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 
184  /**
185  * @internal
186  * Convertes raw command line argument data to proper QString.
187  *
188  * @param rawstr raw text
189  * @return properly decoded QString
190  */
191  static QString decodeInput(const QByteArray &rawstr);
192 
193  /**
194  * @internal
195  * Convertes QString to raw command line output.
196  *
197  * @param str string to be encoded
198  * @return raw text
199  */
200  static QByteArray encodeOutput(const QString &str);
201 
202  /**
203  * @internal
204  * Shell output with proper decoding.
205  */
206  void printQ(const QString &msg);
207 
208  /**
209  * @internal
210  * Try to match given option in the list of options.
211  * Returns match status.
212  *
213  * @return:
214  * 0 - option not found.
215  * 1 - option found // -fork
216  * 2 - inverse option found ('no') // -nofork
217  * 3 - option + arg found // -fork now
218  *
219  * +4 - no more options follow // !fork
220  */
221  static int findOption(const KCmdLineOptions &options, QByteArray &opt,
222  QByteArray &opt_name, QString &def, bool &enabled);
223 
224  /**
225  * @internal
226  *
227  * Checks what to do with a single option
228  */
229  static void findOption(const QByteArray &optv, const QByteArray &_opt,
230  int &i, bool _enabled, bool &moreOptions);
231 
232  /**
233  * @internal
234  *
235  * Parse all arguments, verify correct syntax and put all arguments
236  * where they belong.
237  */
238  static void parseAllArgs();
239 
240  /**
241  * @internal
242  *
243  * Remove named options.
244  *
245  * @param id The name of the options to be removed.
246  */
247  static void removeArgs(const QByteArray &id);
248 
249  /**
250  * @internal
251  *
252  * Convert &, ", ', <, > characters into XML entities
253  * &amp;, &lt;, &gt;, &apos;, &quot;, respectively.
254  */
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 
360  /**
361  * @internal
362  *
363  * Set a boolean option
364  */
365  void setOption(const QByteArray &option, bool enabled);
366 
367  /**
368  * @internal
369  *
370  * Set a string option
371  */
372  void setOption(const QByteArray &option, const QByteArray &value);
373 
374  /**
375  * @internal
376  *
377  * Add an argument
378  */
379  void addArgument(const QByteArray &argument);
380 
381  /**
382  * @internal
383  *
384  * Save to a stream.
385  */
386  void save(QDataStream &) const;
387 
388  /**
389  * @internal
390  *
391  * Restore from a stream.
392  */
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 
491 /**
492  * Add Qt and KDE command line options to KCmdLineArgs.
493  */
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 
1276 /**
1277  * Constructor.
1278  *
1279  * The given arguments are assumed to be constants.
1280  */
1282  const KLocalizedString &_name,
1283  const QByteArray &_id)
1284  : d(new KCmdLineArgsPrivate(_options, _name, _id))
1285 {
1286 }
1287 
1288 /**
1289  * Destructor.
1290  */
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  }
1600  }
1601  return lst;
1602 }
void append(const T &value)
T & first()
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QStringList getOptionList(const QByteArray &option) const
Read out all occurrences of a string option.
QString arg(int n) const
Read out an argument.
QString appName() const
Returns the application's internal name.
static void usage(const QByteArray &id=QByteArray())
Print the usage help to stdout and exit.
bool atEnd() const const
QString fromUtf8(const char *str, int size)
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 escape(const QString &plain)
QString getOption(const QByteArray &option) const
Read out a string option.
KCmdLineOptions()
Constructor.
int indexOf(char ch, int from) const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QChar separator()
void clear()
static void usageError(const QString &error)
Print an error to stderr and the usage help to stdout and exit.
static KCmdLineArgs * parsedArgs(const QByteArray &id=QByteArray())
Access parsed arguments.
QAction * load(const QObject *recvr, const char *slot, QObject *parent)
bool isSet(const QByteArray &option) const
Read out a boolean option or check for the presence of string option.
~KCmdLineArgs()
Destructor.
void reserve(int size)
void clear()
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.
bool exists() const const
static QString appName()
Get the appname according to argv[0].
char at(int i) const const
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
QTextCodec * codecForLocale()
QByteArray::iterator begin()
void prepend(const T &value)
int count() const const
void chop(int n)
static void enable_i18n()
Enable i18n to be able to print a translated error message.
QString i18n(const char *text, const TYPE &arg...)
QString fromLocal8Bit(const char *str, int size)
A class for command-line argument handling.
Definition: kcmdlineargs.h:286
static void addStdCmdLineOptions(StdCmdLineArgs stdargs=StdCmdLineArgs(CmdLineArgQt|CmdLineArgKDE))
add standard Qt/KDE command-line args
T takeFirst()
~KCmdLineOptions()
Destructor.
void about(QWidget *parent, const QString &text, const QString &title=QString(), Options options=Notify)
QString currentPath()
QByteArray mid(int pos, int len) const const
bool isEmpty() const const
QUrl fromLocalFile(const QString &localFile)
QCA_EXPORT QString appName()
int length() const const
int count() const
Read the number of arguments that aren't options (but, for example, filenames).
bool startsWith(const QByteArray &ba) const const
void clear()
Clear all options and arguments.
bool isEmpty() const const
QString fromNativeSeparators(const QString &pathName)
static QUrl makeURL(const QByteArray &urlArg)
Used by url().
static void saveAppArgs(QDataStream &)
KLocalizedString KI18N_EXPORT ki18n(const char *text)
QUrl url(int n) const
Read out an argument representing a URL.
static void setCwd(const QByteArray &cwd)
Made public for apps that don't use KCmdLineArgs To be done before makeURL, to set the current workin...
bool contains(char ch) const const
static QString cwd()
Get the CWD (Current Working Directory) associated with the current command line arguments.
bool isRelative() const const
bool isRelative() const const
KCmdLineOptions & operator=(const KCmdLineOptions &options)
Assignment operator.
QByteArray left(int len) const const
bool isEmpty() const const
QList::iterator erase(QList::iterator pos)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
const char * name(StandardAction id)
KGuiItem defaults()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
bool endsWith(const QByteArray &ba) const const
static char ** qtArgv()
Returns command line options for consumption by Qt after parsing them in a way that is consistent wit...
QList::iterator begin()
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.
KCmdLineArgs(const KCmdLineOptions &_options, const KLocalizedString &_name, const QByteArray &_id)
Constructor.
int length() const const
QByteArray toLocal8Bit() const const
Class that holds command line options.
Definition: kcmdlineargs.h:53
static void addTempFileOption()
Add standard option –tempfile.
This class is used to store information about a program.
Definition: k4aboutdata.h:199
QList::iterator end()
static void loadAppArgs(QDataStream &)
Load arguments from a stream.
QByteArray::iterator end()
static void reset()
Reset all option definitions, i.e.
QString & append(QChar ch)
static bool isTempFileSet()
char * data()
static int & qtArgc()
Returns the number of arguments returned by qtArgv()
static const K4AboutData * aboutData()
Returns the K4AboutData for consumption by KComponentData.
QAction * save(const QObject *recvr, const char *slot, QObject *parent)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue Aug 16 2022 03:55:21 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.