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