KDELibs4Support

kcmdlineargs.cpp
1 /*
2  Copyright (C) 1999 Waldo Bastian <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 #include "kcmdlineargs.h"
20 
21 #include <config-kdelibs4support.h>
22 
23 #include <sys/param.h>
24 
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <locale.h>
31 
32 #if HAVE_LIMITS_H
33 #include <limits.h>
34 #endif
35 
36 #include <QDir>
37 #include <QDebug>
38 #include <QFile>
39 #include <QHash>
40 #include <QTextCodec>
41 #include <QUrl>
42 #include <QDataStream>
43 
44 #include "k4aboutdata.h"
45 #include <kcoreaddons_version.h>
46 
47 // -----------------------------------------------------------------------------
48 // Design notes:
49 //
50 // These classes deal with a lot of text, some of which needs to be
51 // marked for translation. Since at the time when these object and calls are
52 // made the translation catalogs are usually still not initialized, the
53 // translation has to be delayed. This is achieved by using KLocalizedString
54 // for translatable strings. KLocalizedStrings are produced by ki18n* calls,
55 // instead of the more usuall i18n* calls which produce QString by trying to
56 // translate immediately.
57 //
58 // All the non-translatable string arguments to methods are taken QByteArray,
59 // all the translatable are KLocalizedString. The getter methods always return
60 // proper QString: the non-translatable strings supplied by the code are
61 // treated with QString::fromUtf8(), those coming from the outside with
62 // QTextCodec::toUnicode(), and translatable strings are finalized to QStrings
63 // at the point of getter calls (i.e. delayed translation).
64 //
65 // The code below uses locally defined s->decodeInput(QByteArray) and
66 // s->encodeOutput(QString) calls to centralize the conversion of raw external
67 // bytes (instead of QString::to/fromLocal8Bit(), QFile::decodeName, etc.)
68 // -----------------------------------------------------------------------------
69 
70 #if HAVE_X11
71 #define DISPLAY "DISPLAY"
72 #else
73 #define DISPLAY "NODISPLAY"
74 #endif
75 
76 //
77 // Helper classes
78 //
79 
80 class KCmdLineParsedOptions : public QHash<QByteArray, QByteArray>
81 {
82 public:
83  KCmdLineParsedOptions() { }
84 };
85 
86 class KCmdLineParsedArgs : public QList<QByteArray>
87 {
88 public:
89  KCmdLineParsedArgs() { }
90 };
91 
92 class KCmdLineArgsList: public QList<KCmdLineArgs *>
93 {
94 public:
95  KCmdLineArgsList() { }
96  ~KCmdLineArgsList()
97  {
98  while (count()) {
99  delete takeFirst();
100  }
101  }
102 };
103 
104 //
105 // KCmdLineOptions
106 //
107 
108 class KCmdLineOptionsPrivate
109 {
110 public:
111  QList<QByteArray> names;
112  QList<KLocalizedString> descriptions;
114 };
115 
117  : d(new KCmdLineOptionsPrivate)
118 {}
119 
121 {
122  delete d;
123 }
124 
126  : d(new KCmdLineOptionsPrivate(*(options.d)))
127 {
128 }
129 
131 {
132  if (this != &options) {
133  *d = *(options.d);
134  }
135  return *this;
136 }
137 
139  const KLocalizedString &description,
140  const QByteArray &defaultValue)
141 {
142  d->names.append(name);
143  d->descriptions.append(description);
144  d->defaults.append(QString::fromUtf8(defaultValue.data()));
145  return *this;
146 }
147 
149 {
150  d->names += other.d->names;
151  d->descriptions += other.d->descriptions;
152  d->defaults += other.d->defaults;
153  return *this;
154 }
155 
156 //
157 // KCmdLineArgs static data and methods
158 //
159 
160 class KCmdLineArgsStatic
161 {
162 public:
163 
164  KCmdLineArgsList *argsList; // All options.
165  const K4AboutData *about;
166 
167  int all_argc; // The original argc
168  char **all_argv; // The original argv
169  char *appName;
170  bool parsed : 1; // Whether we have parsed the arguments since calling init
171  bool ignoreUnknown : 1; // Ignore unknown options and arguments
172  QByteArray mCwd; // Current working directory. Important for KUnqiueApp!
174 
175  KCmdLineOptions qt_options;
176  KCmdLineOptions kde_options;
177 
178  KCmdLineArgsStatic();
179 
180  ~KCmdLineArgsStatic();
181 
182  QTextCodec *codec; // codec for converting raw input to QString
183 
191  static QString decodeInput(const QByteArray &rawstr);
192 
200  static QByteArray encodeOutput(const QString &str);
201 
206  void printQ(const QString &msg);
207 
221  static int findOption(const KCmdLineOptions &options, QByteArray &opt,
222  QByteArray &opt_name, QString &def, bool &enabled);
223 
229  static void findOption(const QByteArray &optv, const QByteArray &_opt,
230  int &i, bool _enabled, bool &moreOptions);
231 
238  static void parseAllArgs();
239 
247  static void removeArgs(const QByteArray &id);
248 
255  static QString escape(const QString &text);
256 };
257 Q_GLOBAL_STATIC(KCmdLineArgsStatic, staticObj)
258 
259 KCmdLineArgsStatic::KCmdLineArgsStatic()
260 {
261  // Global data
262  argsList = nullptr;
263  all_argc = 0;
264  all_argv = nullptr;
265  appName = nullptr;
266  mCwd.clear();
267  about = nullptr;
268  parsed = false;
269  ignoreUnknown = false;
270  mStdargs = {};
271 
272  // Text codec.
273  codec = QTextCodec::codecForLocale();
274 
275  // Qt options
276  //FIXME: Check if other options are specific to Qt/X11
277 #if HAVE_X11
278  qt_options.add("display <displayname>", ki18n("Use the X-server display 'displayname'"));
279 #else
280 #endif
281  qt_options.add("session <sessionId>", ki18n("Restore the application for the given 'sessionId'"));
282  qt_options.add("cmap", ki18n("Causes the application to install a private color\nmap on an 8-bit display"));
283  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"));
284  qt_options.add("nograb", ki18n("tells Qt to never grab the mouse or the keyboard"));
285  qt_options.add("dograb", ki18n("running under a debugger can cause an implicit\n-nograb, use -dograb to override"));
286  qt_options.add("sync", ki18n("switches to synchronous mode for debugging"));
287  qt_options.add("fn");
288  qt_options.add("font <fontname>", ki18n("defines the application font"));
289  qt_options.add("bg");
290  qt_options.add("background <color>", ki18n("sets the default background color and an\napplication palette (light and dark shades are\ncalculated)"));
291  qt_options.add("fg");
292  qt_options.add("foreground <color>", ki18n("sets the default foreground color"));
293  qt_options.add("btn");
294  qt_options.add("button <color>", ki18n("sets the default button color"));
295  qt_options.add("name <name>", ki18n("sets the application name"));
296  qt_options.add("title <title>", ki18n("sets the application title (caption)"));
297  qt_options.add("testability", ki18n("load the testability framework"));
298 #if HAVE_X11
299  qt_options.add("visual TrueColor", ki18n("forces the application to use a TrueColor visual on\nan 8-bit display"));
300  qt_options.add("inputstyle <inputstyle>", ki18n("sets XIM (X Input Method) input style. Possible\nvalues are onthespot, overthespot, offthespot and\nroot"));
301  qt_options.add("im <XIM server>", ki18n("set XIM server"));
302  qt_options.add("noxim", ki18n("disable XIM"));
303 #endif
304  qt_options.add("reverse", ki18n("mirrors the whole layout of widgets"));
305  qt_options.add("stylesheet <file.qss>", ki18n("applies the Qt stylesheet to the application widgets"));
306  qt_options.add("graphicssystem <system>", ki18n("use a different graphics system instead of the default one, options are raster and opengl (experimental)"));
307  qt_options.add("qmljsdebugger <port>", ki18n("QML JS debugger information. Application must be\nbuilt with -DQT_DECLARATIVE_DEBUG for the debugger to be\nenabled"));
308  qt_options.add("platform <platform>", ki18n("The windowing system platform (e.g. xcb or wayland)"));
309  // KDE options
310  kde_options.add("caption <caption>", ki18n("Use 'caption' as name in the titlebar"));
311  kde_options.add("icon <icon>", ki18n("Use 'icon' as the application icon"));
312  kde_options.add("config <filename>", ki18n("Use alternative configuration file"));
313  kde_options.add("nocrashhandler", ki18n("Disable crash handler, to get core dumps"));
314 #if HAVE_X11
315  kde_options.add("waitforwm", ki18n("Waits for a WM_NET compatible windowmanager"));
316 #endif
317  kde_options.add("style <style>", ki18n("sets the application GUI style"));
318  kde_options.add("geometry <geometry>", ki18n("sets the client geometry of the main widget - see man X for the argument format (usually WidthxHeight+XPos+YPos)"));
319 #ifndef Q_OS_WIN
320  kde_options.add("smkey <sessionKey>"); // this option is obsolete and exists only to allow smooth upgrades from sessions
321 #endif
322 }
323 
324 KCmdLineArgsStatic::~KCmdLineArgsStatic()
325 {
326  delete argsList;
327  // K4AboutData object is deleted by ~KCleanUpGlobalStatic.
328  //delete about;
329 }
330 
331 //
332 // KCmdLineArgs private data and methods
333 //
334 
335 class KCmdLineArgsPrivate
336 {
337  friend class KCmdLineArgsStatic;
338 public:
339  KCmdLineArgsPrivate(const KCmdLineOptions &_options, const KLocalizedString &_name, const QByteArray &_id)
340  : options(_options)
341  , name(_name)
342  , id(_id)
343  , parsedOptionList(nullptr)
344  , parsedArgList(nullptr)
345  , isQt(id == "qt")
346  {
347  }
348  ~KCmdLineArgsPrivate()
349  {
350  delete parsedOptionList;
351  delete parsedArgList;
352  }
353  const KCmdLineOptions options;
354  const KLocalizedString name;
355  const QByteArray id;
356  KCmdLineParsedOptions *parsedOptionList;
357  KCmdLineParsedArgs *parsedArgList;
358  bool isQt;
359 
365  void setOption(const QByteArray &option, bool enabled);
366 
372  void setOption(const QByteArray &option, const QByteArray &value);
373 
379  void addArgument(const QByteArray &argument);
380 
386  void save(QDataStream &) const;
387 
393  void load(QDataStream &);
394 };
395 
396 //
397 // Static functions
398 //
399 
400 QString
401 KCmdLineArgsStatic::decodeInput(const QByteArray &rawstr)
402 {
403  return staticObj()->codec->toUnicode(rawstr);
404 }
405 
407 KCmdLineArgsStatic::encodeOutput(const QString &str)
408 {
409  return staticObj()->codec->fromUnicode(str);
410 }
411 
412 void
413 KCmdLineArgsStatic::printQ(const QString &msg)
414 {
415  fprintf(stdout, "%s", encodeOutput(msg).data());
416 }
417 
418 void
419 KCmdLineArgs::init(int _argc, char **_argv,
420  const QByteArray &_appname,
421  const QByteArray &_catalog,
422  const KLocalizedString &_programName,
423  const QByteArray &_version,
424  const KLocalizedString &_description,
425  StdCmdLineArgs stdargs)
426 {
427  init(_argc, _argv,
428  new K4AboutData(_appname, _catalog, _programName, _version, _description),
429  stdargs);
430 }
431 
432 void
433 KCmdLineArgs::initIgnore(int _argc, char **_argv, const QByteArray &_appname)
434 {
435  init(_argc, _argv,
436  new K4AboutData(_appname, nullptr, ki18n(_appname.data()), "unknown", ki18n("KDE Application")));
437  staticObj()->ignoreUnknown = true;
438 }
439 
440 void
442 {
443  char **_argv = (char **) malloc(sizeof(char *));
444  _argv[0] = (char *) staticObj()->encodeOutput(ab->appName()).data();
445  init(1, _argv, ab, CmdLineArgNone);
446 }
447 
448 void
449 KCmdLineArgs::init(int _argc, char **_argv, const K4AboutData *_about, StdCmdLineArgs stdargs)
450 {
451  staticObj()->all_argc = _argc;
452  staticObj()->all_argv = _argv;
453 
454  if (!staticObj()->all_argv) {
455  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
456  fprintf(stderr, "Passing null-pointer to 'argv' is not allowed.\n\n");
457 
458  assert(0);
459  exit(255);
460  }
461 
462  // Strip path from argv[0]
463  if (staticObj()->all_argc) {
464  char *p = strrchr(staticObj()->all_argv[0], QDir::separator().toLatin1());
465  if (p) {
466  staticObj()->appName = p + 1;
467  } else {
468  staticObj()->appName = staticObj()->all_argv[0];
469  }
470  }
471 
472  staticObj()->about = _about;
473  staticObj()->parsed = false;
474  staticObj()->mCwd = QDir::currentPath().toLocal8Bit(); //currentPath() uses fromLocal8Bit internally apparently
475  addStdCmdLineOptions(stdargs);
476 }
477 
479 {
480  return QString::fromLocal8Bit(staticObj()->mCwd.data());
481 }
482 
484 {
485  if (!staticObj()->appName) {
486  return QString();
487  }
488  return staticObj()->decodeInput(staticObj()->appName);
489 }
490 
495 {
496  if (stdargs & KCmdLineArgs::CmdLineArgQt) {
497  KCmdLineArgs::addCmdLineOptions(staticObj()->qt_options, ki18n("Qt"), "qt");
498  }
499  if (stdargs & KCmdLineArgs::CmdLineArgKDE) {
500  KCmdLineArgs::addCmdLineOptions(staticObj()->kde_options, ki18n("KDE"), "kde");
501  }
502  staticObj()->mStdargs = stdargs;
503 }
504 
505 void
507  const QByteArray &id, const QByteArray &afterId)
508 {
509  if (!staticObj()->argsList) {
510  staticObj()->argsList = new KCmdLineArgsList;
511  }
512 
513  int pos = staticObj()->argsList->count();
514  // To make sure that the named options come before unnamed.
515  if (pos > 0 && !id.isEmpty() && staticObj()->argsList->last()->d->name.isEmpty()) {
516  pos--;
517  }
518 
519  KCmdLineArgsList::Iterator args;
520  int i = 0;
521  for (args = staticObj()->argsList->begin(); args != staticObj()->argsList->end(); ++args, i++) {
522  if (id == (*args)->d->id) {
523  return; // Options already present.
524  }
525 
526  // Only check for afterId if it has been given non-empty, as the
527  // unnamed option group should come after all named groups.
528  if (!afterId.isEmpty() && afterId == (*args)->d->id) {
529  pos = i + 1;
530  }
531  }
532 
533  Q_ASSERT(staticObj()->parsed == false); // You must add _ALL_ cmd line options
534  // before accessing the arguments!
535  staticObj()->argsList->insert(pos, new KCmdLineArgs(options, name, id));
536 }
537 
538 void
540 {
541  if (!staticObj()->parsed) {
542  staticObj()->parseAllArgs();
543  }
544 
545  // Remove Qt and KDE options.
546  staticObj()->removeArgs("qt");
547  staticObj()->removeArgs("kde");
548  staticObj()->removeArgs("kuniqueapp");
549 
550  ds << staticObj()->mCwd;
551 
552  uint count = staticObj()->argsList ? staticObj()->argsList->count() : 0;
553  ds << count;
554 
555  if (!count) {
556  return;
557  }
558 
559  KCmdLineArgsList::Iterator args;
560  for (args = staticObj()->argsList->begin(); args != staticObj()->argsList->end(); ++args) {
561  ds << (*args)->d->id;
562  (*args)->d->save(ds);
563  }
564 }
565 
566 void
568 {
569  staticObj()->parsed = true; // don't reparse argc/argv!
570 
571  // Remove Qt and KDE options.
572  staticObj()->removeArgs("qt");
573  staticObj()->removeArgs("kde");
574  staticObj()->removeArgs("kuniqueapp");
575 
576  KCmdLineArgsList::Iterator args;
577  if (staticObj()->argsList) {
578  for (args = staticObj()->argsList->begin(); args != staticObj()->argsList->end(); ++args) {
579  (*args)->clear();
580  }
581  }
582 
583  if (ds.atEnd()) {
584  return;
585  }
586 
587  QByteArray qCwd;
588  ds >> qCwd;
589 
590  staticObj()->mCwd = qCwd;
591 
592  uint count;
593  ds >> count;
594 
595  while (count--) {
596  QByteArray id;
597  ds >> id;
598  Q_ASSERT(staticObj()->argsList);
599  bool found = false;
600  for (args = staticObj()->argsList->begin(); args != staticObj()->argsList->end(); ++args) {
601  if ((*args)->d->id == id) {
602  (*args)->d->load(ds);
603  found = true;
604  break;
605  }
606  }
607  if (!found) {
608  qWarning() << "Argument definitions for" << id << "not found!";
609  // The next ds >> id will do nonsensical things...
610  }
611  }
612  staticObj()->parsed = true;
613 }
614 
616 {
617  if (!staticObj()->argsList) {
618  return nullptr;
619  }
620  KCmdLineArgsList::Iterator args = staticObj()->argsList->begin();
621  while (args != staticObj()->argsList->end()) {
622  if ((*args)->d->id == id) {
623  if (!staticObj()->parsed) {
624  staticObj()->parseAllArgs();
625  }
626  return *args;
627  }
628  ++args;
629  }
630 
631  return nullptr;
632 }
633 
634 void KCmdLineArgsStatic::removeArgs(const QByteArray &id)
635 {
636  if (!staticObj()->argsList) {
637  return;
638  }
639  KCmdLineArgsList::Iterator args = staticObj()->argsList->begin();
640  while (args != staticObj()->argsList->end()) {
641  if ((*args)->d->id == id) {
642  if (!staticObj()->parsed) {
643  staticObj()->parseAllArgs();
644  }
645  break;
646  }
647  ++args;
648  }
649 
650  if (args != staticObj()->argsList->end()) {
651  KCmdLineArgs *a = *args;
652  staticObj()->argsList->erase(args);
653  delete a;
654  }
655 }
656 
657 #pragma message("KDE5 TODO: Remove this method once it is in Qt5")
658 QString KCmdLineArgsStatic::escape(const QString &text)
659 {
660  int tlen = text.length();
661  QString ntext;
662  ntext.reserve(tlen);
663  for (int i = 0; i < tlen; ++i) {
664  QChar c = text[i];
665  if (c == QLatin1Char('&')) {
666  ntext += QLatin1String("&amp;");
667  } else if (c == QLatin1Char('<')) {
668  ntext += QLatin1String("&lt;");
669  } else if (c == QLatin1Char('>')) {
670  ntext += QLatin1String("&gt;");
671  } else if (c == QLatin1Char('\'')) {
672  ntext += QLatin1String("&apos;"); // not handled by Qt::escape
673  } else if (c == QLatin1Char('"')) {
674  ntext += QLatin1String("&quot;");
675  } else {
676  ntext += c;
677  }
678  }
679  return ntext;
680 }
681 
682 int
683 KCmdLineArgsStatic::findOption(const KCmdLineOptions &options, QByteArray &opt,
684  QByteArray &opt_name, QString &def, bool &enabled)
685 {
686  int result;
687  bool inverse;
688 
689  for (int i = 0; i < options.d->names.size(); i++) {
690  result = 0;
691  inverse = false;
692  opt_name = options.d->names[i];
693  if (opt_name.startsWith(':') || opt_name.isEmpty()) {
694  continue;
695  }
696  if (opt_name.startsWith('!')) {
697  opt_name = opt_name.mid(1);
698  result = 4;
699  }
700  if (opt_name.startsWith("no") && !opt_name.contains('<')) { // krazy:exclude=strings
701  opt_name = opt_name.mid(2);
702  inverse = true;
703  }
704 
705  int len = opt.length();
706  if (opt == opt_name.left(len)) {
707  opt_name = opt_name.mid(len);
708  if (opt_name.isEmpty()) {
709  if (inverse) {
710  return result + 2;
711  }
712 
713  if (options.d->descriptions[i].isEmpty()) {
714  i++;
715  if (i >= options.d->names.size()) {
716  return result + 0;
717  }
718  QByteArray nextOption = options.d->names[i];
719  int p = nextOption.indexOf(' ');
720  if (p > 0) {
721  nextOption = nextOption.left(p);
722  }
723  if (nextOption.startsWith('!')) {
724  nextOption = nextOption.mid(1);
725  }
726  if (nextOption.startsWith("no") && !nextOption.contains('<')) { // krazy:exclude=strings
727  nextOption = nextOption.mid(2);
728  enabled = !enabled;
729  }
730  result = findOption(options, nextOption, opt_name, def, enabled);
731  Q_ASSERT(result);
732  opt = nextOption;
733  return result;
734  }
735 
736  return 1;
737  }
738  if (opt_name.startsWith(' ')) {
739  opt_name = opt_name.mid(1);
740  def = options.d->defaults[i];
741  return result + 3;
742  }
743  }
744  }
745  return 0;
746 }
747 
748 void
749 KCmdLineArgsStatic::findOption(const QByteArray &optv, const QByteArray &_opt,
750  int &i, bool _enabled, bool &moreOptions)
751 {
752  KCmdLineArgsList::Iterator args = staticObj()->argsList->begin();
753  QByteArray opt = _opt;
754  QByteArray opt_name;
755  QString def;
756  QByteArray argument;
757  int j = opt.indexOf('=');
758  if (j != -1) {
759  argument = opt.mid(j + 1);
760  opt = opt.left(j);
761  }
762 
763  bool enabled = true;
764  int result = 0;
765  while (args != staticObj()->argsList->end()) {
766  enabled = _enabled;
767  result = findOption((*args)->d->options, opt, opt_name, def, enabled);
768  if (result) {
769  break;
770  }
771  ++args;
772  }
773  if ((args == staticObj()->argsList->end()) &&
774  (optv.startsWith('-') && !optv.startsWith("--"))) { // krazy:exclude=strings
775  // Option not found check if it is a valid option
776  // in the style of -Pprinter1 or ps -aux
777  int p = 1;
778  while (true) {
779  QByteArray singleCharOption = " "; // krazy:exclude=doublequote_chars
780  singleCharOption[0] = optv[p];
781  args = staticObj()->argsList->begin();
782  while (args != staticObj()->argsList->end()) {
783  enabled = _enabled;
784  result = findOption((*args)->d->options, singleCharOption,
785  opt_name, def, enabled);
786  if (result) {
787  break;
788  }
789  ++args;
790  }
791  if (args == staticObj()->argsList->end()) {
792  break; // Unknown argument
793  }
794 
795  p++;
796  if (result == 1) { // Single option
797  (*args)->d->setOption(singleCharOption, enabled);
798  if (p < optv.length()) {
799  continue; // Next option
800  } else {
801  return; // Finished
802  }
803  } else if (result == 3) { // This option takes an argument
804  if (argument.isEmpty()) {
805  argument = optv.mid(p);
806  }
807  (*args)->d->setOption(singleCharOption, argument);
808  return;
809  }
810  break; // Unknown argument
811  }
812  args = staticObj()->argsList->end();
813  result = 0;
814  }
815 
816  if (args == staticObj()->argsList->end() || !result) {
817  if (staticObj()->ignoreUnknown) {
818  return;
819  }
821  KCmdLineArgs::usageError(i18n("Unknown option '%1'.", QString::fromLocal8Bit(_opt.data())));
822  }
823 
824  if ((result & 4) != 0) {
825  result &= ~4;
826  moreOptions = false;
827  }
828 
829  if (result == 3) { // This option takes an argument
830  if (!enabled) {
831  if (staticObj()->ignoreUnknown) {
832  return;
833  }
835  KCmdLineArgs::usageError(i18n("Unknown option '%1'.", QString::fromLocal8Bit(_opt.data())));
836  }
837  if (argument.isEmpty()) {
838  i++;
839  if (i >= staticObj()->all_argc) {
841  KCmdLineArgs::usageError(i18nc("@info:shell %1 is cmdoption name", "'%1' missing.", QString::fromLocal8Bit(opt_name.data())));
842  }
843  argument = staticObj()->all_argv[i];
844  }
845  (*args)->d->setOption(opt, argument);
846  } else {
847  (*args)->d->setOption(opt, enabled);
848  }
849 }
850 
851 void
852 KCmdLineArgsStatic::parseAllArgs()
853 {
854  bool allowArgs = false;
855  bool inOptions = true;
856  bool everythingAfterArgIsArgs = false;
857  KCmdLineArgs *appOptions = staticObj()->argsList->last();
858  if (appOptions->d->id.isEmpty()) {
859  Q_FOREACH (const QByteArray &name, appOptions->d->options.d->names) {
860  everythingAfterArgIsArgs = everythingAfterArgIsArgs || name.startsWith("!+");
861  allowArgs = allowArgs || name.startsWith('+') || everythingAfterArgIsArgs;
862  }
863  }
864  for (int i = 1; i < staticObj()->all_argc; i++) {
865  if (!staticObj()->all_argv[i]) {
866  continue;
867  }
868 
869  if ((staticObj()->all_argv[i][0] == '-') && staticObj()->all_argv[i][1] && inOptions) {
870  bool enabled = true;
871  QByteArray orig = staticObj()->all_argv[i];
872  QByteArray option = orig.mid(1);
873  if (option.startsWith('-')) {
874  option = option.mid(1);
875  if (option.isEmpty()) {
876  inOptions = false;
877  continue;
878  }
879  }
880  if (option == "help") {
882  } else if (option.startsWith("help-")) { // krazy:exclude=strings
883  KCmdLineArgs::usage(option.mid(5));
884  }
885 #ifdef Q_OS_MAC
886  // skip the finder -psn_* hint
887  else if (option.startsWith("psn_")) { // krazy:exclude=strings
888  continue;
889  }
890 #endif
891  else if ((option == "version") || (option == "v")) {
893  staticObj()->printQ(i18nc("@info:shell message on appcmd --version; do not translate 'Development Platform'"
894  "%3 application name, other %n version strings",
895  "Qt: %1\n"
896  "KDE Frameworks: %2\n"
897  "%3: %4\n",
898  QString::fromLatin1(qVersion()),
899  QString::fromLatin1(KCOREADDONS_VERSION_STRING),
900  staticObj()->about->programName(),
901  staticObj()->about->version()));
902  exit(0);
903  } else if (option == "license") {
905  staticObj()->printQ(staticObj()->about->license());
906  staticObj()->printQ(QString::fromLatin1("\n"));
907  exit(0);
908  } else if (option == "author") {
910  if (staticObj()->about) {
911  const QList<K4AboutPerson> authors = staticObj()->about->authors();
912  if (!authors.isEmpty()) {
913  QString authorlist;
914  for (QList<K4AboutPerson>::ConstIterator it = authors.begin(); it != authors.end(); ++it) {
915  QString email;
916  if (!(*it).emailAddress().isEmpty()) {
917  email = QString::fromLatin1(" &lt;") + (*it).emailAddress() + QLatin1String("&gt;");
918  }
919  authorlist += QString::fromLatin1(" ") + (*it).name() + email + QLatin1Char('\n');
920  }
921  staticObj()->printQ(i18nc("the 2nd argument is a list of name+address, one on each line", "%1 was written by\n%2", QString(staticObj()->about->programName()), authorlist));
922  }
923  } else {
924  staticObj()->printQ(i18n("This application was written by somebody who wants to remain anonymous."));
925  }
926  if (staticObj()->about) {
927  if (!staticObj()->about->customAuthorTextEnabled()) {
928  if (staticObj()->about->bugAddress().isEmpty() || staticObj()->about->bugAddress() == QLatin1String("[email protected]")) {
929  staticObj()->printQ(i18n("Please use http://bugs.kde.org to report bugs.\n"));
930  } else {
931  staticObj()->printQ(i18n("Please report bugs to %1.\n", staticObj()->about->bugAddress()));
932  }
933  } else {
934  staticObj()->printQ(staticObj()->about->customAuthorPlainText() + QLatin1Char('\n'));
935  }
936  }
937  exit(0);
938  } else {
939  if (option.startsWith("no")) { // krazy:exclude=strings
940  bool noHasParameter = false;
941  Q_FOREACH (const QByteArray &name, appOptions->d->options.d->names) {
942  if (name.contains(option + QByteArray(" ")) && name.contains('<')) {
943  noHasParameter = true;
944  break;
945  }
946  }
947  if (!noHasParameter) {
948  option = option.mid(2);
949  enabled = false;
950  }
951  }
952  staticObj()->findOption(orig, option, i, enabled, inOptions);
953  }
954  } else {
955  // Check whether appOptions allows these arguments
956  if (!allowArgs) {
957  if (staticObj()->ignoreUnknown) {
958  continue;
959  }
961  KCmdLineArgs::usageError(i18n("Unexpected argument '%1'.", staticObj()->escape(staticObj()->decodeInput(staticObj()->all_argv[i]))));
962  } else {
963  appOptions->d->addArgument(staticObj()->all_argv[i]);
964  if (everythingAfterArgIsArgs) {
965  inOptions = false;
966  }
967  }
968  }
969  }
970  staticObj()->parsed = true;
971 }
972 
974 {
975  if (!staticObj()->argsList) {
976  addStdCmdLineOptions(CmdLineArgKDE | CmdLineArgQt); // Lazy bastards!
977  }
978 
979  static int qt_argc = -1;
980  if (qt_argc != -1) {
981  return qt_argc;
982  }
983 
984  if (!(staticObj()->mStdargs & KCmdLineArgs::CmdLineArgQt)) {
985  qt_argc = 2;
986  return qt_argc;
987  }
988 
989  KCmdLineArgs *args = parsedArgs("qt");
990  Q_ASSERT(args); // No qt options have been added!
991  if (!staticObj()->all_argv) {
992  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
993  fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
994 
995  assert(0);
996  exit(255);
997  }
998 
999  Q_ASSERT(staticObj()->all_argc >= (args->count() + 1));
1000  qt_argc = args->count() + 1;
1001  return qt_argc;
1002 }
1003 
1004 static char **s_qt_argv;
1005 
1006 char **
1008 {
1009  if (!staticObj()->argsList) {
1010  addStdCmdLineOptions(CmdLineArgKDE | CmdLineArgQt); // Lazy bastards!
1011  }
1012 
1013  if (s_qt_argv != nullptr) {
1014  return s_qt_argv;
1015  }
1016 
1017  if (!(staticObj()->mStdargs & KCmdLineArgs::CmdLineArgQt)) {
1018  s_qt_argv = new char *[2];
1019  s_qt_argv[0] = qstrdup(staticObj()->all_argc ? staticObj()->all_argv[0] : "");
1020  s_qt_argv[1] = nullptr;
1021 
1022  return s_qt_argv;
1023  }
1024 
1025  KCmdLineArgs *args = parsedArgs("qt");
1026  if (!args) {
1027  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
1028  fprintf(stderr, "The \"qt\" options have not be added to KCmdLineArgs!\n\n");
1029 
1030  assert(0);
1031  exit(255);
1032  }
1033  if (!staticObj()->all_argv) {
1034  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
1035  fprintf(stderr, "Application has not called KCmdLineArgs::init(...).\n\n");
1036 
1037  assert(0);
1038  exit(255);
1039  }
1040 
1041  int count = args->count();
1042  s_qt_argv = new char *[ count + 2 ];
1043  s_qt_argv[0] = qstrdup(staticObj()->all_argc ? staticObj()->all_argv[0] : "");
1044  int i = 0;
1045  for (; i < count; i++) {
1046  s_qt_argv[i + 1] = qstrdup(args->d->parsedArgList->at(i).data());
1047  }
1048  s_qt_argv[i + 1] = nullptr;
1049 
1050  return s_qt_argv;
1051 }
1052 
1053 const K4AboutData *
1055 {
1056  return staticObj()->about;
1057 }
1058 
1059 void
1061 {
1062 #pragma message ("KDE5 NOTE: What about this method ?")
1063 }
1064 
1065 void
1067 {
1068  QByteArray localError = staticObj()->encodeOutput(error);
1069  if (localError.endsWith('\n')) {
1070  localError.chop(1);
1071  }
1072  fprintf(stderr, "%s: %s\n", staticObj()->appName, localError.data());
1073 
1074  QString tmp = i18n("Use --help to get a list of available command line options.");
1075  localError = staticObj()->encodeOutput(tmp);
1076  fprintf(stderr, "%s: %s\n", staticObj()->appName, localError.data());
1077  exit(254);
1078 }
1079 
1080 void
1082 {
1083  enable_i18n();
1084  Q_ASSERT(staticObj()->argsList != nullptr); // It's an error to call usage(...) without
1085  // having done addCmdLineOptions first!
1086 
1087  QString optionFormatString = QString::fromLatin1(" %1 %2\n");
1088  QString optionFormatStringDef = QString::fromLatin1(" %1 %2 [%3]\n");
1089  QString tmp;
1090  QString usage;
1091 
1092  KCmdLineArgsList::Iterator args = --(staticObj()->argsList->end());
1093 
1094  if ((*args)->d->id.isEmpty() && ((*args)->d->options.d->names.size() > 0) &&
1095  !(*args)->d->options.d->names[0].startsWith('+')) {
1096  usage = i18n("[options] ") + usage;
1097  }
1098 
1099  while (true) {
1100  if (!(*args)->d->name.isEmpty()) {
1101  usage = i18n("[%1-options]", (*args)->d->name.toString()) + QLatin1Char(' ') + usage;
1102  }
1103  if (args == staticObj()->argsList->begin()) {
1104  break;
1105  }
1106  --args;
1107  }
1108 
1109  KCmdLineArgs *appOptions = staticObj()->argsList->last();
1110  if (appOptions->d->id.isEmpty()) {
1111  const KCmdLineOptions &option = appOptions->d->options;
1112  for (int i = 0; i < option.d->names.size(); i++) {
1113  QByteArray opt_name = option.d->names[i];
1114  if (opt_name.startsWith('+')) {
1115  usage += QString::fromLatin1(opt_name.mid(1).data()) + QLatin1Char(' ');
1116  } else if (opt_name.startsWith("!+")) {
1117  usage += QString::fromLatin1(opt_name.mid(2).data()) + QLatin1Char(' ');
1118  }
1119  }
1120  }
1121 
1122  staticObj()->printQ(i18n("Usage: %1 %2\n", QString::fromLocal8Bit(staticObj()->appName), staticObj()->escape(usage)));
1123  staticObj()->printQ(QLatin1Char('\n') + staticObj()->about->shortDescription() + QLatin1Char('\n'));
1124 
1125  staticObj()->printQ(i18n("\nGeneric options:\n"));
1126  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1("--help"), -25)
1127  .arg(i18n("Show help about options")));
1128 
1129  args = staticObj()->argsList->begin();
1130  while (args != staticObj()->argsList->end()) {
1131  if (!(*args)->d->name.isEmpty() && !(*args)->d->id.isEmpty()) {
1132  QString option = QString::fromLatin1("--help-%1").arg(QString::fromLatin1((*args)->d->id.data()));
1133  QString desc = i18n("Show %1 specific options", (*args)->d->name.toString());
1134 
1135  staticObj()->printQ(optionFormatString.arg(option, -25).arg(desc));
1136  }
1137  ++args;
1138  }
1139 
1140  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1("--help-all"), -25).arg(i18n("Show all options")));
1141  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1("--author"), -25).arg(i18n("Show author information")));
1142  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1("-v, --version"), -25).arg(i18n("Show version information")));
1143  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1("--license"), -25).arg(i18n("Show license information")));
1144  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1("--"), -25).arg(i18n("End of options")));
1145 
1146  args = staticObj()->argsList->begin(); // Sets current to 1st.
1147 
1148  bool showAll = (id == "all");
1149 
1150  if (!showAll) {
1151  while (args != staticObj()->argsList->end()) {
1152  if (id == (*args)->d->id) {
1153  break;
1154  }
1155  ++args;
1156  }
1157  }
1158 
1159  while (args != staticObj()->argsList->end()) {
1160  bool hasArgs = false;
1161  bool hasOptions = false;
1162  QString optionsHeader;
1163  if (!(*args)->d->name.isEmpty()) {
1164  optionsHeader = i18n("\n%1 options:\n", (*args)->d->name.toString());
1165  } else {
1166  optionsHeader = i18n("\nOptions:\n");
1167  }
1168 
1169  while (args != staticObj()->argsList->end()) {
1170  const KCmdLineOptions &option = (*args)->d->options;
1171  QByteArray opt;
1172 
1173  for (int i = 0; i < option.d->names.size(); i++) {
1174  QString description;
1175  QStringList dl;
1176 
1177  QString descriptionFull;
1178  if (!option.d->descriptions[i].isEmpty()) {
1179  descriptionFull = option.d->descriptions[i].toString();
1180  }
1181 
1182  // Option header
1183  if (option.d->names[i].startsWith(':')) {
1184  if (!descriptionFull.isEmpty()) {
1185  optionsHeader = QLatin1Char('\n') + descriptionFull;
1186  if (!optionsHeader.endsWith(QLatin1Char('\n'))) {
1187  optionsHeader.append(QLatin1Char('\n'));
1188  }
1189  hasOptions = false;
1190  }
1191  continue;
1192  }
1193 
1194  // Free-form comment
1195  if (option.d->names[i].isEmpty()) {
1196  if (!descriptionFull.isEmpty()) {
1197  tmp = QLatin1Char('\n') + descriptionFull;
1198  if (!tmp.endsWith(QLatin1Char('\n'))) {
1199  tmp.append(QLatin1Char('\n'));
1200  }
1201  staticObj()->printQ(tmp);
1202  }
1203  continue;
1204  }
1205 
1206  // Options
1207  if (!descriptionFull.isEmpty()) {
1208  dl = descriptionFull.split(QLatin1Char('\n'), QString::KeepEmptyParts);
1209  description = dl.first();
1210  dl.erase(dl.begin());
1211  }
1212  QByteArray name = option.d->names[i];
1213  if (name.startsWith('!')) {
1214  name = name.mid(1);
1215  }
1216 
1217  if (name.startsWith('+')) {
1218  if (!hasArgs) {
1219  staticObj()->printQ(i18n("\nArguments:\n"));
1220  hasArgs = true;
1221  }
1222 
1223  name = name.mid(1);
1224  if (name.startsWith('[') && name.endsWith(']')) {
1225  name = name.mid(1, name.length() - 2);
1226  }
1227  staticObj()->printQ(optionFormatString.arg(QString::fromLocal8Bit(name.data()), -25).arg(description));
1228  } else {
1229  if (!hasOptions) {
1230  staticObj()->printQ(optionsHeader);
1231  hasOptions = true;
1232  }
1233 
1234  if ((name.length() == 1) || (name[1] == ' ')) {
1235  name = '-' + name;
1236  } else {
1237  name = "--" + name;
1238  }
1239  if (descriptionFull.isEmpty()) {
1240  opt = name + ", ";
1241  } else {
1242  opt = opt + name;
1243  if (option.d->defaults[i].isEmpty()) {
1244  staticObj()->printQ(optionFormatString.arg(QString::fromLatin1(opt.data()), -25).arg(description));
1245  } else {
1246  staticObj()->printQ(optionFormatStringDef.arg(QString::fromLatin1(opt.data()), -25)
1247  .arg(description, option.d->defaults[i]));
1248  }
1249  opt.clear();
1250  }
1251  }
1252  for (QStringList::Iterator it = dl.begin();
1253  it != dl.end();
1254  ++it) {
1255  staticObj()->printQ(optionFormatString.arg(QString(), -25).arg(*it));
1256  }
1257  }
1258 
1259  ++args;
1260  if (args == staticObj()->argsList->end() || !(*args)->d->name.isEmpty() || (*args)->d->id.isEmpty()) {
1261  break;
1262  }
1263  }
1264  if (!showAll) {
1265  break;
1266  }
1267  }
1268 
1269  exit(0);
1270 }
1271 
1272 //
1273 // Member functions
1274 //
1275 
1282  const KLocalizedString &_name,
1283  const QByteArray &_id)
1284  : d(new KCmdLineArgsPrivate(_options, _name, _id))
1285 {
1286 }
1287 
1292 {
1293  if (!staticObj.isDestroyed() && staticObj()->argsList) {
1294  staticObj()->argsList->removeAll(this);
1295  }
1296  delete d;
1297 }
1298 
1299 void
1301 {
1302  staticObj()->mCwd = cwd;
1303 }
1304 
1305 void
1307 {
1308  delete d->parsedArgList; d->parsedArgList = nullptr;
1309  delete d->parsedOptionList; d->parsedOptionList = nullptr;
1310 }
1311 
1312 void
1314 {
1315  delete staticObj()->argsList; staticObj()->argsList = nullptr;
1316  staticObj()->parsed = false;
1317 }
1318 
1319 void
1320 KCmdLineArgsPrivate::save(QDataStream &ds) const
1321 {
1322  if (parsedOptionList) {
1323  ds << (*(parsedOptionList));
1324  } else {
1325  ds << quint32(0);
1326  }
1327 
1328  if (parsedArgList) {
1329  ds << (*(parsedArgList));
1330  } else {
1331  ds << quint32(0);
1332  }
1333 }
1334 
1335 void
1336 KCmdLineArgsPrivate::load(QDataStream &ds)
1337 {
1338  if (!parsedOptionList) {
1339  parsedOptionList = new KCmdLineParsedOptions;
1340  }
1341  if (!parsedArgList) {
1342  parsedArgList = new KCmdLineParsedArgs;
1343  }
1344 
1345  ds >> (*(parsedOptionList));
1346  ds >> (*(parsedArgList));
1347 
1348  if (parsedOptionList->count() == 0) {
1349  delete parsedOptionList; parsedOptionList = nullptr;
1350  }
1351  if (parsedArgList->count() == 0) {
1352  delete parsedArgList; parsedArgList = nullptr;
1353  }
1354 }
1355 
1356 void
1357 KCmdLineArgsPrivate::setOption(const QByteArray &opt, bool enabled)
1358 {
1359  if (isQt) {
1360  // Qt does it own parsing.
1361  QByteArray argString = "-"; // krazy:exclude=doublequote_chars
1362  if (!enabled) {
1363  argString += "no";
1364  }
1365  argString += opt;
1366  addArgument(argString);
1367  }
1368  if (!parsedOptionList) {
1369  parsedOptionList = new KCmdLineParsedOptions;
1370  }
1371 
1372  if (enabled) {
1373  parsedOptionList->insert(opt, "t"); // krazy:exclude=doublequote_chars
1374  } else {
1375  parsedOptionList->insert(opt, "f"); // krazy:exclude=doublequote_chars
1376  }
1377 }
1378 
1379 void
1380 KCmdLineArgsPrivate::setOption(const QByteArray &opt, const QByteArray &value)
1381 {
1382  if (isQt) {
1383  // Qt does it's own parsing.
1384  QByteArray argString = "-"; // krazy:exclude=doublequote_chars
1385  argString += opt;
1386  if (opt == "qmljsdebugger") {
1387  // hack: Qt expects the value of the "qmljsdebugger" option to be
1388  // passed using a '=' separator rather than a space, so we recreate it
1389  // correctly.
1390  // See code of QCoreApplicationPrivate::processCommandLineArguments()
1391  addArgument(argString + "=" + value);
1392  } else {
1393  addArgument(argString);
1394  addArgument(value);
1395  }
1396 
1397 #if HAVE_X11
1398  // Hack coming up!
1399  if (argString == "-display") {
1400  qputenv(DISPLAY, value);
1401  }
1402 #endif
1403  }
1404  if (!parsedOptionList) {
1405  parsedOptionList = new KCmdLineParsedOptions;
1406  }
1407 
1408  parsedOptionList->insertMulti(opt, value);
1409 }
1410 
1411 QString
1413 {
1414  QByteArray opt = _opt;
1415  QByteArray value;
1416  if (d->parsedOptionList) {
1417  value = d->parsedOptionList->value(opt);
1418  }
1419  if (!value.isEmpty()) {
1420  return QString::fromLocal8Bit(value.data());
1421  }
1422 
1423  // Look up the default.
1424  QByteArray opt_name;
1425  QString def;
1426  bool dummy = true;
1427  int result = staticObj()->findOption(d->options, opt, opt_name, def, dummy) & ~4;
1428 
1429  if (result != 3) {
1430  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
1431  fprintf(stderr, "Application requests for getOption(\"%s\") but the \"%s\" option\n",
1432  opt.data(), opt.data());
1433  fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
1434 
1435  Q_ASSERT(0);
1436  exit(255);
1437  }
1438  return def;
1439 }
1440 
1443 {
1444  QStringList result;
1445  if (!d->parsedOptionList) {
1446  return result;
1447  }
1448 
1449  while (true) {
1450  QByteArray value = d->parsedOptionList->take(opt);
1451  if (value.isEmpty()) {
1452  break;
1453  }
1454  result.prepend(QString::fromLocal8Bit(value.data()));
1455  }
1456 
1457  // Reinsert items in dictionary
1458  // WABA: This is rather silly, but I don't want to add restrictions
1459  // to the API like "you can only call this function once".
1460  // I can't access all items without taking them out of the list.
1461  // So taking them out and then putting them back is the only way.
1462  Q_FOREACH (const QString &str, result) {
1463  d->parsedOptionList->insertMulti(opt, str.toLocal8Bit());
1464  }
1465  return result;
1466 }
1467 
1468 bool
1470 {
1471  // Look up the default.
1472  QByteArray opt = _opt;
1473  QByteArray opt_name;
1474  QString def;
1475  int result = 0;
1476  KCmdLineArgsList::Iterator args = staticObj()->argsList->begin();
1477  while (args != staticObj()->argsList->end()) {
1478  bool dummy = true;
1479  result = staticObj()->findOption((*args)->d->options, opt, opt_name, def, dummy) & ~4;
1480  if (result) {
1481  break;
1482  }
1483  ++args;
1484  }
1485 
1486  if (result == 0) {
1487  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs):\n");
1488  fprintf(stderr, "Application requests for isSet(\"%s\") but the \"%s\" option\n",
1489  opt.data(), opt.data());
1490  fprintf(stderr, "has never been specified via addCmdLineOptions( ... )\n\n");
1491 
1492  Q_ASSERT(0);
1493  exit(255);
1494  }
1495 
1496  QByteArray value;
1497  if (d->parsedOptionList) {
1498  value = d->parsedOptionList->value(opt);
1499  }
1500 
1501  if (!value.isEmpty()) {
1502  if (result == 3) {
1503  return true;
1504  } else {
1505  return (value.at(0) == 't');
1506  }
1507  }
1508 
1509  if (result == 3) {
1510  return false; // String option has 'false' as default.
1511  }
1512 
1513  // We return 'true' as default if the option was listed as '-nofork'
1514  // We return 'false' as default if the option was listed as '-fork'
1515  return (result == 2);
1516 }
1517 
1518 int
1520 {
1521  return d->parsedArgList ? d->parsedArgList->count() : 0;
1522 }
1523 
1524 QString
1525 KCmdLineArgs::arg(int n) const
1526 {
1527  if (!d->parsedArgList || (n >= (int) d->parsedArgList->count())) {
1528  fprintf(stderr, "\n\nFAILURE (KCmdLineArgs): Argument out of bounds\n");
1529  fprintf(stderr, "Application requests for arg(%d) without checking count() first.\n",
1530  n);
1531 
1532  Q_ASSERT(0);
1533  exit(255);
1534  }
1535 
1536  return QString::fromLocal8Bit(d->parsedArgList->at(n).data());
1537 }
1538 
1539 QUrl
1540 KCmdLineArgs::url(int n) const
1541 {
1542  return makeURL(arg(n).toUtf8());
1543 }
1544 
1546 {
1547  const QString urlArg = QString::fromUtf8(_urlArg.data());
1548  QFileInfo fileInfo(urlArg);
1549  if (!fileInfo.isRelative()) { // i.e. starts with '/', on unix
1551  return result; // Absolute path.
1552  }
1553 
1554  QUrl qurl(urlArg);
1555  if (qurl.isRelative() || fileInfo.exists()) {
1556  QUrl result = QUrl::fromLocalFile(cwd() + QLatin1Char('/') + urlArg);
1557 #if 0 //Qt5 TODO: QUrlInfo::cleanPath
1558  result.cleanPath(); //This did use KUrl::cleanPath()
1559 #endif
1560  return result; // Relative path
1561  }
1562 
1563  return QUrl(urlArg); // Argument is a URL
1564 }
1565 
1566 void
1567 KCmdLineArgsPrivate::addArgument(const QByteArray &argument)
1568 {
1569  if (!parsedArgList) {
1570  parsedArgList = new KCmdLineParsedArgs;
1571  }
1572 
1573  parsedArgList->append(argument);
1574 }
1575 
1576 void
1578 {
1579  KCmdLineOptions tmpopt;
1580  tmpopt.add("tempfile", ki18n("The files/URLs opened by the application will be deleted after use"));
1581  KCmdLineArgs::addCmdLineOptions(tmpopt, ki18n("KDE-tempfile"), "kde-tempfile");
1582 }
1583 
1585 {
1586  KCmdLineArgs *args = KCmdLineArgs::parsedArgs("kde-tempfile");
1587  return args && args->isSet("tempfile");
1588 }
1589 
1591 {
1592  QStringList lst;
1593 
1594  for (int i = 0; i < staticObj()->all_argc; i++) {
1595  char *arg = staticObj()->all_argv[i];
1596  if (!arg) {
1597  continue;
1598  }
1599  lst.append(QString::fromLocal8Bit(arg));
1600  }
1601  return lst;
1602 }
KGuiItem defaults()
static void addCmdLineOptions(const KCmdLineOptions &options, const KLocalizedString &name=KLocalizedString(), const QByteArray &id=QByteArray(), const QByteArray &afterId=QByteArray())
Add options to your application.
static QStringList allArguments()
Returns the list of command-line arguments.
QString & append(QChar ch)
void clear()
QStringList getOptionList(const QByteArray &option) const
Read out all occurrences of a string option.
static bool isTempFileSet()
static int & qtArgc()
Returns the number of arguments returned by qtArgv()
QString fromNativeSeparators(const QString &pathName)
KCmdLineOptions & add(const QByteArray &name, const KLocalizedString &description=KLocalizedString(), const QByteArray &defaultValue=QByteArray())
Add command line option, by providing its name, description, and possibly a default value...
char at(int i) const const
~KCmdLineArgs()
Destructor.
~KCmdLineOptions()
Destructor.
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
Access parsed arguments.
static QString cwd()
Get the CWD (Current Working Directory) associated with the current command line arguments.
A class for command-line argument handling.
Definition: kcmdlineargs.h:286
void chop(int n)
bool isEmpty() const const
bool startsWith(const QByteArray &ba) const const
QList::iterator erase(QList::iterator pos)
QString appName() const
Returns the application&#39;s internal name.
int length() const const
QString currentPath()
QString arg(int n) const
Read out an argument.
static char ** qtArgv()
Returns command line options for consumption by Qt after parsing them in a way that is consistent wit...
QChar separator()
static void addTempFileOption()
Add standard option –tempfile.
static void usageError(const QString &error)
Print an error to stderr and the usage help to stdout and exit.
QTextCodec * codecForLocale()
bool isSet(const QByteArray &option) const
Read out a boolean option or check for the presence of string option.
int count() const
Read the number of arguments that aren&#39;t options (but, for example, filenames).
KCmdLineArgs(const KCmdLineOptions &_options, const KLocalizedString &_name, const QByteArray &_id)
Constructor.
static void loadAppArgs(QDataStream &)
Load arguments from a stream.
void clear()
static void reset()
Reset all option definitions, i.e.
int indexOf(char ch, int from) const const
QString fromLocal8Bit(const char *str, int size)
void append(const T &value)
QString fromUtf8(const char *str, int size)
KCmdLineOptions()
Constructor.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
static QString appName()
Get the appname according to argv[0].
bool isEmpty() const const
static const K4AboutData * aboutData()
Returns the K4AboutData for consumption by KComponentData.
bool isEmpty() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QByteArray::iterator begin()
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
typedef Iterator
static void usage(const QByteArray &id=QByteArray())
Print the usage help to stdout and exit.
T & first()
QByteArray mid(int pos, int len) const const
bool atEnd() const const
This class is used to store information about a program.
Definition: k4aboutdata.h:199
QList::iterator end()
QByteArray toLocal8Bit() const const
static QUrl makeURL(const QByteArray &urlArg)
Used by url().
QCA_EXPORT void init()
QString i18n(const char *text, const TYPE &arg...)
static void setCwd(const QByteArray &cwd)
Made public for apps that don&#39;t use KCmdLineArgs To be done before makeURL, to set the current workin...
static void saveAppArgs(QDataStream &)
QByteArray left(int len) const const
bool isRelative() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool contains(char ch) const const
static void init(int argc, char **argv, const QByteArray &appname, const QByteArray &catalog, const KLocalizedString &programName, const QByteArray &version, const KLocalizedString &description=KLocalizedString(), StdCmdLineArgs stdargs=StdCmdLineArgs(CmdLineArgQt|CmdLineArgKDE))
Initialize class.
int length() const const
void reserve(int size)
char * data()
QString fromLatin1(const char *str, int size)
KLocalizedString KI18N_EXPORT ki18n(const char *text)
QString getOption(const QByteArray &option) const
Read out a string option.
void prepend(const T &value)
static void addStdCmdLineOptions(StdCmdLineArgs stdargs=StdCmdLineArgs(CmdLineArgQt|CmdLineArgKDE))
add standard Qt/KDE command-line args
QString::iterator begin()
Class that holds command line options.
Definition: kcmdlineargs.h:53
QList::iterator begin()
QUrl url(int n) const
Read out an argument representing a URL.
bool endsWith(const QByteArray &ba) const const
QByteArray::iterator end()
QUrl fromLocalFile(const QString &localFile)
void clear()
Clear all options and arguments.
static void enable_i18n()
Enable i18n to be able to print a translated error message.
QCA_EXPORT QString appName()
KCmdLineOptions & operator=(const KCmdLineOptions &options)
Assignment operator.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Aug 13 2020 22:58:29 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.