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