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