MythTV  master
mythcommandlineparser.cpp
Go to the documentation of this file.
1 /* -*- Mode: c++ -*-
2 *
3 * Class CommandLineArg
4 * Class MythCommandLineParser
5 *
6 * Copyright (C) Raymond Wagner 2011
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22 
23 #if defined ANDROID && __ANDROID_API__ < 24
24 // ftello and fseeko do not exist in android before api level 24
25 #define ftello ftell
26 #define fseeko fseek
27 #endif
28 
29 // C++ headers
30 #include <algorithm>
31 #include <csignal>
32 #include <cstdio>
33 #include <cstdlib>
34 #include <fstream>
35 #include <iostream>
36 #include <unistd.h>
37 
38 // System headers
39 #include <sys/types.h>
40 #ifndef _WIN32
41 # include <sys/ioctl.h>
42 # include <pwd.h>
43 # include <grp.h>
44 # if defined(__linux__) || defined(__LINUX__)
45 # include <sys/prctl.h>
46 # endif // linux
47 #endif // not _WIN32
48 
49 // Qt headers
50 #include <QtGlobal>
51 #include <QCoreApplication>
52 #include <QDateTime>
53 #include <QDir>
54 #include <QFile>
55 #include <QFileInfo>
56 #include <QRegularExpression>
57 #include <QSize>
58 #include <QString>
59 #include <QTextStream>
60 #include <QVariant>
61 #include <QVariantList>
62 #include <QVariantMap>
63 #include <utility>
64 
65 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
66  #define QT_ENDL endl
67 #else
68  #define QT_ENDL Qt::endl
69 #endif
70 
71 // MythTV headers
72 #include "mythcommandlineparser.h"
73 #include "mythcorecontext.h"
74 #include "exitcodes.h"
75 #include "mythconfig.h"
76 #include "mythlogging.h"
77 #include "mythversion.h"
78 #include "logging.h"
79 #include "mythmiscutil.h"
80 #include "mythdate.h"
81 
82 static constexpr int k_defaultWidth = 79;
83 
87 static int GetTermWidth(void)
88 {
89 #if defined(_WIN32) || defined(Q_OS_ANDROID)
90  return k_defaultWidth;
91 #else
92  struct winsize ws {};
93 
94  if (ioctl(0, TIOCGWINSZ, &ws) != 0)
95  return k_defaultWidth;
96 
97  return static_cast<int>(ws.ws_col);
98 #endif
99 }
100 
101 static QByteArray strip_quotes(const QByteArray& array)
102 {
103  return ((array.startsWith('"') && array.endsWith('"') ) ||
104  (array.startsWith('\'') && array.endsWith('\''))
105  ) ? array.mid(1, array.size() - 2) : array;
106 }
107 
108 static void wrapList(QStringList &list, int width)
109 {
110  // Set a minimum width of 5 to prevent a crash; if this is triggered,
111  // something has gone seriously wrong and the result won't really be usable
112  width = std::max(width, 5);
113 
114  for (int i = 0; i < list.size(); i++)
115  {
116  QString string = list.at(i);
117 
118  if( string.size() <= width )
119  continue;
120 
121  QString left = string.left(width);
122  bool inserted = false;
123 
124  while( !inserted && !left.endsWith(" " ))
125  {
126  if( string.mid(left.size(), 1) == " " )
127  {
128  list.replace(i, left);
129  list.insert(i+1, string.mid(left.size()).trimmed());
130  inserted = true;
131  }
132  else
133  {
134  left.chop(1);
135  if( !left.contains(" ") )
136  {
137  // Line is too long, just hyphenate it
138  list.replace(i, left + "-");
139  list.insert(i+1, string.mid(left.size()));
140  inserted = true;
141  }
142  }
143  }
144 
145  if( !inserted )
146  {
147  left.chop(1);
148  list.replace(i, left);
149  list.insert(i+1, string.mid(left.size()).trimmed());
150  }
151  }
152 }
153 
158 QStringList MythCommandLineParser::MythSplitCommandString(const QString &line)
159 {
160  QStringList fields;
164  enum states {
165  START,
166  INTEXT,
167  INSQUOTE,
168  INDQUOTE,
169  ESCTEXT,
170  ESCSQUOTE,
171  ESCDQUOTE,
172  };
173  states state = START;
174  int tokenStart = -1;
175 
176  for (int i = 0; i < line.size(); i++)
177  {
178  const QChar c = line.at(i);
179 
180  switch (state) {
181  case START:
182  tokenStart = i;
183  if (c.isSpace()) break;
184  if (c == '\'') state = INSQUOTE;
185  else if (c == '\"') state = INDQUOTE;
186  else if (c == '\\') state = ESCTEXT;
187  else state = INTEXT;
188  break;
189  case INTEXT:
190  if (c.isSpace()) {
191  fields += line.mid(tokenStart, i - tokenStart);
192  state = START;
193  break;
194  }
195  else if (c == '\'') state = INSQUOTE;
196  else if (c == '\"') state = INDQUOTE;
197  else if (c == '\\') state = ESCTEXT;
198  break;
199  case INSQUOTE:
200  if (c == '\'') state = INTEXT;
201  else if (c == '\\') state = ESCSQUOTE;
202  break;
203  case INDQUOTE:
204  if (c == '\"') state = INTEXT;
205  else if (c == '\\') state = ESCDQUOTE;
206  break;
207  case ESCTEXT: state = INTEXT; break;
208  case ESCSQUOTE: state = INSQUOTE; break;
209  case ESCDQUOTE: state = INDQUOTE; break;
210  }
211  }
212 
213  if (state != START)
214  fields += line.mid(tokenStart);
215  return fields;
216 }
217 
222 {
223  switch (type)
224  {
225  case Result::kEnd:
226  return "kEnd";
227 
228  case Result::kEmpty:
229  return "kEmpty";
230 
231  case Result::kOptOnly:
232  return "kOptOnly";
233 
234  case Result::kOptVal:
235  return "kOptVal";
236 
237  case Result::kCombOptVal:
238  return "kCombOptVal";
239 
240  case Result::kArg:
241  return "kArg";
242 
244  return "kPassthrough";
245 
246  case Result::kInvalid:
247  return "kInvalid";
248  }
249  return "kUnknown";
250 }
251 
286 CommandLineArg::CommandLineArg(const QString& name, QMetaType::Type type,
287  QVariant def, QString help, QString longhelp) :
288  ReferenceCounter(QString("CommandLineArg:%1").arg(name)),
289  m_name(name), m_type(type), m_default(std::move(def)),
290  m_help(std::move(help)), m_longhelp(std::move(longhelp))
291 {
292  if ((m_type != QMetaType::QString) && (m_type != QMetaType::QStringList) &&
293  (m_type != QMetaType::QVariantMap))
294  m_converted = true;
295 }
296 
303 CommandLineArg::CommandLineArg(const QString& name, QMetaType::Type type, QVariant def)
304  : ReferenceCounter(QString("CommandLineArg:%1").arg(name)),
305  m_name(name), m_type(type), m_default(std::move(def))
306 {
307  if ((m_type != QMetaType::QString) && (m_type != QMetaType::QStringList) &&
308  (m_type != QMetaType::QVariantMap))
309  m_converted = true;
310 }
311 
319 CommandLineArg::CommandLineArg(const QString& name) :
320  ReferenceCounter(QString("CommandLineArg:%1").arg(name)),
321  m_name(name)
322 {
323 }
324 
329 {
330  // this may cause problems if the terminal is too narrow, or if too
331  // many keywords for the same argument are used
332  return m_keywords.join(", ");
333 }
334 
339 {
340  int len = GetKeywordString().length();
341 
342  QList<CommandLineArg*>::const_iterator i1;
343  for (i1 = m_parents.begin(); i1 != m_parents.end(); ++i1)
344  len = std::max(len, (*i1)->GetKeywordLength()+2);
345 
346  return len;
347 }
348 
364 QString CommandLineArg::GetHelpString(int off, const QString& group, bool force) const
365 {
366  QString helpstr;
367  QTextStream msg(&helpstr, QIODevice::WriteOnly);
368  int termwidth = GetTermWidth();
369  if (termwidth < off)
370  {
371  if (off > 70)
372  {
373  // developer has configured some absurdly long command line
374  // arguments, but we still need to do something
375  termwidth = off+40;
376  }
377  else
378  {
379  // user is running uselessly narrow console, use a sane console
380  // width instead
381  termwidth = k_defaultWidth;
382  }
383  }
384 
385  if (m_help.isEmpty() && !force)
386  // only print if there is a short help to print
387  return helpstr;
388 
389  if ((m_group != group) && !force)
390  // only print if looping over the correct group
391  return helpstr;
392 
393  if (!m_parents.isEmpty() && !force)
394  {
395  // only print if an independent option, not subject
396  // to a parent option
397  return helpstr;
398  }
399 
400  if (!m_deprecated.isEmpty())
401  // option is marked as deprecated, do not show
402  return helpstr;
403 
404  if (!m_removed.isEmpty())
405  // option is marked as removed, do not show
406  return helpstr;
407 
408  QString pad;
409  pad.fill(' ', off);
410 
411  // print the first line with the available keywords
412  QStringList hlist = m_help.split('\n');
413  wrapList(hlist, termwidth-off);
414  msg << " ";
415  if (!m_parents.isEmpty())
416  msg << " ";
417  msg << GetKeywordString().leftJustified(off, ' ')
418  << hlist.takeFirst() << QT_ENDL;
419 
420  // print remaining lines with necessary padding
421  for (const auto & line : qAsConst(hlist))
422  msg << pad << line << QT_ENDL;
423 
424  // loop through any child arguments to print underneath
425  for (auto * arg : qAsConst(m_children))
426  msg << arg->GetHelpString(off, group, true);
427 
428  msg.flush();
429  return helpstr;
430 }
431 
439 QString CommandLineArg::GetLongHelpString(QString keyword) const
440 {
441  QString helpstr;
442  QTextStream msg(&helpstr, QIODevice::WriteOnly);
443  int termwidth = GetTermWidth();
444 
445  // help called for an argument that is not me, this should not happen
446  if (!m_keywords.contains(keyword))
447  return helpstr;
448 
449  // argument has been marked as removed, so warn user of such
450  if (!m_removed.isEmpty())
451  {
452  PrintRemovedWarning(keyword);
453  // argument has been marked as deprecated, so warn user of such
454  }
455  else if (!m_deprecated.isEmpty())
456  {
457  PrintDeprecatedWarning(keyword);
458  }
459 
460  msg << "Option: " << keyword << QT_ENDL << QT_ENDL;
461 
462  bool first = true;
463 
464  // print all related keywords, padding for multiples
465  for (const auto & word : qAsConst(m_keywords))
466  {
467  if (word != keyword)
468  {
469  if (first)
470  {
471  msg << "Aliases: " << word << QT_ENDL;
472  first = false;
473  }
474  else
475  msg << " " << word << QT_ENDL;
476  }
477  }
478 
479  // print type and default for the stored value
480 #if QT_VERSION < QT_VERSION_CHECK(5,15,0)
481  msg << "Type: " << QMetaType::typeName(m_type) << QT_ENDL;
482 #else
483  msg << "Type: " << QMetaType(m_type).name() << QT_ENDL;
484 #endif
485  if (m_default.canConvert<QString>())
486  msg << "Default: " << m_default.toString() << QT_ENDL;
487 
488  QStringList help;
489  if (m_longhelp.isEmpty())
490  help = m_help.split("\n");
491  else
492  help = m_longhelp.split("\n");
493  wrapList(help, termwidth-13);
494 
495  // print description, wrapping and padding as necessary
496  msg << "Description: " << help.takeFirst() << QT_ENDL;
497  for (const auto & line : qAsConst(help))
498  msg << " " << line << QT_ENDL;
499 
500  QList<CommandLineArg*>::const_iterator i2;
501 
502  // loop through the four relation types and print
503  if (!m_parents.isEmpty())
504  {
505  msg << QT_ENDL << "Can be used in combination with:" << QT_ENDL;
506  for (auto * parent : qAsConst(m_parents))
507  msg << " " << parent->GetPreferredKeyword()
508  .toLocal8Bit().constData();
509  msg << QT_ENDL;
510  }
511 
512  if (!m_children.isEmpty())
513  {
514  msg << QT_ENDL << "Allows the use of:" << QT_ENDL;
515  for (i2 = m_children.constBegin(); i2 != m_children.constEnd(); ++i2)
516  msg << " " << (*i2)->GetPreferredKeyword()
517  .toLocal8Bit().constData();
518  msg << QT_ENDL;
519  }
520 
521  if (!m_requires.isEmpty())
522  {
523  msg << QT_ENDL << "Requires the use of:" << QT_ENDL;
524  for (i2 = m_requires.constBegin(); i2 != m_requires.constEnd(); ++i2)
525  msg << " " << (*i2)->GetPreferredKeyword()
526  .toLocal8Bit().constData();
527  msg << QT_ENDL;
528  }
529 
530  if (!m_blocks.isEmpty())
531  {
532  msg << QT_ENDL << "Prevents the use of:" << QT_ENDL;
533  for (i2 = m_blocks.constBegin(); i2 != m_blocks.constEnd(); ++i2)
534  msg << " " << (*i2)->GetPreferredKeyword()
535  .toLocal8Bit().constData();
536  msg << QT_ENDL;
537  }
538 
539  msg.flush();
540  return helpstr;
541 }
542 
549 bool CommandLineArg::Set(const QString& opt)
550 {
551  m_usedKeyword = opt;
552 
553  switch (m_type)
554  {
555  case QMetaType::Bool:
556  m_stored = QVariant(!m_default.toBool());
557  break;
558 
559  case QMetaType::Int:
560  if (m_stored.isNull())
561  m_stored = QVariant(1);
562  else
563  m_stored = QVariant(m_stored.toInt() + 1);
564  break;
565 
566  case QMetaType::QString:
568  break;
569 
570  default:
571  std::cerr << "Command line option did not receive value:" << std::endl
572  << " " << opt.toLocal8Bit().constData() << std::endl;
573  return false;
574  }
575 
576  m_given = true;
577  return true;
578 }
579 
582 bool CommandLineArg::Set(const QString& opt, const QByteArray& val)
583 {
584  QVariantList vlist;
585  QList<QByteArray> blist;
586  QVariantMap vmap;
587  m_usedKeyword = opt;
588 
589  switch (m_type)
590  {
591  case QMetaType::Bool:
592  std::cerr << "Boolean type options do not accept values:" << std::endl
593  << " " << opt.toLocal8Bit().constData() << std::endl;
594  return false;
595 
596  case QMetaType::QString:
597  m_stored = QVariant(val);
598  break;
599 
600  case QMetaType::Int:
601  m_stored = QVariant(val.toInt());
602  break;
603 
604  case QMetaType::UInt:
605  m_stored = QVariant(val.toUInt());
606  break;
607 
608  case QMetaType::LongLong:
609  m_stored = QVariant(val.toLongLong());
610  break;
611 
612  case QMetaType::Double:
613  m_stored = QVariant(val.toDouble());
614  break;
615 
616  case QMetaType::QDateTime:
617  m_stored = QVariant(MythDate::fromString(QString(val)));
618  break;
619 
620  case QMetaType::QStringList:
621  if (!m_stored.isNull())
622  vlist = m_stored.toList();
623  vlist << val;
624  m_stored = QVariant(vlist);
625  break;
626 
627  case QMetaType::QVariantMap:
628  if (!val.contains('='))
629  {
630  std::cerr << "Command line option did not get expected "
631  << "key/value pair" << std::endl;
632  return false;
633  }
634 
635  blist = val.split('=');
636 
637  if (!m_stored.isNull())
638  vmap = m_stored.toMap();
639  vmap[QString(strip_quotes(blist[0]))] = QVariant(strip_quotes(blist[1]));
640  m_stored = QVariant(vmap);
641  break;
642 
643  case QMetaType::QSize:
644  if (!val.contains('x'))
645  {
646  std::cerr << "Command line option did not get expected "
647  << "XxY pair" << std::endl;
648  return false;
649  }
650 
651  blist = val.split('x');
652  m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
653  break;
654 
655  default:
656  m_stored = QVariant(val);
657  }
658 
659  m_given = true;
660  return true;
661 }
662 
666 {
667  m_children << new CommandLineArg(opt);
668  return this;
669 }
670 
674 {
675  for (const auto& opt : qAsConst(opts))
676  m_children << new CommandLineArg(opt);
677  return this;
678 }
679 
683 {
684  m_parents << new CommandLineArg(opt);
685  return this;
686 }
687 
691 {
692  for (const auto& opt : qAsConst(opts))
693  m_parents << new CommandLineArg(opt);
694  return this;
695 }
696 
700 {
701  m_parents << new CommandLineArg(opt);
702  return this;
703 }
704 
708 {
709  for (const auto& opt : qAsConst(opts))
710  m_parents << new CommandLineArg(opt);
711  return this;
712 }
713 
717 {
718  m_children << new CommandLineArg(opt);
719  return this;
720 }
721 
725 {
726  for (const auto& opt : qAsConst(opts))
727  m_children << new CommandLineArg(opt);
728  return this;
729 }
730 
734 {
735  m_children << new CommandLineArg(opt);
736  m_requires << new CommandLineArg(opt);
737  return this;
738 }
739 
743 {
744  for (const auto& opt : qAsConst(opts))
745  {
746  m_children << new CommandLineArg(opt);
747  m_requires << new CommandLineArg(opt);
748  }
749  return this;
750 }
751 
755 {
756  m_parents << new CommandLineArg(opt);
757  m_requiredby << new CommandLineArg(opt);
758  return this;
759 }
760 
764 {
765  for (const auto& opt : qAsConst(opts))
766  {
767  m_parents << new CommandLineArg(opt);
768  m_requiredby << new CommandLineArg(opt);
769  }
770  return this;
771 }
772 
776 {
777  m_requires << new CommandLineArg(opt);
778  return this;
779 }
780 
784 {
785  for (const auto& opt : qAsConst(opts))
786  m_requires << new CommandLineArg(opt);
787  return this;
788 }
789 
793 {
794  m_blocks << new CommandLineArg(opt);
795  return this;
796 }
797 
801 {
802  for (const auto& opt : qAsConst(opts))
803  m_blocks << new CommandLineArg(opt);
804  return this;
805 }
806 
810 {
811  if (depstr.isEmpty())
812  depstr = "and will be removed in a future version.";
813  m_deprecated = depstr;
814  return this;
815 }
816 
819 CommandLineArg* CommandLineArg::SetRemoved(QString remstr, QString remver)
820 {
821  if (remstr.isEmpty())
822  remstr = "and is no longer available in this version.";
823  m_removed = remstr;
824  m_removedversion = std::move(remver);
825  return this;
826 }
827 
833 void CommandLineArg::SetParentOf(CommandLineArg *other, bool forward)
834 {
835  bool replaced = false;
836  other->IncrRef();
837 
838  for (int i = 0; i < m_children.size(); i++)
839  {
840  if (m_children[i]->m_name == other->m_name)
841  {
842  m_children[i]->DecrRef();
843  m_children.replace(i, other);
844  replaced = true;
845  break;
846  }
847  }
848 
849  if (!replaced)
850  m_children << other;
851 
852  if (forward)
853  other->SetChildOf(this, false);
854 }
855 
861 void CommandLineArg::SetChildOf(CommandLineArg *other, bool forward)
862 {
863  bool replaced = false;
864  other->IncrRef();
865 
866  for (int i = 0; i < m_parents.size(); i++)
867  {
868  if (m_parents[i]->m_name == other->m_name)
869  {
870  m_parents[i]->DecrRef();
871  m_parents.replace(i, other);
872  replaced = true;
873  break;
874  }
875  }
876 
877  if (!replaced)
878  m_parents << other;
879 
880  if (forward)
881  other->SetParentOf(this, false);
882 }
883 
889 void CommandLineArg::SetRequires(CommandLineArg *other, bool /*forward*/)
890 {
891  bool replaced = false;
892  other->IncrRef();
893 
894  for (int i = 0; i < m_requires.size(); i++)
895  {
896  if (m_requires[i]->m_name == other->m_name)
897  {
898  m_requires[i]->DecrRef();
899  m_requires.replace(i, other);
900  replaced = true;
901  break;
902  }
903  }
904 
905  if (!replaced)
906  m_requires << other;
907 
908 // requirements need not be reciprocal
909 // if (forward)
910 // other->SetRequires(this, false);
911 }
912 
918 void CommandLineArg::SetBlocks(CommandLineArg *other, bool forward)
919 {
920  bool replaced = false;
921  other->IncrRef();
922 
923  for (int i = 0; i < m_blocks.size(); i++)
924  {
925  if (m_blocks[i]->m_name == other->m_name)
926  {
927  m_blocks[i]->DecrRef();
928  m_blocks.replace(i, other);
929  replaced = true;
930  break;
931  }
932  }
933 
934  if (!replaced)
935  m_blocks << other;
936 
937  if (forward)
938  other->SetBlocks(this, false);
939 }
940 
943 void CommandLineArg::AllowOneOf(const QList<CommandLineArg*>& args)
944 {
945  // TODO: blocks do not get set properly if multiple dummy arguments
946  // are provided. since this method will not have access to the
947  // argument list, this issue will have to be resolved later in
948  // ReconcileLinks().
949 
950  // loop through all but the last entry
951  for (auto i1 = args.cbegin(); i1 != args.cend()-1; ++i1)
952  {
953  // loop through the next to the last entry
954  // and block use with the current
955  for (auto i2 = i1+1; i2 != args.cend(); ++i2)
956  {
957  (*i1)->SetBlocks(*i2);
958  }
959 
960  if ((*i1)->m_type == QMetaType::UnknownType)
961  (*i1)->DecrRef();
962  }
963 }
964 
972 {
973  if (!QCoreApplication::instance())
974  // QApplication not available, no sense doing anything yet
975  return;
976 
977  if (m_converted)
978  // already run, abort
979  return;
980 
981  if (!m_given)
982  {
983  // nothing to work on, abort
984  m_converted = true;
985  return;
986  }
987 
988 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
989  auto storedType = static_cast<QMetaType::Type>(m_stored.type());
990 #else
991  auto storedType = m_stored.typeId();
992 #endif
993  if (m_type == QMetaType::QString)
994  {
995  if (storedType == QMetaType::QByteArray)
996  {
997  m_stored = QString::fromLocal8Bit(m_stored.toByteArray());
998  }
999  // else
1000  // not sure why this isnt a bytearray, but ignore it and
1001  // set it as converted
1002  }
1003  else if (m_type == QMetaType::QStringList)
1004  {
1005  if (storedType == QMetaType::QVariantList)
1006  {
1007  QVariantList vlist = m_stored.toList();
1008  QStringList slist;
1009  for (const auto& item : qAsConst(vlist))
1010  slist << QString::fromLocal8Bit(item.toByteArray());
1011  m_stored = QVariant(slist);
1012  }
1013  }
1014  else if (m_type == QMetaType::QVariantMap)
1015  {
1016  QVariantMap vmap = m_stored.toMap();
1017  // NOLINTNEXTLINE(modernize-loop-convert)
1018  for (auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1019  (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1020  }
1021  else
1022  return;
1023 
1024  m_converted = true;
1025 }
1026 
1027 
1034 {
1035  QStringList::const_iterator it;
1036  QString preferred;
1037  int len = 0;
1038 
1039  for (it = m_keywords.constBegin(); it != m_keywords.constEnd(); ++it)
1040  {
1041  int len2 = (*it).size();
1042  if (len2 > len)
1043  {
1044  preferred = *it;
1045  len = len2;
1046  }
1047  }
1048 
1049  return preferred;
1050 }
1051 
1056 {
1057  if (!m_given)
1058  return true; // not in use, no need for checks
1059 
1060  QList<CommandLineArg*>::const_iterator i;
1061 
1062  bool passes = false;
1063  for (i = m_parents.constBegin(); i != m_parents.constEnd(); ++i)
1064  {
1065  // one of these must have been defined
1066  if ((*i)->m_given)
1067  {
1068  passes = true;
1069  break;
1070  }
1071  }
1072  if (!passes && !m_parents.isEmpty())
1073  {
1074  std::cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
1075  << " requires at least one of the following arguments" << std::endl;
1076  for (i = m_parents.constBegin(); i != m_parents.constEnd(); ++i)
1077  std::cerr << " "
1078  << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1079  std::cerr << std::endl << std::endl;
1080  return false;
1081  }
1082 
1083  // we dont care about children
1084 
1085  for (i = m_requires.constBegin(); i != m_requires.constEnd(); ++i)
1086  {
1087  // all of these must have been defined
1088  if (!(*i)->m_given)
1089  {
1090  std::cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
1091  << " requires all of the following be defined as well"
1092  << std::endl;
1093  for (i = m_requires.constBegin(); i != m_requires.constEnd(); ++i)
1094  {
1095  std::cerr << " "
1096  << (*i)->GetPreferredKeyword().toLocal8Bit()
1097  .constData();
1098  }
1099  std::cerr << std::endl << std::endl;
1100  return false;
1101  }
1102  }
1103 
1104  for (i = m_blocks.constBegin(); i != m_blocks.constEnd(); ++i)
1105  {
1106  // none of these can be defined
1107  if ((*i)->m_given)
1108  {
1109  std::cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
1110  << " requires that none of the following be defined" << std::endl;
1111  for (i = m_blocks.constBegin(); i != m_blocks.constEnd(); ++i)
1112  {
1113  std::cerr << " "
1114  << (*i)->GetPreferredKeyword().toLocal8Bit()
1115  .constData();
1116  }
1117  std::cerr << std::endl << std::endl;
1118  return false;
1119  }
1120  }
1121 
1122  return true;
1123 }
1124 
1128 {
1129  // clear out interdependent pointers in preparation for deletion
1130  while (!m_parents.isEmpty())
1131  m_parents.takeFirst()->DecrRef();
1132 
1133  while (!m_children.isEmpty())
1134  m_children.takeFirst()->DecrRef();
1135 
1136  while (!m_blocks.isEmpty())
1137  m_blocks.takeFirst()->DecrRef();
1138 
1139  while (!m_requires.isEmpty())
1140  m_requires.takeFirst()->DecrRef();
1141 
1142  while (!m_requiredby.isEmpty())
1143  m_requiredby.takeFirst()->DecrRef();
1144 }
1145 
1149 {
1150  if (!m_given)
1151  return;
1152 
1153  std::cerr << " " << m_name.leftJustified(30).toLocal8Bit().constData();
1154 
1155  QSize tmpsize;
1156  QMap<QString, QVariant> tmpmap;
1157  QMap<QString, QVariant>::const_iterator it;
1158  QVariantList vlist;
1159  bool first = true;
1160 
1161  switch (m_type)
1162  {
1163  case QMetaType::Bool:
1164  std::cerr << (m_stored.toBool() ? "True" : "False") << std::endl;
1165  break;
1166 
1167  case QMetaType::Int:
1168  std::cerr << m_stored.toInt() << std::endl;
1169  break;
1170 
1171  case QMetaType::UInt:
1172  std::cerr << m_stored.toUInt() << std::endl;
1173  break;
1174 
1175  case QMetaType::LongLong:
1176  std::cerr << m_stored.toLongLong() << std::endl;
1177  break;
1178 
1179  case QMetaType::Double:
1180  std::cerr << m_stored.toDouble() << std::endl;
1181  break;
1182 
1183  case QMetaType::QSize:
1184  tmpsize = m_stored.toSize();
1185  std::cerr << "x=" << tmpsize.width()
1186  << " y=" << tmpsize.height()
1187  << std::endl;
1188  break;
1189 
1190  case QMetaType::QString:
1191  std::cerr << '"' << m_stored.toByteArray().constData()
1192  << '"' << std::endl;
1193  break;
1194 
1195  case QMetaType::QStringList:
1196  vlist = m_stored.toList();
1197  std::cerr << '"' << vlist.takeFirst().toByteArray().constData() << '"';
1198  for (const auto& str : qAsConst(vlist))
1199  {
1200  std::cerr << ", \""
1201  << str.constData()
1202  << '"';
1203  }
1204  std::cerr << std::endl;
1205  break;
1206 
1207  case QMetaType::QVariantMap:
1208  tmpmap = m_stored.toMap();
1209  for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1210  {
1211  if (first)
1212  first = false;
1213  else
1214  std::cerr << QString("").leftJustified(32)
1215  .toLocal8Bit().constData();
1216 
1217  std::cerr << it.key().toLocal8Bit().constData()
1218  << '='
1219  << it->toByteArray().constData()
1220  << std::endl;
1221  }
1222 
1223  break;
1224 
1225  case QMetaType::QDateTime:
1226  std::cerr << m_stored.toDateTime().toString(Qt::ISODate)
1227  .toLocal8Bit().constData()
1228  << std::endl;
1229  break;
1230 
1231  default:
1232  std::cerr << std::endl;
1233  }
1234 }
1235 
1238 void CommandLineArg::PrintRemovedWarning(QString &keyword) const
1239 {
1240  QString warn = QString("%1 has been removed").arg(keyword);
1241  if (!m_removedversion.isEmpty())
1242  warn += QString(" as of MythTV %1").arg(m_removedversion);
1243 
1244  std::cerr << QString("****************************************************\n"
1245  " WARNING: %1\n"
1246  " %2\n"
1247  "****************************************************\n\n")
1248  .arg(warn, m_removed)
1249  .toLocal8Bit().constData();
1250 }
1251 
1254 void CommandLineArg::PrintDeprecatedWarning(QString &keyword) const
1255 {
1256  std::cerr << QString("****************************************************\n"
1257  " WARNING: %1 has been deprecated\n"
1258  " %2\n"
1259  "****************************************************\n\n")
1260  .arg(keyword, m_deprecated)
1261  .toLocal8Bit().constData();
1262 }
1263 
1278  : m_appname(std::move(appname))
1279 {
1280  if (qEnvironmentVariableIsSet("VERBOSE_PARSER"))
1281  {
1282  std::cerr << "MythCommandLineParser is now operating verbosely." << std::endl;
1283  m_verbose = true;
1284  }
1285 
1287 }
1288 
1290 {
1291  QMap<QString, CommandLineArg*>::iterator i;
1292 
1293  i = m_namedArgs.begin();
1294  while (i != m_namedArgs.end())
1295  {
1296  (*i)->CleanupLinks();
1297  (*i)->DecrRef();
1298  i = m_namedArgs.erase(i);
1299  }
1300 
1301  i = m_optionedArgs.begin();
1302  while (i != m_optionedArgs.end())
1303  {
1304  (*i)->DecrRef();
1305  i = m_optionedArgs.erase(i);
1306  }
1307 }
1308 
1343  const QString& name, QMetaType::Type type, QVariant def,
1344  QString help, QString longhelp)
1345 {
1346  CommandLineArg *arg = nullptr;
1347 
1348  if (m_namedArgs.contains(name))
1349  arg = m_namedArgs[name];
1350  else
1351  {
1352  arg = new CommandLineArg(name, type, std::move(def), std::move(help), std::move(longhelp));
1353  m_namedArgs.insert(name, arg);
1354  }
1355 
1356  for (const auto & str : qAsConst(arglist))
1357  {
1358  if (!m_optionedArgs.contains(str))
1359  {
1360  arg->AddKeyword(str);
1361  if (m_verbose)
1362  {
1363  std::cerr << "Adding " << str.toLocal8Bit().constData()
1364  << " as taking type '"
1365 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1366  << QVariant::typeToName(static_cast<int>(type))
1367 #else
1368  << QMetaType(type).name()
1369 #endif
1370  << "'" << std::endl;
1371  }
1372  arg->IncrRef();
1373  m_optionedArgs.insert(str, arg);
1374  }
1375  }
1376 
1377  return arg;
1378 }
1379 
1383 {
1384  std::cout << "Please attach all output as a file in bug reports." << std::endl;
1385  std::cout << "MythTV Version : " << GetMythSourceVersion() << std::endl;
1386  std::cout << "MythTV Branch : " << GetMythSourcePath() << std::endl;
1387  std::cout << "Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1388  std::cout << "Library API : " << MYTH_BINARY_VERSION << std::endl;
1389  std::cout << "QT Version : " << QT_VERSION_STR << std::endl;
1390 #ifdef MYTH_BUILD_CONFIG
1391  std::cout << "Options compiled in:" <<std::endl;
1392  std::cout << MYTH_BUILD_CONFIG << std::endl;
1393 #endif
1394 }
1395 
1399 {
1400  QString help = GetHelpString();
1401  std::cerr << help.toLocal8Bit().constData();
1402 }
1403 
1410 {
1411  QString helpstr;
1412  QTextStream msg(&helpstr, QIODevice::WriteOnly);
1413 
1414  QString versionStr = QString("%1 version: %2 [%3] www.mythtv.org")
1416  msg << versionStr << QT_ENDL;
1417 
1418  if (toString("showhelp").isEmpty())
1419  {
1420  // build generic help text
1421 
1422  QString descr = GetHelpHeader();
1423  if (descr.size() > 0)
1424  msg << QT_ENDL << descr << QT_ENDL << QT_ENDL;
1425 
1426  // loop through registered arguments to populate list of groups
1427  QStringList groups("");
1428  int maxlen = 0;
1429  for (auto * cmdarg : qAsConst(m_namedArgs))
1430  {
1431  maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1432  if (!groups.contains(cmdarg->m_group))
1433  groups << cmdarg->m_group;
1434  }
1435 
1436  // loop through list of groups and print help string for each
1437  // arguments will filter themselves if they are not in the group
1438  maxlen += 4;
1439  for (const auto & group : qAsConst(groups))
1440  {
1441  if (group.isEmpty())
1442  msg << "Misc. Options:" << QT_ENDL << QT_ENDL;
1443  else
1444  msg << group.toLocal8Bit().constData() << " Options:" << QT_ENDL << QT_ENDL;
1445 
1446  for (auto * cmdarg : qAsConst(m_namedArgs))
1447  msg << cmdarg->GetHelpString(maxlen, group);
1448  msg << QT_ENDL;
1449  }
1450  }
1451  else
1452  {
1453  // build help for a specific argument
1454  QString optstr = "-" + toString("showhelp");
1455  if (!m_optionedArgs.contains(optstr))
1456  {
1457  optstr = "-" + optstr;
1458  if (!m_optionedArgs.contains(optstr))
1459  return QString("Could not find option matching '%1'\n")
1460  .arg(toString("showhelp"));
1461  }
1462 
1463  if (m_optionedArgs[optstr] != nullptr)
1464  msg << m_optionedArgs[optstr]->GetLongHelpString(optstr);
1465  }
1466 
1467  msg.flush();
1468  return helpstr;
1469 }
1470 
1474  int &argpos, QString &opt, QByteArray &val)
1475 {
1476  opt.clear();
1477  val.clear();
1478 
1479  if (argpos >= argc)
1480  // this shouldnt happen, return and exit
1481  return Result::kEnd;
1482 
1483  QByteArray tmp(argv[argpos]);
1484  if (tmp.isEmpty())
1485  // string is empty, return and loop
1486  return Result::kEmpty;
1487 
1488  if (m_passthroughActive)
1489  {
1490  // pass through has been activated
1491  val = tmp;
1492  return Result::kArg;
1493  }
1494 
1495  if (tmp.startsWith('-') && tmp.size() > 1)
1496  {
1497  if (tmp == "--")
1498  {
1499  // all options beyond this will be passed as a single string
1500  m_passthroughActive = true;
1501  return Result::kPassthrough;
1502  }
1503 
1504  if (tmp.contains('='))
1505  {
1506  // option contains '=', split
1507  QList<QByteArray> blist = tmp.split('=');
1508 
1509  if (blist.size() != 2)
1510  {
1511  // more than one '=' in option, this is not handled
1512  opt = QString(tmp);
1513  return Result::kInvalid;
1514  }
1515 
1516  opt = QString(strip_quotes(blist[0]));
1517  val = strip_quotes(blist[1]);
1518  return Result::kCombOptVal;
1519  }
1520 
1521  opt = QString(tmp);
1522 
1523  if (argpos+1 >= argc)
1524  // end of input, option only
1525  return Result::kOptOnly;
1526 
1527  tmp = QByteArray(argv[++argpos]);
1528  if (tmp.isEmpty())
1529  // empty string, option only
1530  return Result::kOptOnly;
1531 
1532  if (tmp.startsWith("-") && tmp.size() > 1)
1533  {
1534  // no value found for option, backtrack
1535  argpos--;
1536  return Result::kOptOnly;
1537  }
1538 
1539  val = tmp;
1540  return Result::kOptVal;
1541  }
1542 
1543  // input is not an option string, return as arg
1544  val = tmp;
1545  return Result::kArg;
1546 }
1547 
1554 bool MythCommandLineParser::Parse(int argc, const char * const * argv)
1555 {
1556  Result res = Result::kEnd;
1557  QString opt;
1558  QByteArray val;
1559  CommandLineArg *argdef = nullptr;
1560 
1561  // reconnect interdependencies between command line options
1562  if (!ReconcileLinks())
1563  return false;
1564 
1565  // loop through command line arguments until all are spent
1566  for (int argpos = 1; argpos < argc; ++argpos)
1567  {
1568 
1569  // pull next option
1570  res = getOpt(argc, argv, argpos, opt, val);
1571 
1572  if (m_verbose)
1573  {
1574  std::cerr << "res: " << NamedOptType(res) << std::endl
1575  << "opt: " << opt.toLocal8Bit().constData() << std::endl
1576  << "val: " << val.constData() << std::endl << std::endl;
1577  }
1578 
1579  // '--' found on command line, enable passthrough mode
1580  if (res == Result::kPassthrough && !m_namedArgs.contains("_passthrough"))
1581  {
1582  std::cerr << "Received '--' but passthrough has not been enabled" << std::endl;
1583  SetValue("showhelp", "");
1584  return false;
1585  }
1586 
1587  // end of options found, terminate loop
1588  if (res == Result::kEnd)
1589  break;
1590 
1591  // GetOpt pulled an empty option, this shouldnt happen by ignore
1592  // it and continue
1593  if (res == Result::kEmpty)
1594  continue;
1595 
1596  // more than one equal found in key/value pair, fault out
1597  if (res == Result::kInvalid)
1598  {
1599  std::cerr << "Invalid option received:" << std::endl << " "
1600  << opt.toLocal8Bit().constData();
1601  SetValue("showhelp", "");
1602  return false;
1603  }
1604 
1605  // passthrough is active, so add the data to the stringlist
1606  if (m_passthroughActive)
1607  {
1608  m_namedArgs["_passthrough"]->Set("", val);
1609  continue;
1610  }
1611 
1612  // argument with no preceeding '-' encountered, add to stringlist
1613  if (res == Result::kArg)
1614  {
1615  if (!m_namedArgs.contains("_args"))
1616  {
1617  std::cerr << "Received '"
1618  << val.constData()
1619  << "' but unassociated arguments have not been enabled"
1620  << std::endl;
1621  SetValue("showhelp", "");
1622  return false;
1623  }
1624 
1625  m_namedArgs["_args"]->Set("", val);
1626  continue;
1627  }
1628 
1629  // this line should not be passed once arguments have started collecting
1630  if (toBool("_args"))
1631  {
1632  std::cerr << "Command line arguments received out of sequence"
1633  << std::endl;
1634  SetValue("showhelp", "");
1635  return false;
1636  }
1637 
1638 #ifdef Q_OS_DARWIN
1639  if (opt.startsWith("-psn_"))
1640  {
1641  std::cerr << "Ignoring Process Serial Number from command line"
1642  << std::endl;
1643  continue;
1644  }
1645 #endif
1646 
1647  if (!m_optionedArgs.contains(opt))
1648  {
1649  // argument is unhandled, check if parser allows arbitrary input
1650  if (m_namedArgs.contains("_extra"))
1651  {
1652  // arbitrary allowed, specify general collection pool
1653  argdef = m_namedArgs["_extra"];
1654  QByteArray tmp = opt.toLocal8Bit();
1655  tmp += '=';
1656  tmp += val;
1657  val = tmp;
1658  res = Result::kOptVal;
1659  }
1660  else
1661  {
1662  // arbitrary not allowed, fault out
1663  std::cerr << "Unhandled option given on command line:" << std::endl
1664  << " " << opt.toLocal8Bit().constData() << std::endl;
1665  SetValue("showhelp", "");
1666  return false;
1667  }
1668  }
1669  else
1670  argdef = m_optionedArgs[opt];
1671 
1672  // argument has been marked as removed, warn user and fail
1673  if (!argdef->m_removed.isEmpty())
1674  {
1675  argdef->PrintRemovedWarning(opt);
1676  SetValue("showhelp", "");
1677  return false;
1678  }
1679 
1680  // argument has been marked as deprecated, warn user
1681  if (!argdef->m_deprecated.isEmpty())
1682  argdef->PrintDeprecatedWarning(opt);
1683 
1684  if (m_verbose)
1685  std::cerr << "name: " << argdef->GetName().toLocal8Bit().constData()
1686  << std::endl;
1687 
1688  // argument is keyword only, no value
1689  if (res == Result::kOptOnly)
1690  {
1691  if (!argdef->Set(opt))
1692  {
1693  SetValue("showhelp", "");
1694  return false;
1695  }
1696  }
1697  // argument has keyword and value
1698  else if ((res == Result::kOptVal) || (res == Result::kCombOptVal))
1699  {
1700  if (!argdef->Set(opt, val))
1701  {
1702  // if option and value were combined with a '=', abort directly
1703  // otherwise, attempt processing them independenly
1704  if ((res == Result::kCombOptVal) || !argdef->Set(opt))
1705  {
1706  SetValue("showhelp", "");
1707  return false;
1708  }
1709  // drop back an iteration so the unused value will get
1710  // processed a second time as a keyword-less argument
1711  --argpos;
1712  }
1713  }
1714  else
1715  {
1716  SetValue("showhelp", "");
1717  return false; // this should not occur
1718  }
1719 
1720  if (m_verbose)
1721  std::cerr << "value: " << argdef->m_stored.toString().toLocal8Bit().constData()
1722  << std::endl;
1723  }
1724 
1725  if (m_verbose)
1726  {
1727  std::cerr << "Processed option list:" << std::endl;
1728  for (auto * cmdarg : qAsConst(m_namedArgs))
1729  cmdarg->PrintVerbose();
1730 
1731  if (m_namedArgs.contains("_args"))
1732  {
1733  std::cerr << std::endl << "Extra argument list:" << std::endl;
1734  QStringList slist = toStringList("_args");
1735  for (const auto& lopt : qAsConst(slist))
1736  std::cerr << " " << (lopt).toLocal8Bit().constData() << std::endl;
1737  }
1738 
1739  if (m_namedArgs.contains("_passthrough"))
1740  {
1741  std::cerr << std::endl << "Passthrough string:" << std::endl;
1742  std::cerr << " " << GetPassthrough().toLocal8Bit().constData() << std::endl;
1743  }
1744 
1745  std::cerr << std::endl;
1746  }
1747 
1748  // make sure all interdependencies are fulfilled
1749  for (auto * cmdarg : qAsConst(m_namedArgs))
1750  {
1751  if (!cmdarg->TestLinks())
1752  {
1753  QString keyword = cmdarg->m_usedKeyword;
1754  if (keyword.startsWith('-'))
1755  {
1756  if (keyword.startsWith("--"))
1757  keyword.remove(0,2);
1758  else
1759  keyword.remove(0,1);
1760  }
1761 
1762  SetValue("showhelp", keyword);
1763  return false;
1764  }
1765  }
1766 
1767  return true;
1768 }
1769 
1770 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, bool def,
1771  QString help, QString longhelp)
1772 {
1773  return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(help), std::move(longhelp));
1774 }
1775 
1776 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, int def,
1777  QString help, QString longhelp)
1778 {
1779  return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(help), std::move(longhelp));
1780 }
1781 
1782 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, uint def,
1783  QString help, QString longhelp)
1784 {
1785  return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(help), std::move(longhelp));
1786 }
1787 
1788 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, long long def,
1789  QString help, QString longhelp)
1790 {
1791  return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(help), std::move(longhelp));
1792 }
1793 
1794 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, double def,
1795  QString help, QString longhelp)
1796 {
1797  return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(help), std::move(longhelp));
1798 }
1799 
1800 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, const char *def,
1801  QString help, QString longhelp)
1802 {
1803  return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(help), std::move(longhelp));
1804 }
1805 
1806 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, const QString& def,
1807  QString help, QString longhelp)
1808 {
1809  return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(help), std::move(longhelp));
1810 }
1811 
1812 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, QSize def,
1813  QString help, QString longhelp)
1814 {
1815  return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(help), std::move(longhelp));
1816 }
1817 
1818 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, const QDateTime& def,
1819  QString help, QString longhelp)
1820 {
1821  return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(help), std::move(longhelp));
1822 }
1823 
1824 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name, QMetaType::Type type,
1825  QString help, QString longhelp)
1826 {
1827  return add(QStringList(arg), name, type,
1828 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1829  QVariant(static_cast<QVariant::Type>(type)),
1830 #else
1831  QVariant(QMetaType(type)),
1832 #endif
1833  std::move(help), std::move(longhelp));
1834 }
1835 
1836 CommandLineArg* MythCommandLineParser::add(const QString& arg, const QString& name,
1837  QMetaType::Type type,
1838  QVariant def, QString help, QString longhelp)
1839 {
1840  return add(QStringList(arg), name, type, std::move(def), std::move(help), std::move(longhelp));
1841 }
1842 
1843 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, bool def,
1844  QString help, QString longhelp)
1845 {
1846  return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(help), std::move(longhelp));
1847 }
1848 
1849 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, int def,
1850  QString help, QString longhelp)
1851 {
1852  return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(help), std::move(longhelp));
1853 }
1854 
1855 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, uint def,
1856  QString help, QString longhelp)
1857 {
1858  return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(help), std::move(longhelp));
1859 }
1860 
1861 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, long long def,
1862  QString help, QString longhelp)
1863 {
1864  return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(help), std::move(longhelp));
1865 }
1866 
1867 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, double def,
1868  QString help, QString longhelp)
1869 {
1870  return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(help), std::move(longhelp));
1871 }
1872 
1873 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, const char *def,
1874  QString help, QString longhelp)
1875 {
1876  return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(help), std::move(longhelp));
1877 }
1878 
1879 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, const QString& def,
1880  QString help, QString longhelp)
1881 {
1882  return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(help), std::move(longhelp));
1883 }
1884 
1885 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, QSize def,
1886  QString help, QString longhelp)
1887 {
1888  return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(help), std::move(longhelp));
1889 }
1890 
1891 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name, const QDateTime& def,
1892  QString help, QString longhelp)
1893 {
1894  return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(help), std::move(longhelp));
1895 }
1896 
1897 CommandLineArg* MythCommandLineParser::add(QStringList arglist, const QString& name,
1898  QMetaType::Type type,
1899  QString help, QString longhelp)
1900 {
1901  return add(std::move(arglist), name, type,
1902 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1903  QVariant(static_cast<QVariant::Type>(type)),
1904 #else
1905  QVariant(QMetaType(type)),
1906 #endif
1907  std::move(help), std::move(longhelp));
1908 }
1909 
1914 {
1915  if (m_verbose)
1916  std::cerr << "Reconciling links for option interdependencies." << std::endl;
1917 
1918  QMap<QString,CommandLineArg*>::iterator args_it;
1919  for (args_it = m_namedArgs.begin(); args_it != m_namedArgs.end(); ++args_it)
1920  {
1921  QList<CommandLineArg*> links = (*args_it)->m_parents;
1922  QList<CommandLineArg*>::iterator links_it;
1923  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1924  {
1925  if ((*links_it)->m_type != QMetaType::UnknownType)
1926  continue; // already handled
1927 
1928  if (!m_namedArgs.contains((*links_it)->m_name))
1929  {
1930  // not found
1931  std::cerr << "ERROR: could not reconcile linked argument." << std::endl
1932  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1933  << "' could not find '"
1934  << (*links_it)->m_name.toLocal8Bit().constData()
1935  << "'." << std::endl
1936  << " Please resolve dependency and recompile." << std::endl;
1937  return false;
1938  }
1939 
1940  // replace linked argument
1941  if (m_verbose)
1942  {
1943  std::cerr << QString(" Setting %1 as child of %2")
1944  .arg((*args_it)->m_name, (*links_it)->m_name)
1945  .toLocal8Bit().constData()
1946  << std::endl;
1947  }
1948  (*args_it)->SetChildOf(m_namedArgs[(*links_it)->m_name]);
1949  }
1950 
1951  links = (*args_it)->m_children;
1952  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1953  {
1954  if ((*links_it)->m_type != QMetaType::UnknownType)
1955  continue; // already handled
1956 
1957  if (!m_namedArgs.contains((*links_it)->m_name))
1958  {
1959  // not found
1960  std::cerr << "ERROR: could not reconcile linked argument." << std::endl
1961  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1962  << "' could not find '"
1963  << (*links_it)->m_name.toLocal8Bit().constData()
1964  << "'." << std::endl
1965  << " Please resolve dependency and recompile." << std::endl;
1966  return false;
1967  }
1968 
1969  // replace linked argument
1970  if (m_verbose)
1971  {
1972  std::cerr << QString(" Setting %1 as parent of %2")
1973  .arg((*args_it)->m_name, (*links_it)->m_name)
1974  .toLocal8Bit().constData()
1975  << std::endl;
1976  }
1977  (*args_it)->SetParentOf(m_namedArgs[(*links_it)->m_name]);
1978  }
1979 
1980  links = (*args_it)->m_requires;
1981  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1982  {
1983  if ((*links_it)->m_type != QMetaType::UnknownType)
1984  continue; // already handled
1985 
1986  if (!m_namedArgs.contains((*links_it)->m_name))
1987  {
1988  // not found
1989  std::cerr << "ERROR: could not reconcile linked argument." << std::endl
1990  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1991  << "' could not find '"
1992  << (*links_it)->m_name.toLocal8Bit().constData()
1993  << "'." << std::endl
1994  << " Please resolve dependency and recompile." << std::endl;
1995  return false;
1996  }
1997 
1998  // replace linked argument
1999  if (m_verbose)
2000  {
2001  std::cerr << QString(" Setting %1 as requiring %2")
2002  .arg((*args_it)->m_name, (*links_it)->m_name)
2003  .toLocal8Bit().constData()
2004  << std::endl;
2005  }
2006  (*args_it)->SetRequires(m_namedArgs[(*links_it)->m_name]);
2007  }
2008 
2009  QList<CommandLineArg*>::iterator req_it =
2010  (*args_it)->m_requiredby.begin();
2011  while (req_it != (*args_it)->m_requiredby.end())
2012  {
2013  if ((*req_it)->m_type == QMetaType::UnknownType)
2014  {
2015  // if its not an invalid, it shouldnt be here anyway
2016  if (m_namedArgs.contains((*req_it)->m_name))
2017  {
2018  m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2019  if (m_verbose)
2020  {
2021  std::cerr << QString(" Setting %1 as blocking %2")
2022  .arg((*args_it)->m_name,
2023  (*req_it)->m_name)
2024  .toLocal8Bit().constData()
2025  << std::endl;
2026  }
2027  }
2028  }
2029 
2030  (*req_it)->DecrRef();
2031  req_it = (*args_it)->m_requiredby.erase(req_it);
2032  }
2033 
2034  QList<CommandLineArg*>::iterator block_it =
2035  (*args_it)->m_blocks.begin();
2036  while (block_it != (*args_it)->m_blocks.end())
2037  {
2038  if ((*block_it)->m_type != QMetaType::UnknownType)
2039  {
2040  ++block_it;
2041  continue; // already handled
2042  }
2043 
2044  if (!m_namedArgs.contains((*block_it)->m_name))
2045  {
2046  (*block_it)->DecrRef();
2047  block_it = (*args_it)->m_blocks.erase(block_it);
2048  continue; // if it doesnt exist, it cant block this command
2049  }
2050 
2051  // replace linked argument
2052  if (m_verbose)
2053  {
2054  std::cerr << QString(" Setting %1 as blocking %2")
2055  .arg((*args_it)->m_name, (*block_it)->m_name)
2056  .toLocal8Bit().constData()
2057  << std::endl;
2058  }
2059  (*args_it)->SetBlocks(m_namedArgs[(*block_it)->m_name]);
2060  ++block_it;
2061  }
2062  }
2063 
2064  return true;
2065 }
2066 
2070 QVariant MythCommandLineParser::operator[](const QString &name)
2071 {
2072  QVariant var("");
2073  if (!m_namedArgs.contains(name))
2074  return var;
2075 
2076  CommandLineArg *arg = m_namedArgs[name];
2077 
2078  if (arg->m_given)
2079  var = arg->m_stored;
2080  else
2081  var = arg->m_default;
2082 
2083  return var;
2084 }
2085 
2089 QStringList MythCommandLineParser::GetArgs(void) const
2090 {
2091  return toStringList("_args");
2092 }
2093 
2097 QMap<QString,QString> MythCommandLineParser::GetExtra(void) const
2098 {
2099  return toMap("_extra");
2100 }
2101 
2105 {
2106  return toStringList("_passthrough").join(" ");
2107 }
2108 
2117 {
2118  QMap<QString,QString> smap = toMap("overridesettings");
2119 
2120  if (!m_overridesImported)
2121  {
2122  if (toBool("overridesettingsfile"))
2123  {
2124  QString filename = toString("overridesettingsfile");
2125  if (!filename.isEmpty())
2126  {
2127  QFile f(filename);
2128  if (f.open(QIODevice::ReadOnly))
2129  {
2130  QTextStream in(&f);
2131  while (!in.atEnd()) {
2132  QString line = in.readLine().trimmed();
2133 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2134  QStringList tokens = line.split("=",
2135  QString::SkipEmptyParts);
2136 #else
2137  QStringList tokens = line.split("=",
2138  Qt::SkipEmptyParts);
2139 #endif
2140  if (tokens.size() == 2)
2141  {
2142  static const QRegularExpression kQuoteStartRE { "^[\"']" };
2143  static const QRegularExpression kQuoteEndRE { "[\"']$" };
2144  tokens[0].remove(kQuoteStartRE);
2145  tokens[0].remove(kQuoteEndRE);
2146  tokens[1].remove(kQuoteStartRE);
2147  tokens[1].remove(kQuoteEndRE);
2148  if (!tokens[0].isEmpty())
2149  smap[tokens[0]] = tokens[1];
2150  }
2151  }
2152  }
2153  else
2154  {
2155  QByteArray tmp = filename.toLatin1();
2156  std::cerr << "Failed to open the override settings file: '"
2157  << tmp.constData() << "'" << std::endl;
2158  }
2159  }
2160  }
2161 
2162  if (toBool("windowed"))
2163  smap["RunFrontendInWindow"] = "1";
2164  else if (toBool("notwindowed"))
2165  smap["RunFrontendInWindow"] = "0";
2166 
2167  if (toBool("mousecursor"))
2168  smap["HideMouseCursor"] = "0";
2169  else if (toBool("nomousecursor"))
2170  smap["HideMouseCursor"] = "1";
2171 
2172  m_overridesImported = true;
2173 
2174  if (!smap.isEmpty())
2175  {
2176  QVariantMap vmap;
2177  for (auto it = smap.cbegin(); it != smap.cend(); ++it)
2178  vmap[it.key()] = QVariant(it.value());
2179 
2180  m_namedArgs["overridesettings"]->Set(QVariant(vmap));
2181  }
2182  }
2183 
2184  if (m_verbose)
2185  {
2186  std::cerr << "Option Overrides:" << std::endl;
2187  QMap<QString, QString>::const_iterator it;
2188  for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2189  std::cerr << QString(" %1 - %2").arg(it.key(), 30).arg(*it)
2190  .toLocal8Bit().constData() << std::endl;
2191  }
2192 
2193  return smap;
2194 }
2195 
2202 bool MythCommandLineParser::toBool(const QString& key) const
2203 {
2204  if (!m_namedArgs.contains(key))
2205  return false;
2206 
2207  CommandLineArg *arg = m_namedArgs[key];
2208  if (arg == nullptr)
2209  return false;
2210 
2211  if (arg->m_type == QMetaType::Bool)
2212  {
2213  if (arg->m_given)
2214  return arg->m_stored.toBool();
2215  return arg->m_default.toBool();
2216  }
2217 
2218  return arg->m_given;
2219 }
2220 
2224 int MythCommandLineParser::toInt(const QString& key) const
2225 {
2226  int val = 0;
2227  if (!m_namedArgs.contains(key))
2228  return val;
2229 
2230  CommandLineArg *arg = m_namedArgs[key];
2231  if (arg == nullptr)
2232  return val;
2233 
2234  if (arg->m_given)
2235  {
2236  if (arg->m_stored.canConvert<int>())
2237  val = arg->m_stored.toInt();
2238  }
2239  else
2240  {
2241  if (arg->m_default.canConvert<int>())
2242  val = arg->m_default.toInt();
2243  }
2244 
2245  return val;
2246 }
2247 
2251 uint MythCommandLineParser::toUInt(const QString& key) const
2252 {
2253  uint val = 0;
2254  if (!m_namedArgs.contains(key))
2255  return val;
2256 
2257  CommandLineArg *arg = m_namedArgs[key];
2258  if (arg == nullptr)
2259  return val;
2260 
2261  if (arg->m_given)
2262  {
2263  if (arg->m_stored.canConvert<uint>())
2264  val = arg->m_stored.toUInt();
2265  }
2266  else
2267  {
2268  if (arg->m_default.canConvert<uint>())
2269  val = arg->m_default.toUInt();
2270  }
2271 
2272  return val;
2273 }
2274 
2278 long long MythCommandLineParser::toLongLong(const QString& key) const
2279 {
2280  long long val = 0;
2281  if (!m_namedArgs.contains(key))
2282  return val;
2283 
2284  CommandLineArg *arg = m_namedArgs[key];
2285  if (arg == nullptr)
2286  return val;
2287 
2288  if (arg->m_given)
2289  {
2290  if (arg->m_stored.canConvert<long long>())
2291  val = arg->m_stored.toLongLong();
2292  }
2293  else
2294  {
2295  if (arg->m_default.canConvert<long long>())
2296  val = arg->m_default.toLongLong();
2297  }
2298 
2299  return val;
2300 }
2301 
2305 double MythCommandLineParser::toDouble(const QString& key) const
2306 {
2307  double val = 0.0;
2308  if (!m_namedArgs.contains(key))
2309  return val;
2310 
2311  CommandLineArg *arg = m_namedArgs[key];
2312  if (arg == nullptr)
2313  return val;
2314 
2315  if (arg->m_given)
2316  {
2317  if (arg->m_stored.canConvert<double>())
2318  val = arg->m_stored.toDouble();
2319  }
2320  else
2321  {
2322  if (arg->m_default.canConvert<double>())
2323  val = arg->m_default.toDouble();
2324  }
2325 
2326  return val;
2327 }
2328 
2332 QSize MythCommandLineParser::toSize(const QString& key) const
2333 {
2334  QSize val(0,0);
2335  if (!m_namedArgs.contains(key))
2336  return val;
2337 
2338  CommandLineArg *arg = m_namedArgs[key];
2339  if (arg == nullptr)
2340  return val;
2341 
2342  if (arg->m_given)
2343  {
2344  if (arg->m_stored.canConvert<QSize>())
2345  val = arg->m_stored.toSize();
2346  }
2347  else
2348  {
2349  if (arg->m_default.canConvert<QSize>())
2350  val = arg->m_default.toSize();
2351  }
2352 
2353  return val;
2354 }
2355 
2359 QString MythCommandLineParser::toString(const QString& key) const
2360 {
2361  QString val("");
2362  if (!m_namedArgs.contains(key))
2363  return val;
2364 
2365  CommandLineArg *arg = m_namedArgs[key];
2366  if (arg == nullptr)
2367  return val;
2368 
2369  if (arg->m_given)
2370  {
2371  if (!arg->m_converted)
2372  arg->Convert();
2373 
2374  if (arg->m_stored.canConvert<QString>())
2375  val = arg->m_stored.toString();
2376  }
2377  else
2378  {
2379  if (arg->m_default.canConvert<QString>())
2380  val = arg->m_default.toString();
2381  }
2382 
2383  return val;
2384 }
2385 
2390 QStringList MythCommandLineParser::toStringList(const QString& key, const QString& sep) const
2391 {
2392  QVariant varval;
2393  QStringList val;
2394  if (!m_namedArgs.contains(key))
2395  return val;
2396 
2397  CommandLineArg *arg = m_namedArgs[key];
2398  if (arg == nullptr)
2399  return val;
2400 
2401  if (arg->m_given)
2402  {
2403  if (!arg->m_converted)
2404  arg->Convert();
2405 
2406  varval = arg->m_stored;
2407  }
2408  else
2409  varval = arg->m_default;
2410 
2411  if (arg->m_type == QMetaType::QString && !sep.isEmpty())
2412  val = varval.toString().split(sep);
2413  else if (varval.canConvert<QStringList>())
2414  val = varval.toStringList();
2415 
2416  return val;
2417 }
2418 
2422 QMap<QString,QString> MythCommandLineParser::toMap(const QString& key) const
2423 {
2424  QMap<QString, QString> val;
2425  QMap<QString, QVariant> tmp;
2426  if (!m_namedArgs.contains(key))
2427  return val;
2428 
2429  CommandLineArg *arg = m_namedArgs[key];
2430  if (arg == nullptr)
2431  return val;
2432 
2433  if (arg->m_given)
2434  {
2435  if (!arg->m_converted)
2436  arg->Convert();
2437 
2438  if (arg->m_stored.canConvert<QMap<QString, QVariant>>())
2439  tmp = arg->m_stored.toMap();
2440  }
2441  else
2442  {
2443  if (arg->m_default.canConvert<QMap<QString, QVariant>>())
2444  tmp = arg->m_default.toMap();
2445  }
2446 
2447  for (auto i = tmp.cbegin(); i != tmp.cend(); ++i)
2448  val[i.key()] = i.value().toString();
2449 
2450  return val;
2451 }
2452 
2456 QDateTime MythCommandLineParser::toDateTime(const QString& key) const
2457 {
2458  QDateTime val;
2459  if (!m_namedArgs.contains(key))
2460  return val;
2461 
2462  CommandLineArg *arg = m_namedArgs[key];
2463  if (arg == nullptr)
2464  return val;
2465 
2466  if (arg->m_given)
2467  {
2468  if (arg->m_stored.canConvert<QDateTime>())
2469  val = arg->m_stored.toDateTime();
2470  }
2471  else
2472  {
2473  if (arg->m_default.canConvert<QDateTime>())
2474  val = arg->m_default.toDateTime();
2475  }
2476 
2477  return val;
2478 }
2479 
2484 {
2485  if (m_namedArgs.contains("_args"))
2486  {
2487  if (!allow)
2488  m_namedArgs.remove("_args");
2489  }
2490  else if (!allow)
2491  return;
2492 
2493  auto *arg = new CommandLineArg("_args", QMetaType::QStringList, QStringList());
2494  m_namedArgs["_args"] = arg;
2495 }
2496 
2501 {
2502  if (m_namedArgs.contains("_extra"))
2503  {
2504  if (!allow)
2505  m_namedArgs.remove("_extra");
2506  }
2507  else if (!allow)
2508  return;
2509 
2510  QMap<QString,QVariant> vmap;
2511  auto *arg = new CommandLineArg("_extra", QMetaType::QVariantMap, vmap);
2512 
2513  m_namedArgs["_extra"] = arg;
2514 }
2515 
2520 {
2521  if (m_namedArgs.contains("_passthrough"))
2522  {
2523  if (!allow)
2524  m_namedArgs.remove("_passthrough");
2525  }
2526  else if (!allow)
2527  return;
2528 
2529  auto *arg = new CommandLineArg("_passthrough",
2530  QMetaType::QStringList, QStringList());
2531  m_namedArgs["_passthrough"] = arg;
2532 }
2533 
2537 {
2538  add(QStringList{"-h", "--help", "--usage"},
2539  "showhelp", "", "Display this help printout, or give detailed "
2540  "information of selected option.",
2541  "Displays a list of all commands available for use with "
2542  "this application. If another option is provided as an "
2543  "argument, it will provide detailed information on that "
2544  "option.");
2545 }
2546 
2550 {
2551  add("--version", "showversion", false, "Display version information.",
2552  "Display informtion about build, including:\n"
2553  " version, branch, protocol, library API, Qt "
2554  "and compiled options.");
2555 }
2556 
2560 {
2561  add(QStringList{"-nw", "--no-windowed"},
2562  "notwindowed", false,
2563  "Prevent application from running in a window.", "")
2564  ->SetBlocks("windowed")
2565  ->SetGroup("User Interface");
2566 
2567  add(QStringList{"-w", "--windowed"}, "windowed",
2568  false, "Force application to run in a window.", "")
2569  ->SetGroup("User Interface");
2570 }
2571 
2575 {
2576  add("--mouse-cursor", "mousecursor", false,
2577  "Force visibility of the mouse cursor.", "")
2578  ->SetBlocks("nomousecursor")
2579  ->SetGroup("User Interface");
2580 
2581  add("--no-mouse-cursor", "nomousecursor", false,
2582  "Force the mouse cursor to be hidden.", "")
2583  ->SetGroup("User Interface");
2584 }
2585 
2589 {
2590  add(QStringList{"-d", "--daemon"}, "daemon", false,
2591  "Fork application into background after startup.",
2592  "Fork application into background, detatching from "
2593  "the local terminal.\nOften used with: "
2594  " --logpath --pidfile --user");
2595 }
2596 
2601 {
2602  add(QStringList{"-O", "--override-setting"},
2603  "overridesettings", QMetaType::QVariantMap,
2604  "Override a single setting defined by a key=value pair.",
2605  "Override a single setting from the database using "
2606  "options defined as one or more key=value pairs\n"
2607  "Multiple can be defined by multiple uses of the "
2608  "-O option.");
2609  add("--override-settings-file", "overridesettingsfile", "",
2610  "Define a file of key=value pairs to be "
2611  "loaded for setting overrides.", "");
2612 }
2613 
2617 {
2618  add("--chanid", "chanid", 0U,
2619  "Specify chanid of recording to operate on.", "")
2620  ->SetRequires("starttime");
2621 
2622  add("--starttime", "starttime", QDateTime(),
2623  "Specify start time of recording to operate on.", "")
2624  ->SetRequires("chanid");
2625 }
2626 
2630 {
2631  add(QStringList{"-geometry", "--geometry"}, "geometry",
2632  "", "Specify window size and position (WxH[+X+Y])", "")
2633  ->SetGroup("User Interface");
2634 }
2635 
2639 {
2640  add("--noupnp", "noupnp", false, "Disable use of UPnP.", "");
2641 }
2642 
2646 {
2647  add("--dvbv3", "dvbv3", false, "Use legacy DVBv3 API.", "");
2648 }
2649 
2654  const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2655 {
2656  defaultLogLevel =
2657  ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2658  LOG_INFO : defaultLogLevel;
2659 
2660  QString logLevelStr = logLevelGetName(defaultLogLevel);
2661 
2662  add(QStringList{"-v", "--verbose"}, "verbose",
2663  defaultVerbosity,
2664  "Specify log filtering. Use '-v help' for level info.", "")
2665  ->SetGroup("Logging");
2666  add("-V", "verboseint", 0LL, "",
2667  "This option is intended for internal use only.\n"
2668  "This option takes an unsigned value corresponding "
2669  "to the bitwise log verbosity operator.")
2670  ->SetGroup("Logging");
2671  add("--logpath", "logpath", "",
2672  "Writes logging messages to a file in the directory logpath with "
2673  "filenames in the format: applicationName.date.pid.log.\n"
2674  "This is typically used in combination with --daemon, and if used "
2675  "in combination with --pidfile, this can be used with log "
2676  "rotators, using the HUP call to inform MythTV to reload the "
2677  "file", "")
2678  ->SetGroup("Logging");
2679  add(QStringList{"-q", "--quiet"}, "quiet", 0,
2680  "Don't log to the console (-q). Don't log anywhere (-q -q)", "")
2681  ->SetGroup("Logging");
2682  add("--loglevel", "loglevel", logLevelStr,
2683  QString(
2684  "Set the logging level. All log messages at lower levels will be "
2685  "discarded.\n"
2686  "In descending order: emerg, alert, crit, err, warning, notice, "
2687  "info, debug\ndefaults to ") + logLevelStr, "")
2688  ->SetGroup("Logging");
2689  add("--syslog", "syslog", "none",
2690  "Set the syslog logging facility.\nSet to \"none\" to disable, "
2691  "defaults to none.", "")
2692  ->SetGroup("Logging");
2693 #if CONFIG_SYSTEMD_JOURNAL
2694  add("--systemd-journal", "systemd-journal", "false",
2695  "Use systemd-journal instead of syslog.", "")
2696  ->SetBlocks(QStringList()
2697  << "syslog"
2698  )
2699  ->SetGroup("Logging");
2700 #endif
2701  add("--nodblog", "nodblog", false, "", "")
2702  ->SetGroup("Logging")
2703  ->SetRemoved("Database logging has been removed.", "34");
2704  add("--enable-dblog", "enabledblog", false, "", "")
2705  ->SetGroup("Logging")
2706  ->SetRemoved("Database logging has been removed.", "34");
2707 
2708  add(QStringList{"-l", "--logfile"},
2709  "logfile", "", "", "")
2710  ->SetGroup("Logging")
2711  ->SetRemoved("This option has been removed as part of "
2712  "rewrite of the logging interface. Please update your init "
2713  "scripts to use --syslog to interface with your system's "
2714  "existing system logging daemon, or --logpath to specify a "
2715  "dirctory for MythTV to write its logs to.", "0.25");
2716 }
2717 
2721 {
2722  add(QStringList{"-p", "--pidfile"}, "pidfile", "",
2723  "Write PID of application to filename.",
2724  "Write the PID of the currently running process as a single "
2725  "line to this file. Used for init scripts to know what "
2726  "process to terminate, and with log rotators "
2727  "to send a HUP signal to process to have it re-open files.");
2728 }
2729 
2733 {
2734  add(QStringList{"-j", "--jobid"}, "jobid", 0, "",
2735  "Intended for internal use only, specify the JobID to match "
2736  "up with in the database for additional information and the "
2737  "ability to update runtime status in the database.");
2738 }
2739 
2743 {
2744  add("--infile", "infile", "", "Input file URI", "");
2745  if (addOutFile)
2746  add("--outfile", "outfile", "", "Output file URI", "");
2747 }
2748 
2752 {
2753 #ifdef USING_X11
2754  add(QStringList{"-display", "--display"}, "display", "",
2755  "Qt (QPA) X11 connection name when using xcb (X11) platform plugin", "")
2756  ->SetGroup("Qt");
2757 #endif
2758 }
2759 
2763 {
2764  add(QStringList{"-platform", "--platform"}, "platform", "", "Qt (QPA) platform argument",
2765  "Qt platform argument that is passed through to Qt")
2766  ->SetGroup("Qt");
2767 }
2768 
2772 {
2773  QString logfile = toString("logpath");
2774  pid_t pid = getpid();
2775 
2776  if (logfile.isEmpty())
2777  return logfile;
2778 
2779  QFileInfo finfo(logfile);
2780  if (!finfo.isDir())
2781  {
2782  LOG(VB_GENERAL, LOG_ERR,
2783  QString("%1 is not a directory, disabling logfiles")
2784  .arg(logfile));
2785  return {};
2786  }
2787 
2788  QString logdir = finfo.filePath();
2789  logfile = QCoreApplication::applicationName() + "." +
2791  QString(".%1").arg(pid) + ".log";
2792 
2793  SetValue("logdir", logdir);
2794  SetValue("logfile", logfile);
2795  SetValue("filepath", QFileInfo(QDir(logdir), logfile).filePath());
2796 
2797  return toString("filepath");
2798 }
2799 
2803 {
2804  QString setting = toString("syslog").toLower();
2805  if (setting == "none")
2806  return -2;
2807 
2808  return syslogGetFacility(setting);
2809 }
2810 
2814 {
2815  QString setting = toString("loglevel");
2816  if (setting.isEmpty())
2817  return LOG_INFO;
2818 
2819  LogLevel_t level = logLevelGet(setting);
2820  if (level == LOG_UNKNOWN)
2821  std::cerr << "Unknown log level: " << setting.toLocal8Bit().constData()
2822  << std::endl;
2823 
2824  return level;
2825 }
2826 
2831 bool MythCommandLineParser::SetValue(const QString &key, const QVariant& value)
2832 {
2833  CommandLineArg *arg = nullptr;
2834 
2835  if (!m_namedArgs.contains(key))
2836  {
2837  const QVariant& val(value);
2838 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2839  auto type = static_cast<QMetaType::Type>(val.type());
2840 #else
2841  auto type = static_cast<QMetaType::Type>(val.typeId());
2842 #endif
2843  arg = new CommandLineArg(key, type, val);
2844  m_namedArgs.insert(key, arg);
2845  }
2846  else
2847  {
2848  arg = m_namedArgs[key];
2849 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2850  auto type = static_cast<QMetaType::Type>(value.type());
2851 #else
2852  auto type = value.typeId();
2853 #endif
2854  if (arg->m_type != type)
2855  return false;
2856  }
2857 
2858  arg->Set(value);
2859  return true;
2860 }
2861 
2865 {
2866  int err = 0;
2867 
2868  // Setup the defaults
2869  verboseString = "";
2870  verboseMask = 0;
2871  verboseArgParse(mask);
2872 
2873  if (toBool("verbose"))
2874  {
2875  if ((err = verboseArgParse(toString("verbose"))) != 0)
2876  return err;
2877  }
2878  else if (toBool("verboseint"))
2879  verboseMask = static_cast<uint64_t>(toLongLong("verboseint"));
2880 
2881  verboseMask |= VB_STDIO|VB_FLUSH;
2882 
2883  int quiet = toInt("quiet");
2884  if (std::max(quiet, static_cast<int>(progress)) > 1)
2885  {
2886  verboseMask = VB_NONE|VB_FLUSH;
2887  verboseArgParse("none");
2888  }
2889 
2890  int facility = GetSyslogFacility();
2891 #if CONFIG_SYSTEMD_JOURNAL
2892  bool journal = toBool("systemd-journal");
2893  if (journal)
2894  {
2895  if (facility >= 0)
2897  facility = SYSTEMD_JOURNAL_FACILITY;
2898  }
2899 #endif
2900  LogLevel_t level = GetLogLevel();
2901  if (level == LOG_UNKNOWN)
2903 
2904  LOG(VB_GENERAL, LOG_CRIT,
2905  QString("%1 version: %2 [%3] www.mythtv.org")
2906  .arg(QCoreApplication::applicationName(),
2908  LOG(VB_GENERAL, LOG_CRIT, QString("Qt version: compile: %1, runtime: %2")
2909  .arg(QT_VERSION_STR, qVersion()));
2910  LOG(VB_GENERAL, LOG_INFO, QString("%1 (%2)")
2911  .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2912  LOG(VB_GENERAL, LOG_NOTICE,
2913  QString("Enabled verbose msgs: %1").arg(verboseString));
2914 
2915  QString logfile = GetLogFilePath();
2916  bool propagate = !logfile.isEmpty();
2917 
2918  if (toBool("daemon"))
2919  quiet = std::max(quiet, 1);
2920 
2921  logStart(logfile, progress, quiet, facility, level, propagate);
2922  qInstallMessageHandler([](QtMsgType /*unused*/, const QMessageLogContext& /*unused*/, const QString &Msg)
2923  { LOG(VB_GENERAL, LOG_INFO, "Qt: " + Msg); });
2924 
2925  return GENERIC_EXIT_OK;
2926 }
2927 
2933 {
2934  if (m_verbose)
2935  std::cerr << "Applying settings override" << std::endl;
2936 
2937  QMap<QString, QString> override = GetSettingsOverride();
2938  if (!override.empty())
2939  {
2940  QMap<QString, QString>::iterator it;
2941  for (it = override.begin(); it != override.end(); ++it)
2942  {
2943  LOG(VB_GENERAL, LOG_NOTICE,
2944  QString("Setting '%1' being forced to '%2'")
2945  .arg(it.key(), *it));
2946  gCoreContext->OverrideSettingForSession(it.key(), *it);
2947  }
2948  }
2949 }
2950 
2951 static bool openPidfile(std::ofstream &pidfs, const QString &pidfile)
2952 {
2953  if (!pidfile.isEmpty())
2954  {
2955  pidfs.open(pidfile.toLatin1().constData());
2956  if (!pidfs)
2957  {
2958  std::cerr << "Could not open pid file: " << ENO_STR << std::endl;
2959  return false;
2960  }
2961  }
2962  return true;
2963 }
2964 
2967 static bool setUser(const QString &username)
2968 {
2969  if (username.isEmpty())
2970  return true;
2971 
2972 #ifdef _WIN32
2973  std::cerr << "--user option is not supported on Windows" << std::endl;
2974  return false;
2975 #else // ! _WIN32
2976 #if defined(__linux__) || defined(__LINUX__)
2977  // Check the current dumpability of core dumps, which will be disabled
2978  // by setuid, so we can re-enable, if appropriate
2979  int dumpability = prctl(PR_GET_DUMPABLE);
2980 #endif
2981  struct passwd *user_info = getpwnam(username.toLocal8Bit().constData());
2982  const uid_t user_id = geteuid();
2983 
2984  if (user_id && (!user_info || user_id != user_info->pw_uid))
2985  {
2986  std::cerr << "You must be running as root to use the --user switch." << std::endl;
2987  return false;
2988  }
2989  if (user_info && user_id == user_info->pw_uid)
2990  {
2991  LOG(VB_GENERAL, LOG_WARNING,
2992  QString("Already running as '%1'").arg(username));
2993  }
2994  else if (!user_id && user_info)
2995  {
2996  if (setenv("HOME", user_info->pw_dir,1) == -1)
2997  {
2998  std::cerr << "Error setting home directory." << std::endl;
2999  return false;
3000  }
3001  if (setgid(user_info->pw_gid) == -1)
3002  {
3003  std::cerr << "Error setting effective group." << std::endl;
3004  return false;
3005  }
3006  if (initgroups(user_info->pw_name, user_info->pw_gid) == -1)
3007  {
3008  std::cerr << "Error setting groups." << std::endl;
3009  return false;
3010  }
3011  if (setuid(user_info->pw_uid) == -1)
3012  {
3013  std::cerr << "Error setting effective user." << std::endl;
3014  return false;
3015  }
3016 #if defined(__linux__) || defined(__LINUX__)
3017  if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3018  {
3019  LOG(VB_GENERAL, LOG_WARNING, "Unable to re-enable core file "
3020  "creation. Run without the --user argument to use "
3021  "shell-specified limits.");
3022  }
3023 #endif
3024  }
3025  else
3026  {
3027  std::cerr << QString("Invalid user '%1' specified with --user")
3028  .arg(username).toLocal8Bit().constData() << std::endl;
3029  return false;
3030  }
3031  return true;
3032 #endif // ! _WIN32
3033 }
3034 
3035 
3039 {
3040  std::ofstream pidfs;
3041  if (!openPidfile(pidfs, toString("pidfile")))
3043 
3044  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
3045  LOG(VB_GENERAL, LOG_WARNING, "Unable to ignore SIGPIPE");
3046 
3047 #ifdef Q_OS_DARWIN
3048  if (toBool("daemon"))
3049  {
3050  std::cerr << "Daemonizing is unavailable in OSX" << std::endl;
3051  LOG(VB_GENERAL, LOG_WARNING, "Unable to daemonize");
3052  }
3053 #else
3054  if (toBool("daemon") && (daemon(0, 1) < 0))
3055  {
3056  std::cerr << "Failed to daemonize: " << ENO_STR << std::endl;
3058  }
3059 #endif
3060 
3061  QString username = toString("username");
3062  if (!username.isEmpty() && !setUser(username))
3064 
3065  if (pidfs)
3066  {
3067  pidfs << getpid() << std::endl;
3068  pidfs.close();
3069  }
3070 
3071  return GENERIC_EXIT_OK;
3072 }
pidfile
QString pidfile
Definition: mythjobqueue.cpp:44
MythCommandLineParser::addDisplay
void addDisplay(void)
Canned argument definition for -display.
Definition: mythcommandlineparser.cpp:2751
MythCommandLineParser::addGeometry
void addGeometry(void)
Canned argument definition for –geometry.
Definition: mythcommandlineparser.cpp:2629
setuid
#define setuid(x)
Definition: compat.h:185
build_compdb.args
args
Definition: build_compdb.py:11
logStart
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool propagate, bool testHarness)
Entry point to start logging for the application.
Definition: logging.cpp:637
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MythCommandLineParser::Result
Result
Definition: mythcommandlineparser.h:121
CommandLineArg::SetChild
CommandLineArg * SetChild(const QString &opt)
Set argument as parent of given child.
Definition: mythcommandlineparser.cpp:716
CommandLineArg::SetParent
CommandLineArg * SetParent(const QString &opt)
Set argument as child of given parent.
Definition: mythcommandlineparser.cpp:682
MythCommandLineParser::m_appname
QString m_appname
Definition: mythcommandlineparser.h:271
MythCommandLineParser::operator[]
QVariant operator[](const QString &name)
Returned stored QVariant for given argument, or default value if not used.
Definition: mythcommandlineparser.cpp:2070
openPidfile
static bool openPidfile(std::ofstream &pidfs, const QString &pidfile)
Definition: mythcommandlineparser.cpp:2951
MythCommandLineParser::allowPassthrough
void allowPassthrough(bool allow=true)
Specify that parser should allow a bare '–', and collect all subsequent text as a QString.
Definition: mythcommandlineparser.cpp:2519
CommandLineArg::AllowOneOf
static void AllowOneOf(const QList< CommandLineArg * > &args)
Mark a list of arguments as mutually exclusive.
Definition: mythcommandlineparser.cpp:943
MythCommandLineParser::toMap
QMap< QString, QString > toMap(const QString &key) const
Returns stored QVariant as a QMap, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2422
MythCommandLineParser::Result::kOptVal
@ kOptVal
CommandLineArg::CommandLineArg
CommandLineArg(const QString &name, QMetaType::Type type, QVariant def, QString help, QString longhelp)
Default constructor for CommandLineArg class.
Definition: mythcommandlineparser.cpp:286
CommandLineArg::GetKeywordLength
int GetKeywordLength(void) const
Return length of full keyword string for use in determining indent of help text.
Definition: mythcommandlineparser.cpp:338
MythCommandLineParser::m_verbose
bool m_verbose
Definition: mythcommandlineparser.h:276
progress
bool progress
Definition: mythcommflag.cpp:69
k_defaultWidth
static constexpr int k_defaultWidth
Definition: mythcommandlineparser.cpp:82
CommandLineArg::m_keywords
QStringList m_keywords
Definition: mythcommandlineparser.h:103
MythCommandLineParser::Result::kEmpty
@ kEmpty
CommandLineArg::GetHelpString
QString GetHelpString(int off, const QString &group="", bool force=false) const
Return string containing help text with desired offset.
Definition: mythcommandlineparser.cpp:364
MythCommandLineParser::addPlatform
void addPlatform(void)
Pass through the platform argument to Qt for GUI applications.
Definition: mythcommandlineparser.cpp:2762
MythCommandLineParser::~MythCommandLineParser
virtual ~MythCommandLineParser()
Definition: mythcommandlineparser.cpp:1289
MythCommandLineParser::Result::kPassthrough
@ kPassthrough
MythCoreContext::OverrideSettingForSession
void OverrideSettingForSession(const QString &key, const QString &value)
Definition: mythcorecontext.cpp:1336
GetTermWidth
static int GetTermWidth(void)
returns terminal width, or 79 on error
Definition: mythcommandlineparser.cpp:87
MythCommandLineParser::toDouble
double toDouble(const QString &key) const
Returns stored QVariant as double floating point value, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2305
CommandLineArg::m_removedversion
QString m_removedversion
Definition: mythcommandlineparser.h:98
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythversion.cpp:5
MythCommandLineParser::addPIDFile
void addPIDFile(void)
Canned argument definition for –pidfile.
Definition: mythcommandlineparser.cpp:2720
CommandLineArg::PrintVerbose
void PrintVerbose(void) const
Internal use.
Definition: mythcommandlineparser.cpp:1148
setenv
#define setenv(x, y, z)
Definition: compat.h:89
MythCommandLineParser::addVersion
void addVersion(void)
Canned argument definition for –version.
Definition: mythcommandlineparser.cpp:2549
CommandLineArg::m_removed
QString m_removed
Definition: mythcommandlineparser.h:97
quiet
int quiet
Definition: mythcommflag.cpp:68
CommandLineArg::SetRequires
CommandLineArg * SetRequires(const QString &opt)
Set argument as requiring given option.
Definition: mythcommandlineparser.cpp:775
MythCommandLineParser::ReconcileLinks
bool ReconcileLinks(void)
Replace dummy arguments used to define interdependency with pointers to their real counterparts.
Definition: mythcommandlineparser.cpp:1913
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
wrapList
static void wrapList(QStringList &list, int width)
Definition: mythcommandlineparser.cpp:108
CommandLineArg::m_default
QVariant m_default
Definition: mythcommandlineparser.h:100
MythCommandLineParser::m_overridesImported
bool m_overridesImported
Definition: mythcommandlineparser.h:275
logfile
QString logfile
Definition: mythjobqueue.cpp:45
MythCommandLineParser::addWindowed
void addWindowed(void)
Canned argument definition for –windowed and -no-windowed.
Definition: mythcommandlineparser.cpp:2559
force
bool force
Definition: mythcommflag.cpp:70
CommandLineArg::SetRequiredChild
CommandLineArg * SetRequiredChild(const QString &opt)
Set argument as parent of given child and mark as required.
Definition: mythcommandlineparser.cpp:733
MythCommandLineParser::m_optionedArgs
QMap< QString, CommandLineArg * > m_optionedArgs
Definition: mythcommandlineparser.h:272
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:11
MythCommandLineParser::m_namedArgs
QMap< QString, CommandLineArg * > m_namedArgs
Definition: mythcommandlineparser.h:273
MythCommandLineParser::GetHelpString
QString GetHelpString(void) const
Generate command line option help text.
Definition: mythcommandlineparser.cpp:1409
CommandLineArg::m_parents
QList< CommandLineArg * > m_parents
Definition: mythcommandlineparser.h:106
MythCommandLineParser::addRecording
void addRecording(void)
Canned argument definition for –chanid and –starttime.
Definition: mythcommandlineparser.cpp:2616
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
MythCommandLineParser::Result::kArg
@ kArg
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
MythCommandLineParser::addLogging
void addLogging(const QString &defaultVerbosity="general", LogLevel_t defaultLogLevel=LOG_INFO)
Canned argument definition for all logging options, including –verbose, –logpath, –quiet,...
Definition: mythcommandlineparser.cpp:2653
CommandLineArg::GetLongHelpString
QString GetLongHelpString(QString keyword) const
Return string containing extended help text.
Definition: mythcommandlineparser.cpp:439
CommandLineArg::SetRemoved
CommandLineArg * SetRemoved(QString remstr="", QString remver="")
Set option as removed.
Definition: mythcommandlineparser.cpp:819
CommandLineArg::m_stored
QVariant m_stored
Definition: mythcommandlineparser.h:101
CommandLineArg::SetParentOf
CommandLineArg * SetParentOf(const QString &opt)
Set argument as parent of given child.
Definition: mythcommandlineparser.cpp:665
CommandLineArg::m_blocks
QList< CommandLineArg * > m_blocks
Definition: mythcommandlineparser.h:110
verboseString
QString verboseString
Definition: logging.cpp:98
CommandLineArg::SetChildOf
CommandLineArg * SetChildOf(const QString &opt)
Set argument as child of given parent.
Definition: mythcommandlineparser.cpp:699
MythCommandLineParser::Parse
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
Definition: mythcommandlineparser.cpp:1554
MythCommandLineParser::add
CommandLineArg * add(const QString &arg, const QString &name, bool def, QString help, QString longhelp)
Definition: mythcommandlineparser.cpp:1770
mythdate.h
CommandLineArg::m_given
bool m_given
Definition: mythcommandlineparser.h:92
MythCommandLineParser::addMouse
void addMouse(void)
Canned argument definition for –mouse-cursor and –no-mouse-cursor.
Definition: mythcommandlineparser.cpp:2574
mythlogging.h
logLevelGetName
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:768
CommandLineArg::m_deprecated
QString m_deprecated
Definition: mythcommandlineparser.h:96
MythDate::kFilename
@ kFilename
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:18
MythCommandLineParser::getOpt
Result getOpt(int argc, const char *const *argv, int &argpos, QString &opt, QByteArray &val)
Internal use.
Definition: mythcommandlineparser.cpp:1473
MythCommandLineParser::Result::kInvalid
@ kInvalid
verboseMask
uint64_t verboseMask
Definition: logging.cpp:97
daemon
#define daemon(x, y)
Definition: compat.h:190
CommandLineArg::m_longhelp
QString m_longhelp
Definition: mythcommandlineparser.h:113
CommandLineArg::m_help
QString m_help
Definition: mythcommandlineparser.h:112
MythCommandLineParser::MythCommandLineParser
MythCommandLineParser(QString appname)
Default constructor for MythCommandLineArg class.
Definition: mythcommandlineparser.cpp:1277
logLevelGet
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:746
ENO_STR
#define ENO_STR
Definition: mythlogging.h:74
CommandLineArg::SetRequiredChildOf
CommandLineArg * SetRequiredChildOf(const QString &opt)
Set argument as child required by given parent.
Definition: mythcommandlineparser.cpp:754
CommandLineArg::Set
bool Set(const QString &opt)
Set option as provided on command line with no value.
Definition: mythcommandlineparser.cpp:549
MythCommandLineParser::GetArgs
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
Definition: mythcommandlineparser.cpp:2089
MythCommandLineParser::m_passthroughActive
bool m_passthroughActive
Definition: mythcommandlineparser.h:274
SIGPIPE
#define SIGPIPE
Definition: compat.h:139
MythCommandLineParser::PrintVersion
static void PrintVersion(void)
Print application version information.
Definition: mythcommandlineparser.cpp:1382
CommandLineArg::GetName
QString GetName(void) const
Definition: mythcommandlineparser.h:34
MythCommandLineParser::GetExtra
QMap< QString, QString > GetExtra(void) const
Return map of additional key/value pairs provided on the command line independent of any registered a...
Definition: mythcommandlineparser.cpp:2097
CommandLineArg::PrintDeprecatedWarning
void PrintDeprecatedWarning(QString &keyword) const
Internal use.
Definition: mythcommandlineparser.cpp:1254
MythCommandLineParser::toUInt
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2251
CommandLineArg::m_requires
QList< CommandLineArg * > m_requires
Definition: mythcommandlineparser.h:108
MythCommandLineParser::PrintHelp
void PrintHelp(void) const
Print command line option help.
Definition: mythcommandlineparser.cpp:1398
MythCommandLineParser::Daemonize
int Daemonize(void) const
Fork application into background, and detatch from terminal.
Definition: mythcommandlineparser.cpp:3038
MythCommandLineParser::MythSplitCommandString
static QStringList MythSplitCommandString(const QString &line)
Parse a string into separate tokens.
Definition: mythcommandlineparser.cpp:158
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MythCommandLineParser::GetSyslogFacility
int GetSyslogFacility(void) const
Helper utility for logging interface to return syslog facility.
Definition: mythcommandlineparser.cpp:2802
MythCommandLineParser::ApplySettingsOverride
void ApplySettingsOverride(void)
Apply all overrides to the global context.
Definition: mythcommandlineparser.cpp:2932
GENERIC_EXIT_PERMISSIONS_ERROR
@ GENERIC_EXIT_PERMISSIONS_ERROR
File permissions error.
Definition: exitcodes.h:20
QT_ENDL
#define QT_ENDL
Definition: mythcommandlineparser.cpp:68
GENERIC_EXIT_DAEMONIZING_ERROR
@ GENERIC_EXIT_DAEMONIZING_ERROR
Error daemonizing or execl.
Definition: exitcodes.h:29
MythCommandLineParser::GetSettingsOverride
QMap< QString, QString > GetSettingsOverride(void)
Return map of key/value pairs provided to override database options.
Definition: mythcommandlineparser.cpp:2116
CommandLineArg::GetPreferredKeyword
QString GetPreferredKeyword(void) const
Return the longest keyword for the argument.
Definition: mythcommandlineparser.cpp:1033
CommandLineArg::TestLinks
bool TestLinks(void) const
Test all related arguments to make sure specified requirements are fulfilled.
Definition: mythcommandlineparser.cpp:1055
CommandLineArg::SetBlocks
CommandLineArg * SetBlocks(const QString &opt)
Set argument as incompatible with given option.
Definition: mythcommandlineparser.cpp:792
GetMythSourcePath
const char * GetMythSourcePath()
Definition: mythversion.cpp:10
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
nv_python_libs.vimeo.vimeo_api.user_info
def user_info(user, format="xml")
Definition: vimeo_api.py:517
strip_quotes
static QByteArray strip_quotes(const QByteArray &array)
Definition: mythcommandlineparser.cpp:101
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:894
CommandLineArg::m_type
QMetaType::Type m_type
Definition: mythcommandlineparser.h:99
CommandLineArg::CleanupLinks
void CleanupLinks(void)
Clear out references to other arguments in preparation for deletion.
Definition: mythcommandlineparser.cpp:1127
CommandLineArg::m_usedKeyword
QString m_usedKeyword
Definition: mythcommandlineparser.h:104
CommandLineArg::PrintRemovedWarning
void PrintRemovedWarning(QString &keyword) const
Internal use.
Definition: mythcommandlineparser.cpp:1238
MythCommandLineParser::allowArgs
void allowArgs(bool allow=true)
Specify that parser should allow and collect values provided independent of any keyword.
Definition: mythcommandlineparser.cpp:2483
CommandLineArg::m_requiredby
QList< CommandLineArg * > m_requiredby
Definition: mythcommandlineparser.h:109
START
static constexpr uint8_t START
Definition: freesat_huffman.cpp:3
mythmiscutil.h
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2359
syslogGetFacility
int syslogGetFacility([[maybe_unused]] const QString &facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:721
CommandLineArg::m_group
QString m_group
Definition: mythcommandlineparser.h:95
CommandLineArg::m_name
QString m_name
Definition: mythcommandlineparser.h:94
mythcorecontext.h
MythCommandLineParser::addHelp
void addHelp(void)
Canned argument definition for –help.
Definition: mythcommandlineparser.cpp:2536
MythCommandLineParser::SetValue
bool SetValue(const QString &key, const QVariant &value)
Set a new stored value for an existing argument definition, or spawn a new definition store value in.
Definition: mythcommandlineparser.cpp:2831
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2202
MythCommandLineParser::GetLogLevel
LogLevel_t GetLogLevel(void) const
Helper utility for logging interface to filtering level.
Definition: mythcommandlineparser.cpp:2813
CommandLineArg
Definition for a single command line option.
Definition: mythcommandlineparser.h:21
MythCommandLineParser::toLongLong
long long toLongLong(const QString &key) const
Returns stored QVariant as a long integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2278
std
Definition: mythchrono.h:23
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
CommandLineArg::AddKeyword
void AddKeyword(const QString &keyword)
Definition: mythcommandlineparser.h:32
MythCommandLineParser::toStringList
QStringList toStringList(const QString &key, const QString &sep="") const
Returns stored QVariant as a QStringList, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2390
MythCommandLineParser::NamedOptType
static const char * NamedOptType(Result type)
Definition: mythcommandlineparser.cpp:221
logging.h
setUser
static bool setUser(const QString &username)
Drop permissions to the specified user.
Definition: mythcommandlineparser.cpp:2967
CommandLineArg::SetGroup
CommandLineArg * SetGroup(const QString &group)
Definition: mythcommandlineparser.h:30
MythCommandLineParser::Result::kOptOnly
@ kOptOnly
build_compdb.help
help
Definition: build_compdb.py:10
MythCommandLineParser::addJob
void addJob(void)
Canned argument definition for –jobid.
Definition: mythcommandlineparser.cpp:2732
MythCommandLineParser::toSize
QSize toSize(const QString &key) const
Returns stored QVariant as a QSize value, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2332
MythCommandLineParser::GetLogFilePath
QString GetLogFilePath(void)
Helper utility for logging interface to pull path from –logpath.
Definition: mythcommandlineparser.cpp:2771
CommandLineArg::m_converted
bool m_converted
Definition: mythcommandlineparser.h:93
MythCommandLineParser::ConfigureLogging
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
Definition: mythcommandlineparser.cpp:2864
MythCommandLineParser::addSettingsOverride
void addSettingsOverride(void)
Canned argument definition for –override-setting and –override-settings-file.
Definition: mythcommandlineparser.cpp:2600
CommandLineArg::SetDeprecated
CommandLineArg * SetDeprecated(QString depstr="")
Set option as deprecated.
Definition: mythcommandlineparser.cpp:809
MythCommandLineParser::GetHelpHeader
virtual QString GetHelpHeader(void) const
Definition: mythcommandlineparser.h:141
MythCommandLineParser::LoadArguments
virtual void LoadArguments(void)
Definition: mythcommandlineparser.h:137
MythCommandLineParser::allowExtras
void allowExtras(bool allow=true)
Specify that parser should allow and collect additional key/value pairs not explicitly defined for pr...
Definition: mythcommandlineparser.cpp:2500
MythCommandLineParser::addUPnP
void addUPnP(void)
Canned argument definition for –noupnp.
Definition: mythcommandlineparser.cpp:2638
MythCommandLineParser::addDaemon
void addDaemon(void)
Canned argument definition for –daemon.
Definition: mythcommandlineparser.cpp:2588
geteuid
#define geteuid()
Definition: compat.h:184
exitcodes.h
MythCommandLineParser::toInt
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2224
CommandLineArg::m_children
QList< CommandLineArg * > m_children
Definition: mythcommandlineparser.h:107
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
MythCommandLineParser::addDVBv3
void addDVBv3(void)
Canned argument definition for –dvbv3.
Definition: mythcommandlineparser.cpp:2645
build_compdb.filename
filename
Definition: build_compdb.py:21
GENERIC_EXIT_INVALID_CMDLINE
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:16
mythcommandlineparser.h
MythCommandLineParser::GetPassthrough
QString GetPassthrough(void) const
Return any text supplied on the command line after a bare '–'.
Definition: mythcommandlineparser.cpp:2104
MythCommandLineParser::Result::kEnd
@ kEnd
MythCommandLineParser::Result::kCombOptVal
@ kCombOptVal
MythCommandLineParser::toDateTime
QDateTime toDateTime(const QString &key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2456
MythCommandLineParser::addInFile
void addInFile(bool addOutFile=false)
Canned argument definition for –infile and –outfile.
Definition: mythcommandlineparser.cpp:2742
CommandLineArg::Convert
void Convert(void)
Convert stored string value from QByteArray to QString.
Definition: mythcommandlineparser.cpp:971
ReferenceCounter
General purpose reference counter.
Definition: referencecounter.h:26
CommandLineArg::GetKeywordString
QString GetKeywordString(void) const
Return string containing all possible keyword triggers for this argument.
Definition: mythcommandlineparser.cpp:328