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
47 #endif
48 
49 // Qt headers
50 #include <QtGlobal>
51 #include <QCoreApplication>
52 #include <QDateTime>
53 #include <QDir>
54 #include <QFile>
55 #include <QFileInfo>
56 #include <QRegularExpression>
57 #include <QSize>
58 #include <QString>
59 #include <QTextStream>
60 #include <QVariant>
61 #include <QVariantList>
62 #include <QVariantMap>
63 #include <utility>
64 
65 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
66  #define QT_ENDL endl
67 #else
68  #define QT_ENDL Qt::endl
69 #endif
70 
71 #include "mythcommandlineparser.h"
72 #include "mythcorecontext.h"
73 #include "exitcodes.h"
74 #include "mythconfig.h"
75 #include "mythlogging.h"
76 #include "mythversion.h"
77 #include "logging.h"
78 #include "mythmiscutil.h"
79 #include "mythdate.h"
80 
81 #define TERMWIDTH 79
82 
83 bool openPidfile(std::ofstream &pidfs, const QString &pidfile);
84 bool setUser(const QString &username);
85 int GetTermWidth(void);
86 QByteArray strip_quotes (QByteArray val);
87 
91 int GetTermWidth(void)
92 {
93 #if defined(_WIN32) || defined(Q_OS_ANDROID)
94  return TERMWIDTH;
95 #else
96  struct winsize ws {};
97 
98  if (ioctl(0, TIOCGWINSZ, &ws) != 0)
99  return TERMWIDTH;
100 
101  return (int)ws.ws_col;
102 #endif
103 }
104 
105 QByteArray strip_quotes (QByteArray val)
106 {
107  if (val.startsWith('"') && val.endsWith('"'))
108  return val.mid(1,val.size()-2);
109  if (val.startsWith('\'') && val.endsWith('\''))
110  return val.mid(1,val.size()-2);
111  return val;
112 }
113 
118 {
119  switch (type)
120  {
121  case Result::kEnd:
122  return "kEnd";
123 
124  case Result::kEmpty:
125  return "kEmpty";
126 
127  case Result::kOptOnly:
128  return "kOptOnly";
129 
130  case Result::kOptVal:
131  return "kOptVal";
132 
133  case Result::kCombOptVal:
134  return "kCombOptVal";
135 
136  case Result::kArg:
137  return "kArg";
138 
140  return "kPassthrough";
141 
142  case Result::kInvalid:
143  return "kInvalid";
144 
145  default:
146  return "kUnknown";
147  }
148 }
149 
184 CommandLineArg::CommandLineArg(const QString& name, QVariant::Type type,
185  QVariant def, QString help, QString longhelp) :
186  ReferenceCounter(QString("CommandLineArg:%1").arg(name)),
187  m_name(name), m_type(type), m_default(std::move(def)),
188  m_help(std::move(help)), m_longhelp(std::move(longhelp))
189 {
190  if ((m_type != QVariant::String) && (m_type != QVariant::StringList) &&
191  (m_type != QVariant::Map))
192  m_converted = true;
193 }
194 
201 CommandLineArg::CommandLineArg(const QString& name, QVariant::Type type, QVariant def)
202  : ReferenceCounter(QString("CommandLineArg:%1").arg(name)),
203  m_name(name), m_type(type), m_default(std::move(def))
204 {
205  if ((m_type != QVariant::String) && (m_type != QVariant::StringList) &&
206  (m_type != QVariant::Map))
207  m_converted = true;
208 }
209 
217 CommandLineArg::CommandLineArg(const QString& name) :
218  ReferenceCounter(QString("CommandLineArg:%1").arg(name)),
219  m_name(name)
220 {
221 }
222 
227 {
228  // this may cause problems if the terminal is too narrow, or if too
229  // many keywords for the same argument are used
230  return m_keywords.join(" OR ");
231 }
232 
237 {
238  int len = GetKeywordString().length();
239 
240  QList<CommandLineArg*>::const_iterator i1;
241  for (i1 = m_parents.begin(); i1 != m_parents.end(); ++i1)
242  len = std::max(len, (*i1)->GetKeywordLength()+2);
243 
244  return len;
245 }
246 
262 QString CommandLineArg::GetHelpString(int off, const QString& group, bool force) const
263 {
264  QString helpstr;
265  QTextStream msg(&helpstr, QIODevice::WriteOnly);
266  int termwidth = GetTermWidth();
267  if (termwidth < off)
268  {
269  if (off > 70)
270  {
271  // developer has configured some absurdly long command line
272  // arguments, but we still need to do something
273  termwidth = off+40;
274  }
275  else
276  {
277  // user is running uselessly narrow console, use a sane console
278  // width instead
279  termwidth = 79;
280  }
281  }
282 
283  if (m_help.isEmpty() && !force)
284  // only print if there is a short help to print
285  return helpstr;
286 
287  if ((m_group != group) && !force)
288  // only print if looping over the correct group
289  return helpstr;
290 
291  if (!m_parents.isEmpty() && !force)
292  {
293  // only print if an independent option, not subject
294  // to a parent option
295  return helpstr;
296  }
297 
298  if (!m_deprecated.isEmpty())
299  // option is marked as deprecated, do not show
300  return helpstr;
301 
302  if (!m_removed.isEmpty())
303  // option is marked as removed, do not show
304  return helpstr;
305 
306  QString pad;
307  pad.fill(' ', off);
308 
309  // print the first line with the available keywords
310  QStringList hlist = m_help.split('\n');
311  wrapList(hlist, termwidth-off);
312  if (!m_parents.isEmpty())
313  msg << " ";
314  msg << GetKeywordString().leftJustified(off, ' ')
315  << hlist.takeFirst() << QT_ENDL;
316 
317  // print remaining lines with necessary padding
318  for (const auto & line : qAsConst(hlist))
319  msg << pad << line << QT_ENDL;
320 
321  // loop through any child arguments to print underneath
322  for (auto * arg : qAsConst(m_children))
323  msg << arg->GetHelpString(off, group, true);
324 
325  msg.flush();
326  return helpstr;
327 }
328 
336 QString CommandLineArg::GetLongHelpString(QString keyword) const
337 {
338  QString helpstr;
339  QTextStream msg(&helpstr, QIODevice::WriteOnly);
340  int termwidth = GetTermWidth();
341 
342  // help called for an argument that is not me, this should not happen
343  if (!m_keywords.contains(keyword))
344  return helpstr;
345 
346  // argument has been marked as removed, so warn user of such
347  if (!m_removed.isEmpty())
348  {
349  PrintRemovedWarning(keyword);
350  // argument has been marked as deprecated, so warn user of such
351  }
352  else if (!m_deprecated.isEmpty())
353  {
354  PrintDeprecatedWarning(keyword);
355  }
356 
357  msg << "Option: " << keyword << QT_ENDL << QT_ENDL;
358 
359  bool first = true;
360 
361  // print all related keywords, padding for multiples
362  for (const auto & word : qAsConst(m_keywords))
363  {
364  if (word != keyword)
365  {
366  if (first)
367  {
368  msg << "Aliases: " << word << QT_ENDL;
369  first = false;
370  }
371  else
372  msg << " " << word << QT_ENDL;
373  }
374  }
375 
376  // print type and default for the stored value
377  msg << "Type: " << QVariant::typeToName(m_type) << QT_ENDL;
378  if (m_default.canConvert(QVariant::String))
379  msg << "Default: " << m_default.toString() << QT_ENDL;
380 
381  QStringList help;
382  if (m_longhelp.isEmpty())
383  help = m_help.split("\n");
384  else
385  help = m_longhelp.split("\n");
386  wrapList(help, termwidth-13);
387 
388  // print description, wrapping and padding as necessary
389  msg << "Description: " << help.takeFirst() << QT_ENDL;
390  for (const auto & line : qAsConst(help))
391  msg << " " << line << QT_ENDL;
392 
393  QList<CommandLineArg*>::const_iterator i2;
394 
395  // loop through the four relation types and print
396  if (!m_parents.isEmpty())
397  {
398  msg << QT_ENDL << "Can be used in combination with:" << QT_ENDL;
399  for (auto * parent : qAsConst(m_parents))
400  msg << " " << parent->GetPreferredKeyword()
401  .toLocal8Bit().constData();
402  msg << QT_ENDL;
403  }
404 
405  if (!m_children.isEmpty())
406  {
407  msg << QT_ENDL << "Allows the use of:" << QT_ENDL;
408  for (i2 = m_children.constBegin(); i2 != m_children.constEnd(); ++i2)
409  msg << " " << (*i2)->GetPreferredKeyword()
410  .toLocal8Bit().constData();
411  msg << QT_ENDL;
412  }
413 
414  if (!m_requires.isEmpty())
415  {
416  msg << QT_ENDL << "Requires the use of:" << QT_ENDL;
417  for (i2 = m_requires.constBegin(); i2 != m_requires.constEnd(); ++i2)
418  msg << " " << (*i2)->GetPreferredKeyword()
419  .toLocal8Bit().constData();
420  msg << QT_ENDL;
421  }
422 
423  if (!m_blocks.isEmpty())
424  {
425  msg << QT_ENDL << "Prevents the use of:" << QT_ENDL;
426  for (i2 = m_blocks.constBegin(); i2 != m_blocks.constEnd(); ++i2)
427  msg << " " << (*i2)->GetPreferredKeyword()
428  .toLocal8Bit().constData();
429  msg << QT_ENDL;
430  }
431 
432  msg.flush();
433  return helpstr;
434 }
435 
442 bool CommandLineArg::Set(const QString& opt)
443 {
444  m_usedKeyword = opt;
445 
446  switch (m_type)
447  {
448  case QVariant::Bool:
449  m_stored = QVariant(!m_default.toBool());
450  break;
451 
452  case QVariant::Int:
453  if (m_stored.isNull())
454  m_stored = QVariant(1);
455  else
456  m_stored = QVariant(m_stored.toInt() + 1);
457  break;
458 
459  case QVariant::String:
461  break;
462 
463  default:
464  std::cerr << "Command line option did not receive value:" << std::endl
465  << " " << opt.toLocal8Bit().constData() << std::endl;
466  return false;
467  }
468 
469  m_given = true;
470  return true;
471 }
472 
475 bool CommandLineArg::Set(const QString& opt, const QByteArray& val)
476 {
477  QVariantList vlist;
478  QList<QByteArray> blist;
479  QVariantMap vmap;
480  m_usedKeyword = opt;
481 
482  switch (m_type)
483  {
484  case QVariant::Bool:
485  std::cerr << "Boolean type options do not accept values:" << std::endl
486  << " " << opt.toLocal8Bit().constData() << std::endl;
487  return false;
488 
489  case QVariant::String:
490  m_stored = QVariant(val);
491  break;
492 
493  case QVariant::Int:
494  m_stored = QVariant(val.toInt());
495  break;
496 
497  case QVariant::UInt:
498  m_stored = QVariant(val.toUInt());
499  break;
500 
501  case QVariant::LongLong:
502  m_stored = QVariant(val.toLongLong());
503  break;
504 
505  case QVariant::Double:
506  m_stored = QVariant(val.toDouble());
507  break;
508 
509  case QVariant::DateTime:
510  m_stored = QVariant(MythDate::fromString(QString(val)));
511  break;
512 
513  case QVariant::StringList:
514  if (!m_stored.isNull())
515  vlist = m_stored.toList();
516  vlist << val;
517  m_stored = QVariant(vlist);
518  break;
519 
520  case QVariant::Map:
521  if (!val.contains('='))
522  {
523  std::cerr << "Command line option did not get expected "
524  << "key/value pair" << std::endl;
525  return false;
526  }
527 
528  blist = val.split('=');
529 
530  if (!m_stored.isNull())
531  vmap = m_stored.toMap();
532  vmap[QString(strip_quotes(blist[0]))] = QVariant(strip_quotes(blist[1]));
533  m_stored = QVariant(vmap);
534  break;
535 
536  case QVariant::Size:
537  if (!val.contains('x'))
538  {
539  std::cerr << "Command line option did not get expected "
540  << "XxY pair" << std::endl;
541  return false;
542  }
543 
544  blist = val.split('x');
545  m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
546  break;
547 
548  default:
549  m_stored = QVariant(val);
550  }
551 
552  m_given = true;
553  return true;
554 }
555 
559 {
560  m_children << new CommandLineArg(opt);
561  return this;
562 }
563 
567 {
568  for (const auto& opt : qAsConst(opts))
569  m_children << new CommandLineArg(opt);
570  return this;
571 }
572 
576 {
577  m_parents << new CommandLineArg(opt);
578  return this;
579 }
580 
584 {
585  for (const auto& opt : qAsConst(opts))
586  m_parents << new CommandLineArg(opt);
587  return this;
588 }
589 
593 {
594  m_parents << new CommandLineArg(opt);
595  return this;
596 }
597 
601 {
602  for (const auto& opt : qAsConst(opts))
603  m_parents << new CommandLineArg(opt);
604  return this;
605 }
606 
610 {
611  m_children << new CommandLineArg(opt);
612  return this;
613 }
614 
618 {
619  for (const auto& opt : qAsConst(opts))
620  m_children << new CommandLineArg(opt);
621  return this;
622 }
623 
627 {
628  m_children << new CommandLineArg(opt);
629  m_requires << new CommandLineArg(opt);
630  return this;
631 }
632 
636 {
637  for (const auto& opt : qAsConst(opts))
638  {
639  m_children << new CommandLineArg(opt);
640  m_requires << new CommandLineArg(opt);
641  }
642  return this;
643 }
644 
648 {
649  m_parents << new CommandLineArg(opt);
650  m_requiredby << new CommandLineArg(opt);
651  return this;
652 }
653 
657 {
658  for (const auto& opt : qAsConst(opts))
659  {
660  m_parents << new CommandLineArg(opt);
661  m_requiredby << new CommandLineArg(opt);
662  }
663  return this;
664 }
665 
669 {
670  m_requires << new CommandLineArg(opt);
671  return this;
672 }
673 
677 {
678  for (const auto& opt : qAsConst(opts))
679  m_requires << new CommandLineArg(opt);
680  return this;
681 }
682 
686 {
687  m_blocks << new CommandLineArg(opt);
688  return this;
689 }
690 
694 {
695  for (const auto& opt : qAsConst(opts))
696  m_blocks << new CommandLineArg(opt);
697  return this;
698 }
699 
703 {
704  if (depstr.isEmpty())
705  depstr = "and will be removed in a future version.";
706  m_deprecated = depstr;
707  return this;
708 }
709 
712 CommandLineArg* CommandLineArg::SetRemoved(QString remstr, QString remver)
713 {
714  if (remstr.isEmpty())
715  remstr = "and is no longer available in this version.";
716  m_removed = remstr;
717  m_removedversion = std::move(remver);
718  return this;
719 }
720 
726 void CommandLineArg::SetParentOf(CommandLineArg *other, bool forward)
727 {
728  bool replaced = false;
729  other->IncrRef();
730 
731  for (int i = 0; i < m_children.size(); i++)
732  {
733  if (m_children[i]->m_name == other->m_name)
734  {
735  m_children[i]->DecrRef();
736  m_children.replace(i, other);
737  replaced = true;
738  break;
739  }
740  }
741 
742  if (!replaced)
743  m_children << other;
744 
745  if (forward)
746  other->SetChildOf(this, false);
747 }
748 
754 void CommandLineArg::SetChildOf(CommandLineArg *other, bool forward)
755 {
756  bool replaced = false;
757  other->IncrRef();
758 
759  for (int i = 0; i < m_parents.size(); i++)
760  {
761  if (m_parents[i]->m_name == other->m_name)
762  {
763  m_parents[i]->DecrRef();
764  m_parents.replace(i, other);
765  replaced = true;
766  break;
767  }
768  }
769 
770  if (!replaced)
771  m_parents << other;
772 
773  if (forward)
774  other->SetParentOf(this, false);
775 }
776 
782 void CommandLineArg::SetRequires(CommandLineArg *other, bool /*forward*/)
783 {
784  bool replaced = false;
785  other->IncrRef();
786 
787  for (int i = 0; i < m_requires.size(); i++)
788  {
789  if (m_requires[i]->m_name == other->m_name)
790  {
791  m_requires[i]->DecrRef();
792  m_requires.replace(i, other);
793  replaced = true;
794  break;
795  }
796  }
797 
798  if (!replaced)
799  m_requires << other;
800 
801 // requirements need not be reciprocal
802 // if (forward)
803 // other->SetRequires(this, false);
804 }
805 
811 void CommandLineArg::SetBlocks(CommandLineArg *other, bool forward)
812 {
813  bool replaced = false;
814  other->IncrRef();
815 
816  for (int i = 0; i < m_blocks.size(); i++)
817  {
818  if (m_blocks[i]->m_name == other->m_name)
819  {
820  m_blocks[i]->DecrRef();
821  m_blocks.replace(i, other);
822  replaced = true;
823  break;
824  }
825  }
826 
827  if (!replaced)
828  m_blocks << other;
829 
830  if (forward)
831  other->SetBlocks(this, false);
832 }
833 
836 void CommandLineArg::AllowOneOf(const QList<CommandLineArg*>& args)
837 {
838  // TODO: blocks do not get set properly if multiple dummy arguments
839  // are provided. since this method will not have access to the
840  // argument list, this issue will have to be resolved later in
841  // ReconcileLinks().
842 
843  // loop through all but the last entry
844  for (auto i1 = args.cbegin(); i1 != args.cend()-1; ++i1)
845  {
846  // loop through the next to the last entry
847  // and block use with the current
848  for (auto i2 = i1+1; i2 != args.cend(); ++i2)
849  {
850  (*i1)->SetBlocks(*i2);
851  }
852 
853  if ((*i1)->m_type == QVariant::Invalid)
854  (*i1)->DecrRef();
855  }
856 }
857 
865 {
866  if (!QCoreApplication::instance())
867  // QApplication not available, no sense doing anything yet
868  return;
869 
870  if (m_converted)
871  // already run, abort
872  return;
873 
874  if (!m_given)
875  {
876  // nothing to work on, abort
877  m_converted = true;
878  return;
879  }
880 
881  if (m_type == QVariant::String)
882  {
883  if (m_stored.type() == QVariant::ByteArray)
884  {
885  m_stored = QString::fromLocal8Bit(m_stored.toByteArray());
886  }
887  // else
888  // not sure why this isnt a bytearray, but ignore it and
889  // set it as converted
890  }
891  else if (m_type == QVariant::StringList)
892  {
893  if (m_stored.type() == QVariant::List)
894  {
895  QVariantList vlist = m_stored.toList();
896  QStringList slist;
897  for (const auto& item : qAsConst(vlist))
898  slist << QString::fromLocal8Bit(item.toByteArray());
899  m_stored = QVariant(slist);
900  }
901  }
902  else if (m_type == QVariant::Map)
903  {
904  QVariantMap vmap = m_stored.toMap();
905  // NOLINTNEXTLINE(modernize-loop-convert)
906  for (auto iter = vmap.begin(); iter != vmap.end(); ++iter)
907  (*iter) = QString::fromLocal8Bit(iter->toByteArray());
908  }
909  else
910  return;
911 
912  m_converted = true;
913 }
914 
915 
922 {
923  QStringList::const_iterator it;
924  QString preferred;
925  int len = 0;
926 
927  for (it = m_keywords.constBegin(); it != m_keywords.constEnd(); ++it)
928  {
929  int len2 = (*it).size();
930  if (len2 > len)
931  {
932  preferred = *it;
933  len = len2;
934  }
935  }
936 
937  return preferred;
938 }
939 
944 {
945  if (!m_given)
946  return true; // not in use, no need for checks
947 
948  QList<CommandLineArg*>::const_iterator i;
949 
950  bool passes = false;
951  for (i = m_parents.constBegin(); i != m_parents.constEnd(); ++i)
952  {
953  // one of these must have been defined
954  if ((*i)->m_given)
955  {
956  passes = true;
957  break;
958  }
959  }
960  if (!passes && !m_parents.isEmpty())
961  {
962  std::cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
963  << " requires at least one of the following arguments" << std::endl;
964  for (i = m_parents.constBegin(); i != m_parents.constEnd(); ++i)
965  std::cerr << " "
966  << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
967  std::cerr << std::endl << std::endl;
968  return false;
969  }
970 
971  // we dont care about children
972 
973  for (i = m_requires.constBegin(); i != m_requires.constEnd(); ++i)
974  {
975  // all of these must have been defined
976  if (!(*i)->m_given)
977  {
978  std::cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
979  << " requires all of the following be defined as well"
980  << std::endl;
981  for (i = m_requires.constBegin(); i != m_requires.constEnd(); ++i)
982  {
983  std::cerr << " "
984  << (*i)->GetPreferredKeyword().toLocal8Bit()
985  .constData();
986  }
987  std::cerr << std::endl << std::endl;
988  return false;
989  }
990  }
991 
992  for (i = m_blocks.constBegin(); i != m_blocks.constEnd(); ++i)
993  {
994  // none of these can be defined
995  if ((*i)->m_given)
996  {
997  std::cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
998  << " requires that none of the following be defined" << std::endl;
999  for (i = m_blocks.constBegin(); i != m_blocks.constEnd(); ++i)
1000  {
1001  std::cerr << " "
1002  << (*i)->GetPreferredKeyword().toLocal8Bit()
1003  .constData();
1004  }
1005  std::cerr << std::endl << std::endl;
1006  return false;
1007  }
1008  }
1009 
1010  return true;
1011 }
1012 
1016 {
1017  // clear out interdependent pointers in preparation for deletion
1018  while (!m_parents.isEmpty())
1019  m_parents.takeFirst()->DecrRef();
1020 
1021  while (!m_children.isEmpty())
1022  m_children.takeFirst()->DecrRef();
1023 
1024  while (!m_blocks.isEmpty())
1025  m_blocks.takeFirst()->DecrRef();
1026 
1027  while (!m_requires.isEmpty())
1028  m_requires.takeFirst()->DecrRef();
1029 
1030  while (!m_requiredby.isEmpty())
1031  m_requiredby.takeFirst()->DecrRef();
1032 }
1033 
1037 {
1038  if (!m_given)
1039  return;
1040 
1041  std::cerr << " " << m_name.leftJustified(30).toLocal8Bit().constData();
1042 
1043  QSize tmpsize;
1044  QMap<QString, QVariant> tmpmap;
1045  QMap<QString, QVariant>::const_iterator it;
1046  QVariantList vlist;
1047  bool first = true;
1048 
1049  switch (m_type)
1050  {
1051  case QVariant::Bool:
1052  std::cerr << (m_stored.toBool() ? "True" : "False") << std::endl;
1053  break;
1054 
1055  case QVariant::Int:
1056  std::cerr << m_stored.toInt() << std::endl;
1057  break;
1058 
1059  case QVariant::UInt:
1060  std::cerr << m_stored.toUInt() << std::endl;
1061  break;
1062 
1063  case QVariant::LongLong:
1064  std::cerr << m_stored.toLongLong() << std::endl;
1065  break;
1066 
1067  case QVariant::Double:
1068  std::cerr << m_stored.toDouble() << std::endl;
1069  break;
1070 
1071  case QVariant::Size:
1072  tmpsize = m_stored.toSize();
1073  std::cerr << "x=" << tmpsize.width()
1074  << " y=" << tmpsize.height()
1075  << std::endl;
1076  break;
1077 
1078  case QVariant::String:
1079  std::cerr << '"' << m_stored.toByteArray().constData()
1080  << '"' << std::endl;
1081  break;
1082 
1083  case QVariant::StringList:
1084  vlist = m_stored.toList();
1085  std::cerr << '"' << vlist.takeFirst().toByteArray().constData() << '"';
1086  for (const auto& str : qAsConst(vlist))
1087  {
1088  std::cerr << ", \""
1089  << str.constData()
1090  << '"';
1091  }
1092  std::cerr << std::endl;
1093  break;
1094 
1095  case QVariant::Map:
1096  tmpmap = m_stored.toMap();
1097  for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1098  {
1099  if (first)
1100  first = false;
1101  else
1102  std::cerr << QString("").leftJustified(32)
1103  .toLocal8Bit().constData();
1104 
1105  std::cerr << it.key().toLocal8Bit().constData()
1106  << '='
1107  << it->toByteArray().constData()
1108  << std::endl;
1109  }
1110 
1111  break;
1112 
1113  case QVariant::DateTime:
1114  std::cerr << m_stored.toDateTime().toString(Qt::ISODate)
1115  .toLocal8Bit().constData()
1116  << std::endl;
1117  break;
1118 
1119  default:
1120  std::cerr << std::endl;
1121  }
1122 }
1123 
1126 void CommandLineArg::PrintRemovedWarning(QString &keyword) const
1127 {
1128  QString warn = QString("%1 has been removed").arg(keyword);
1129  if (!m_removedversion.isEmpty())
1130  warn += QString(" as of MythTV %1").arg(m_removedversion);
1131 
1132  std::cerr << QString("****************************************************\n"
1133  " WARNING: %1\n"
1134  " %2\n"
1135  "****************************************************\n\n")
1136  .arg(warn).arg(m_removed)
1137  .toLocal8Bit().constData();
1138 }
1139 
1142 void CommandLineArg::PrintDeprecatedWarning(QString &keyword) const
1143 {
1144  std::cerr << QString("****************************************************\n"
1145  " WARNING: %1 has been deprecated\n"
1146  " %2\n"
1147  "****************************************************\n\n")
1148  .arg(keyword).arg(m_deprecated)
1149  .toLocal8Bit().constData();
1150 }
1151 
1166  : m_appname(std::move(appname))
1167 {
1168  if (qEnvironmentVariableIsSet("VERBOSE_PARSER"))
1169  {
1170  std::cerr << "MythCommandLineParser is now operating verbosely." << std::endl;
1171  m_verbose = true;
1172  }
1173 
1175 }
1176 
1178 {
1179  QMap<QString, CommandLineArg*>::iterator i;
1180 
1181  i = m_namedArgs.begin();
1182  while (i != m_namedArgs.end())
1183  {
1184  (*i)->CleanupLinks();
1185  (*i)->DecrRef();
1186  i = m_namedArgs.erase(i);
1187  }
1188 
1189  i = m_optionedArgs.begin();
1190  while (i != m_optionedArgs.end())
1191  {
1192  (*i)->DecrRef();
1193  i = m_optionedArgs.erase(i);
1194  }
1195 }
1196 
1231  const QString& name, QVariant::Type type, QVariant def,
1232  QString help, QString longhelp)
1233 {
1234  CommandLineArg *arg = nullptr;
1235 
1236  if (m_namedArgs.contains(name))
1237  arg = m_namedArgs[name];
1238  else
1239  {
1240  arg = new CommandLineArg(name, type, std::move(def), std::move(help), std::move(longhelp));
1241  m_namedArgs.insert(name, arg);
1242  }
1243 
1244  for (const auto & str : qAsConst(arglist))
1245  {
1246  if (!m_optionedArgs.contains(str))
1247  {
1248  arg->AddKeyword(str);
1249  if (m_verbose)
1250  {
1251  std::cerr << "Adding " << str.toLocal8Bit().constData()
1252  << " as taking type '" << QVariant::typeToName(type)
1253  << "'" << std::endl;
1254  }
1255  arg->IncrRef();
1256  m_optionedArgs.insert(str, arg);
1257  }
1258  }
1259 
1260  return arg;
1261 }
1262 
1266 {
1267  std::cout << "Please attach all output as a file in bug reports." << std::endl;
1268  std::cout << "MythTV Version : " << GetMythSourceVersion() << std::endl;
1269  std::cout << "MythTV Branch : " << GetMythSourcePath() << std::endl;
1270  std::cout << "Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1271  std::cout << "Library API : " << MYTH_BINARY_VERSION << std::endl;
1272  std::cout << "QT Version : " << QT_VERSION_STR << std::endl;
1273 #ifdef MYTH_BUILD_CONFIG
1274  std::cout << "Options compiled in:" <<std::endl;
1275  std::cout << MYTH_BUILD_CONFIG << std::endl;
1276 #endif
1277 }
1278 
1282 {
1283  QString help = GetHelpString();
1284  std::cerr << help.toLocal8Bit().constData();
1285 }
1286 
1293 {
1294  QString helpstr;
1295  QTextStream msg(&helpstr, QIODevice::WriteOnly);
1296 
1297  QString versionStr = QString("%1 version: %2 [%3] www.mythtv.org")
1298  .arg(m_appname).arg(GetMythSourcePath()).arg(GetMythSourceVersion());
1299  msg << versionStr << QT_ENDL;
1300 
1301  if (toString("showhelp").isEmpty())
1302  {
1303  // build generic help text
1304 
1305  QString descr = GetHelpHeader();
1306  if (descr.size() > 0)
1307  msg << QT_ENDL << descr << QT_ENDL << QT_ENDL;
1308 
1309  // loop through registered arguments to populate list of groups
1310  QStringList groups("");
1311  int maxlen = 0;
1312  for (auto * cmdarg : qAsConst(m_namedArgs))
1313  {
1314  maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1315  if (!groups.contains(cmdarg->m_group))
1316  groups << cmdarg->m_group;
1317  }
1318 
1319  // loop through list of groups and print help string for each
1320  // arguments will filter themselves if they are not in the group
1321  maxlen += 4;
1322  for (const auto & group : qAsConst(groups))
1323  {
1324  if (group.isEmpty())
1325  msg << "Misc. Options:" << QT_ENDL;
1326  else
1327  msg << group.toLocal8Bit().constData() << " Options:" << QT_ENDL;
1328 
1329  for (auto * cmdarg : qAsConst(m_namedArgs))
1330  msg << cmdarg->GetHelpString(maxlen, group);
1331  msg << QT_ENDL;
1332  }
1333  }
1334  else
1335  {
1336  // build help for a specific argument
1337  QString optstr = "-" + toString("showhelp");
1338  if (!m_optionedArgs.contains(optstr))
1339  {
1340  optstr = "-" + optstr;
1341  if (!m_optionedArgs.contains(optstr))
1342  return QString("Could not find option matching '%1'\n")
1343  .arg(toString("showhelp"));
1344  }
1345 
1346  if (m_optionedArgs[optstr] != nullptr)
1347  msg << m_optionedArgs[optstr]->GetLongHelpString(optstr);
1348  }
1349 
1350  msg.flush();
1351  return helpstr;
1352 }
1353 
1357  int &argpos, QString &opt, QByteArray &val)
1358 {
1359  opt.clear();
1360  val.clear();
1361 
1362  if (argpos >= argc)
1363  // this shouldnt happen, return and exit
1364  return Result::kEnd;
1365 
1366  QByteArray tmp(argv[argpos]);
1367  if (tmp.isEmpty())
1368  // string is empty, return and loop
1369  return Result::kEmpty;
1370 
1371  if (m_passthroughActive)
1372  {
1373  // pass through has been activated
1374  val = tmp;
1375  return Result::kArg;
1376  }
1377 
1378  if (tmp.startsWith('-') && tmp.size() > 1)
1379  {
1380  if (tmp == "--")
1381  {
1382  // all options beyond this will be passed as a single string
1383  m_passthroughActive = true;
1384  return Result::kPassthrough;
1385  }
1386 
1387  if (tmp.contains('='))
1388  {
1389  // option contains '=', split
1390  QList<QByteArray> blist = tmp.split('=');
1391 
1392  if (blist.size() != 2)
1393  {
1394  // more than one '=' in option, this is not handled
1395  opt = QString(tmp);
1396  return Result::kInvalid;
1397  }
1398 
1399  opt = QString(strip_quotes(blist[0]));
1400  val = strip_quotes(blist[1]);
1401  return Result::kCombOptVal;
1402  }
1403 
1404  opt = QString(tmp);
1405 
1406  if (argpos+1 >= argc)
1407  // end of input, option only
1408  return Result::kOptOnly;
1409 
1410  tmp = QByteArray(argv[++argpos]);
1411  if (tmp.isEmpty())
1412  // empty string, option only
1413  return Result::kOptOnly;
1414 
1415  if (tmp.startsWith("-") && tmp.size() > 1)
1416  {
1417  // no value found for option, backtrack
1418  argpos--;
1419  return Result::kOptOnly;
1420  }
1421 
1422  val = tmp;
1423  return Result::kOptVal;
1424  }
1425 
1426  // input is not an option string, return as arg
1427  val = tmp;
1428  return Result::kArg;
1429 }
1430 
1437 bool MythCommandLineParser::Parse(int argc, const char * const * argv)
1438 {
1439  Result res = Result::kEnd;
1440  QString opt;
1441  QByteArray val;
1442  CommandLineArg *argdef = nullptr;
1443 
1444  // reconnect interdependencies between command line options
1445  if (!ReconcileLinks())
1446  return false;
1447 
1448  // loop through command line arguments until all are spent
1449  for (int argpos = 1; argpos < argc; ++argpos)
1450  {
1451 
1452  // pull next option
1453  res = getOpt(argc, argv, argpos, opt, val);
1454 
1455  if (m_verbose)
1456  {
1457  std::cerr << "res: " << NamedOptType(res) << std::endl
1458  << "opt: " << opt.toLocal8Bit().constData() << std::endl
1459  << "val: " << val.constData() << std::endl << std::endl;
1460  }
1461 
1462  // '--' found on command line, enable passthrough mode
1463  if (res == Result::kPassthrough && !m_namedArgs.contains("_passthrough"))
1464  {
1465  std::cerr << "Received '--' but passthrough has not been enabled" << std::endl;
1466  SetValue("showhelp", "");
1467  return false;
1468  }
1469 
1470  // end of options found, terminate loop
1471  if (res == Result::kEnd)
1472  break;
1473 
1474  // GetOpt pulled an empty option, this shouldnt happen by ignore
1475  // it and continue
1476  if (res == Result::kEmpty)
1477  continue;
1478 
1479  // more than one equal found in key/value pair, fault out
1480  if (res == Result::kInvalid)
1481  {
1482  std::cerr << "Invalid option received:" << std::endl << " "
1483  << opt.toLocal8Bit().constData();
1484  SetValue("showhelp", "");
1485  return false;
1486  }
1487 
1488  // passthrough is active, so add the data to the stringlist
1489  if (m_passthroughActive)
1490  {
1491  m_namedArgs["_passthrough"]->Set("", val);
1492  continue;
1493  }
1494 
1495  // argument with no preceeding '-' encountered, add to stringlist
1496  if (res == Result::kArg)
1497  {
1498  if (!m_namedArgs.contains("_args"))
1499  {
1500  std::cerr << "Received '"
1501  << val.constData()
1502  << "' but unassociated arguments have not been enabled"
1503  << std::endl;
1504  SetValue("showhelp", "");
1505  return false;
1506  }
1507 
1508  m_namedArgs["_args"]->Set("", val);
1509  continue;
1510  }
1511 
1512  // this line should not be passed once arguments have started collecting
1513  if (toBool("_args"))
1514  {
1515  std::cerr << "Command line arguments received out of sequence"
1516  << std::endl;
1517  SetValue("showhelp", "");
1518  return false;
1519  }
1520 
1521 #ifdef Q_OS_MAC
1522  if (opt.startsWith("-psn_"))
1523  {
1524  std::cerr << "Ignoring Process Serial Number from command line"
1525  << std::endl;
1526  continue;
1527  }
1528 #endif
1529 
1530  if (!m_optionedArgs.contains(opt))
1531  {
1532  // argument is unhandled, check if parser allows arbitrary input
1533  if (m_namedArgs.contains("_extra"))
1534  {
1535  // arbitrary allowed, specify general collection pool
1536  argdef = m_namedArgs["_extra"];
1537  QByteArray tmp = opt.toLocal8Bit();
1538  tmp += '=';
1539  tmp += val;
1540  val = tmp;
1541  res = Result::kOptVal;
1542  }
1543  else
1544  {
1545  // arbitrary not allowed, fault out
1546  std::cerr << "Unhandled option given on command line:" << std::endl
1547  << " " << opt.toLocal8Bit().constData() << std::endl;
1548  SetValue("showhelp", "");
1549  return false;
1550  }
1551  }
1552  else
1553  argdef = m_optionedArgs[opt];
1554 
1555  // argument has been marked as removed, warn user and fail
1556  if (!argdef->m_removed.isEmpty())
1557  {
1558  argdef->PrintRemovedWarning(opt);
1559  SetValue("showhelp", "");
1560  return false;
1561  }
1562 
1563  // argument has been marked as deprecated, warn user
1564  if (!argdef->m_deprecated.isEmpty())
1565  argdef->PrintDeprecatedWarning(opt);
1566 
1567  if (m_verbose)
1568  std::cerr << "name: " << argdef->GetName().toLocal8Bit().constData()
1569  << std::endl;
1570 
1571  // argument is keyword only, no value
1572  if (res == Result::kOptOnly)
1573  {
1574  if (!argdef->Set(opt))
1575  {
1576  SetValue("showhelp", "");
1577  return false;
1578  }
1579  }
1580  // argument has keyword and value
1581  else if ((res == Result::kOptVal) || (res == Result::kCombOptVal))
1582  {
1583  if (!argdef->Set(opt, val))
1584  {
1585  // if option and value were combined with a '=', abort directly
1586  // otherwise, attempt processing them independenly
1587  if ((res == Result::kCombOptVal) || !argdef->Set(opt))
1588  {
1589  SetValue("showhelp", "");
1590  return false;
1591  }
1592  // drop back an iteration so the unused value will get
1593  // processed a second time as a keyword-less argument
1594  --argpos;
1595  }
1596  }
1597  else
1598  {
1599  SetValue("showhelp", "");
1600  return false; // this should not occur
1601  }
1602 
1603  if (m_verbose)
1604  std::cerr << "value: " << argdef->m_stored.toString().toLocal8Bit().constData()
1605  << std::endl;
1606  }
1607 
1608  if (m_verbose)
1609  {
1610  std::cerr << "Processed option list:" << std::endl;
1611  for (auto * cmdarg : qAsConst(m_namedArgs))
1612  cmdarg->PrintVerbose();
1613 
1614  if (m_namedArgs.contains("_args"))
1615  {
1616  std::cerr << std::endl << "Extra argument list:" << std::endl;
1617  QStringList slist = toStringList("_args");
1618  for (const auto& lopt : qAsConst(slist))
1619  std::cerr << " " << (lopt).toLocal8Bit().constData() << std::endl;
1620  }
1621 
1622  if (m_namedArgs.contains("_passthrough"))
1623  {
1624  std::cerr << std::endl << "Passthrough string:" << std::endl;
1625  std::cerr << " " << GetPassthrough().toLocal8Bit().constData() << std::endl;
1626  }
1627 
1628  std::cerr << std::endl;
1629  }
1630 
1631  // make sure all interdependencies are fulfilled
1632  for (auto * cmdarg : qAsConst(m_namedArgs))
1633  {
1634  if (!cmdarg->TestLinks())
1635  {
1636  QString keyword = cmdarg->m_usedKeyword;
1637  if (keyword.startsWith('-'))
1638  {
1639  if (keyword.startsWith("--"))
1640  keyword.remove(0,2);
1641  else
1642  keyword.remove(0,1);
1643  }
1644 
1645  SetValue("showhelp", keyword);
1646  return false;
1647  }
1648  }
1649 
1650  return true;
1651 }
1652 
1657 {
1658  if (m_verbose)
1659  std::cerr << "Reconciling links for option interdependencies." << std::endl;
1660 
1661  QMap<QString,CommandLineArg*>::iterator args_it;
1662  for (args_it = m_namedArgs.begin(); args_it != m_namedArgs.end(); ++args_it)
1663  {
1664  QList<CommandLineArg*> links = (*args_it)->m_parents;
1665  QList<CommandLineArg*>::iterator links_it;
1666  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1667  {
1668  if ((*links_it)->m_type != QVariant::Invalid)
1669  continue; // already handled
1670 
1671  if (!m_namedArgs.contains((*links_it)->m_name))
1672  {
1673  // not found
1674  std::cerr << "ERROR: could not reconcile linked argument." << std::endl
1675  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1676  << "' could not find '"
1677  << (*links_it)->m_name.toLocal8Bit().constData()
1678  << "'." << std::endl
1679  << " Please resolve dependency and recompile." << std::endl;
1680  return false;
1681  }
1682 
1683  // replace linked argument
1684  if (m_verbose)
1685  {
1686  std::cerr << QString(" Setting %1 as child of %2")
1687  .arg((*args_it)->m_name).arg((*links_it)->m_name)
1688  .toLocal8Bit().constData()
1689  << std::endl;
1690  }
1691  (*args_it)->SetChildOf(m_namedArgs[(*links_it)->m_name]);
1692  }
1693 
1694  links = (*args_it)->m_children;
1695  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1696  {
1697  if ((*links_it)->m_type != QVariant::Invalid)
1698  continue; // already handled
1699 
1700  if (!m_namedArgs.contains((*links_it)->m_name))
1701  {
1702  // not found
1703  std::cerr << "ERROR: could not reconcile linked argument." << std::endl
1704  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1705  << "' could not find '"
1706  << (*links_it)->m_name.toLocal8Bit().constData()
1707  << "'." << std::endl
1708  << " Please resolve dependency and recompile." << std::endl;
1709  return false;
1710  }
1711 
1712  // replace linked argument
1713  if (m_verbose)
1714  {
1715  std::cerr << QString(" Setting %1 as parent of %2")
1716  .arg((*args_it)->m_name).arg((*links_it)->m_name)
1717  .toLocal8Bit().constData()
1718  << std::endl;
1719  }
1720  (*args_it)->SetParentOf(m_namedArgs[(*links_it)->m_name]);
1721  }
1722 
1723  links = (*args_it)->m_requires;
1724  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1725  {
1726  if ((*links_it)->m_type != QVariant::Invalid)
1727  continue; // already handled
1728 
1729  if (!m_namedArgs.contains((*links_it)->m_name))
1730  {
1731  // not found
1732  std::cerr << "ERROR: could not reconcile linked argument." << std::endl
1733  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1734  << "' could not find '"
1735  << (*links_it)->m_name.toLocal8Bit().constData()
1736  << "'." << std::endl
1737  << " Please resolve dependency and recompile." << std::endl;
1738  return false;
1739  }
1740 
1741  // replace linked argument
1742  if (m_verbose)
1743  {
1744  std::cerr << QString(" Setting %1 as requiring %2")
1745  .arg((*args_it)->m_name).arg((*links_it)->m_name)
1746  .toLocal8Bit().constData()
1747  << std::endl;
1748  }
1749  (*args_it)->SetRequires(m_namedArgs[(*links_it)->m_name]);
1750  }
1751 
1752  QList<CommandLineArg*>::iterator req_it =
1753  (*args_it)->m_requiredby.begin();
1754  while (req_it != (*args_it)->m_requiredby.end())
1755  {
1756  if ((*req_it)->m_type == QVariant::Invalid)
1757  {
1758  // if its not an invalid, it shouldnt be here anyway
1759  if (m_namedArgs.contains((*req_it)->m_name))
1760  {
1761  m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
1762  if (m_verbose)
1763  {
1764  std::cerr << QString(" Setting %1 as blocking %2")
1765  .arg((*args_it)->m_name)
1766  .arg((*req_it)->m_name)
1767  .toLocal8Bit().constData()
1768  << std::endl;
1769  }
1770  }
1771  }
1772 
1773  (*req_it)->DecrRef();
1774  req_it = (*args_it)->m_requiredby.erase(req_it);
1775  }
1776 
1777  QList<CommandLineArg*>::iterator block_it =
1778  (*args_it)->m_blocks.begin();
1779  while (block_it != (*args_it)->m_blocks.end())
1780  {
1781  if ((*block_it)->m_type != QVariant::Invalid)
1782  {
1783  ++block_it;
1784  continue; // already handled
1785  }
1786 
1787  if (!m_namedArgs.contains((*block_it)->m_name))
1788  {
1789  (*block_it)->DecrRef();
1790  block_it = (*args_it)->m_blocks.erase(block_it);
1791  continue; // if it doesnt exist, it cant block this command
1792  }
1793 
1794  // replace linked argument
1795  if (m_verbose)
1796  {
1797  std::cerr << QString(" Setting %1 as blocking %2")
1798  .arg((*args_it)->m_name).arg((*block_it)->m_name)
1799  .toLocal8Bit().constData()
1800  << std::endl;
1801  }
1802  (*args_it)->SetBlocks(m_namedArgs[(*block_it)->m_name]);
1803  ++block_it;
1804  }
1805  }
1806 
1807  return true;
1808 }
1809 
1813 QVariant MythCommandLineParser::operator[](const QString &name)
1814 {
1815  QVariant var("");
1816  if (!m_namedArgs.contains(name))
1817  return var;
1818 
1819  CommandLineArg *arg = m_namedArgs[name];
1820 
1821  if (arg->m_given)
1822  var = arg->m_stored;
1823  else
1824  var = arg->m_default;
1825 
1826  return var;
1827 }
1828 
1832 QStringList MythCommandLineParser::GetArgs(void) const
1833 {
1834  return toStringList("_args");
1835 }
1836 
1840 QMap<QString,QString> MythCommandLineParser::GetExtra(void) const
1841 {
1842  return toMap("_extra");
1843 }
1844 
1848 {
1849  return toStringList("_passthrough").join(" ");
1850 }
1851 
1860 {
1861  QMap<QString,QString> smap = toMap("overridesettings");
1862 
1863  if (!m_overridesImported)
1864  {
1865  if (toBool("overridesettingsfile"))
1866  {
1867  QString filename = toString("overridesettingsfile");
1868  if (!filename.isEmpty())
1869  {
1870  QFile f(filename);
1871  if (f.open(QIODevice::ReadOnly))
1872  {
1873  QTextStream in(&f);
1874  while (!in.atEnd()) {
1875  QString line = in.readLine().trimmed();
1876 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
1877  QStringList tokens = line.split("=",
1878  QString::SkipEmptyParts);
1879 #else
1880  QStringList tokens = line.split("=",
1881  Qt::SkipEmptyParts);
1882 #endif
1883  if (tokens.size() == 2)
1884  {
1885  tokens[0].remove(QRegularExpression("^[\"']"));
1886  tokens[0].remove(QRegularExpression("[\"']$"));
1887  tokens[1].remove(QRegularExpression("^[\"']"));
1888  tokens[1].remove(QRegularExpression("[\"']$"));
1889  if (!tokens[0].isEmpty())
1890  smap[tokens[0]] = tokens[1];
1891  }
1892  }
1893  }
1894  else
1895  {
1896  QByteArray tmp = filename.toLatin1();
1897  std::cerr << "Failed to open the override settings file: '"
1898  << tmp.constData() << "'" << std::endl;
1899  }
1900  }
1901  }
1902 
1903  if (toBool("windowed"))
1904  smap["RunFrontendInWindow"] = "1";
1905  else if (toBool("notwindowed"))
1906  smap["RunFrontendInWindow"] = "0";
1907 
1908  if (toBool("mousecursor"))
1909  smap["HideMouseCursor"] = "0";
1910  else if (toBool("nomousecursor"))
1911  smap["HideMouseCursor"] = "1";
1912 
1913  m_overridesImported = true;
1914 
1915  if (!smap.isEmpty())
1916  {
1917  QVariantMap vmap;
1918  for (auto it = smap.cbegin(); it != smap.cend(); ++it)
1919  vmap[it.key()] = QVariant(it.value());
1920 
1921  m_namedArgs["overridesettings"]->Set(QVariant(vmap));
1922  }
1923  }
1924 
1925  if (m_verbose)
1926  {
1927  std::cerr << "Option Overrides:" << std::endl;
1928  QMap<QString, QString>::const_iterator it;
1929  for (it = smap.constBegin(); it != smap.constEnd(); ++it)
1930  std::cerr << QString(" %1 - %2").arg(it.key(), 30).arg(*it)
1931  .toLocal8Bit().constData() << std::endl;
1932  }
1933 
1934  return smap;
1935 }
1936 
1943 bool MythCommandLineParser::toBool(const QString& key) const
1944 {
1945  if (!m_namedArgs.contains(key))
1946  return false;
1947 
1948  CommandLineArg *arg = m_namedArgs[key];
1949  if (arg == nullptr)
1950  return false;
1951 
1952  if (arg->m_type == QVariant::Bool)
1953  {
1954  if (arg->m_given)
1955  return arg->m_stored.toBool();
1956  return arg->m_default.toBool();
1957  }
1958 
1959  return arg->m_given;
1960 }
1961 
1965 int MythCommandLineParser::toInt(const QString& key) const
1966 {
1967  int val = 0;
1968  if (!m_namedArgs.contains(key))
1969  return val;
1970 
1971  CommandLineArg *arg = m_namedArgs[key];
1972  if (arg == nullptr)
1973  return val;
1974 
1975  if (arg->m_given)
1976  {
1977  if (arg->m_stored.canConvert(QVariant::Int))
1978  val = arg->m_stored.toInt();
1979  }
1980  else
1981  {
1982  if (arg->m_default.canConvert(QVariant::Int))
1983  val = arg->m_default.toInt();
1984  }
1985 
1986  return val;
1987 }
1988 
1992 uint MythCommandLineParser::toUInt(const QString& key) const
1993 {
1994  uint val = 0;
1995  if (!m_namedArgs.contains(key))
1996  return val;
1997 
1998  CommandLineArg *arg = m_namedArgs[key];
1999  if (arg == nullptr)
2000  return val;
2001 
2002  if (arg->m_given)
2003  {
2004  if (arg->m_stored.canConvert(QVariant::UInt))
2005  val = arg->m_stored.toUInt();
2006  }
2007  else
2008  {
2009  if (arg->m_default.canConvert(QVariant::UInt))
2010  val = arg->m_default.toUInt();
2011  }
2012 
2013  return val;
2014 }
2015 
2019 long long MythCommandLineParser::toLongLong(const QString& key) const
2020 {
2021  long long val = 0;
2022  if (!m_namedArgs.contains(key))
2023  return val;
2024 
2025  CommandLineArg *arg = m_namedArgs[key];
2026  if (arg == nullptr)
2027  return val;
2028 
2029  if (arg->m_given)
2030  {
2031  if (arg->m_stored.canConvert(QVariant::LongLong))
2032  val = arg->m_stored.toLongLong();
2033  }
2034  else
2035  {
2036  if (arg->m_default.canConvert(QVariant::LongLong))
2037  val = arg->m_default.toLongLong();
2038  }
2039 
2040  return val;
2041 }
2042 
2046 double MythCommandLineParser::toDouble(const QString& key) const
2047 {
2048  double val = 0.0;
2049  if (!m_namedArgs.contains(key))
2050  return val;
2051 
2052  CommandLineArg *arg = m_namedArgs[key];
2053  if (arg == nullptr)
2054  return val;
2055 
2056  if (arg->m_given)
2057  {
2058  if (arg->m_stored.canConvert(QVariant::Double))
2059  val = arg->m_stored.toDouble();
2060  }
2061  else
2062  {
2063  if (arg->m_default.canConvert(QVariant::Double))
2064  val = arg->m_default.toDouble();
2065  }
2066 
2067  return val;
2068 }
2069 
2073 QSize MythCommandLineParser::toSize(const QString& key) const
2074 {
2075  QSize val(0,0);
2076  if (!m_namedArgs.contains(key))
2077  return val;
2078 
2079  CommandLineArg *arg = m_namedArgs[key];
2080  if (arg == nullptr)
2081  return val;
2082 
2083  if (arg->m_given)
2084  {
2085  if (arg->m_stored.canConvert(QVariant::Size))
2086  val = arg->m_stored.toSize();
2087  }
2088  else
2089  {
2090  if (arg->m_default.canConvert(QVariant::Size))
2091  val = arg->m_default.toSize();
2092  }
2093 
2094  return val;
2095 }
2096 
2100 QString MythCommandLineParser::toString(const QString& key) const
2101 {
2102  QString val("");
2103  if (!m_namedArgs.contains(key))
2104  return val;
2105 
2106  CommandLineArg *arg = m_namedArgs[key];
2107  if (arg == nullptr)
2108  return val;
2109 
2110  if (arg->m_given)
2111  {
2112  if (!arg->m_converted)
2113  arg->Convert();
2114 
2115  if (arg->m_stored.canConvert(QVariant::String))
2116  val = arg->m_stored.toString();
2117  }
2118  else
2119  {
2120  if (arg->m_default.canConvert(QVariant::String))
2121  val = arg->m_default.toString();
2122  }
2123 
2124  return val;
2125 }
2126 
2131 QStringList MythCommandLineParser::toStringList(const QString& key, const QString& sep) const
2132 {
2133  QVariant varval;
2134  QStringList val;
2135  if (!m_namedArgs.contains(key))
2136  return val;
2137 
2138  CommandLineArg *arg = m_namedArgs[key];
2139  if (arg == nullptr)
2140  return val;
2141 
2142  if (arg->m_given)
2143  {
2144  if (!arg->m_converted)
2145  arg->Convert();
2146 
2147  varval = arg->m_stored;
2148  }
2149  else
2150  varval = arg->m_default;
2151 
2152  if (arg->m_type == QVariant::String && !sep.isEmpty())
2153  val = varval.toString().split(sep);
2154  else if (varval.canConvert(QVariant::StringList))
2155  val = varval.toStringList();
2156 
2157  return val;
2158 }
2159 
2163 QMap<QString,QString> MythCommandLineParser::toMap(const QString& key) const
2164 {
2165  QMap<QString, QString> val;
2166  QMap<QString, QVariant> tmp;
2167  if (!m_namedArgs.contains(key))
2168  return val;
2169 
2170  CommandLineArg *arg = m_namedArgs[key];
2171  if (arg == nullptr)
2172  return val;
2173 
2174  if (arg->m_given)
2175  {
2176  if (!arg->m_converted)
2177  arg->Convert();
2178 
2179  if (arg->m_stored.canConvert(QVariant::Map))
2180  tmp = arg->m_stored.toMap();
2181  }
2182  else
2183  {
2184  if (arg->m_default.canConvert(QVariant::Map))
2185  tmp = arg->m_default.toMap();
2186  }
2187 
2188  for (auto i = tmp.cbegin(); i != tmp.cend(); ++i)
2189  val[i.key()] = i.value().toString();
2190 
2191  return val;
2192 }
2193 
2197 QDateTime MythCommandLineParser::toDateTime(const QString& key) const
2198 {
2199  QDateTime val;
2200  if (!m_namedArgs.contains(key))
2201  return val;
2202 
2203  CommandLineArg *arg = m_namedArgs[key];
2204  if (arg == nullptr)
2205  return val;
2206 
2207  if (arg->m_given)
2208  {
2209  if (arg->m_stored.canConvert(QVariant::DateTime))
2210  val = arg->m_stored.toDateTime();
2211  }
2212  else
2213  {
2214  if (arg->m_default.canConvert(QVariant::DateTime))
2215  val = arg->m_default.toDateTime();
2216  }
2217 
2218  return val;
2219 }
2220 
2225 {
2226  if (m_namedArgs.contains("_args"))
2227  {
2228  if (!allow)
2229  m_namedArgs.remove("_args");
2230  }
2231  else if (!allow)
2232  return;
2233 
2234  auto *arg = new CommandLineArg("_args", QVariant::StringList, QStringList());
2235  m_namedArgs["_args"] = arg;
2236 }
2237 
2242 {
2243  if (m_namedArgs.contains("_extra"))
2244  {
2245  if (!allow)
2246  m_namedArgs.remove("_extra");
2247  }
2248  else if (!allow)
2249  return;
2250 
2251  QMap<QString,QVariant> vmap;
2252  auto *arg = new CommandLineArg("_extra", QVariant::Map, vmap);
2253 
2254  m_namedArgs["_extra"] = arg;
2255 }
2256 
2261 {
2262  if (m_namedArgs.contains("_passthrough"))
2263  {
2264  if (!allow)
2265  m_namedArgs.remove("_passthrough");
2266  }
2267  else if (!allow)
2268  return;
2269 
2270  auto *arg = new CommandLineArg("_passthrough",
2271  QVariant::StringList, QStringList());
2272  m_namedArgs["_passthrough"] = arg;
2273 }
2274 
2278 {
2279  add(QStringList{"-h", "--help", "--usage"},
2280  "showhelp", "", "Display this help printout, or give detailed "
2281  "information of selected option.",
2282  "Displays a list of all commands available for use with "
2283  "this application. If another option is provided as an "
2284  "argument, it will provide detailed information on that "
2285  "option.");
2286 }
2287 
2291 {
2292  add("--version", "showversion", false, "Display version information.",
2293  "Display informtion about build, including:\n"
2294  " version, branch, protocol, library API, Qt "
2295  "and compiled options.");
2296 }
2297 
2301 {
2302  add(QStringList{"-nw", "--no-windowed"},
2303  "notwindowed", false,
2304  "Prevent application from running in a window.", "")
2305  ->SetBlocks("windowed")
2306  ->SetGroup("User Interface");
2307 
2308  add(QStringList{"-w", "--windowed"}, "windowed",
2309  false, "Force application to run in a window.", "")
2310  ->SetGroup("User Interface");
2311 }
2312 
2316 {
2317  add("--mouse-cursor", "mousecursor", false,
2318  "Force visibility of the mouse cursor.", "")
2319  ->SetBlocks("nomousecursor")
2320  ->SetGroup("User Interface");
2321 
2322  add("--no-mouse-cursor", "nomousecursor", false,
2323  "Force the mouse cursor to be hidden.", "")
2324  ->SetGroup("User Interface");
2325 }
2326 
2330 {
2331  add(QStringList{"-d", "--daemon"}, "daemon", false,
2332  "Fork application into background after startup.",
2333  "Fork application into background, detatching from "
2334  "the local terminal.\nOften used with: "
2335  " --logpath --pidfile --user");
2336 }
2337 
2342 {
2343  add(QStringList{"-O", "--override-setting"},
2344  "overridesettings", QVariant::Map,
2345  "Override a single setting defined by a key=value pair.",
2346  "Override a single setting from the database using "
2347  "options defined as one or more key=value pairs\n"
2348  "Multiple can be defined by multiple uses of the "
2349  "-O option.");
2350  add("--override-settings-file", "overridesettingsfile", "",
2351  "Define a file of key=value pairs to be "
2352  "loaded for setting overrides.", "");
2353 }
2354 
2358 {
2359  add("--chanid", "chanid", 0U,
2360  "Specify chanid of recording to operate on.", "")
2361  ->SetRequires("starttime");
2362 
2363  add("--starttime", "starttime", QDateTime(),
2364  "Specify start time of recording to operate on.", "")
2365  ->SetRequires("chanid");
2366 }
2367 
2371 {
2372  add(QStringList{"-geometry", "--geometry"}, "geometry",
2373  "", "Specify window size and position (WxH[+X+Y])", "")
2374  ->SetGroup("User Interface");
2375 }
2376 
2380 {
2381  add("--noupnp", "noupnp", false, "Disable use of UPnP.", "");
2382 }
2383 
2388  const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2389 {
2390  defaultLogLevel =
2391  ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2392  LOG_INFO : defaultLogLevel;
2393 
2394  QString logLevelStr = logLevelGetName(defaultLogLevel);
2395 
2396  add(QStringList{"-v", "--verbose"}, "verbose",
2397  defaultVerbosity,
2398  "Specify log filtering. Use '-v help' for level info.", "")
2399  ->SetGroup("Logging");
2400  add("-V", "verboseint", 0LL, "",
2401  "This option is intended for internal use only.\n"
2402  "This option takes an unsigned value corresponding "
2403  "to the bitwise log verbosity operator.")
2404  ->SetGroup("Logging");
2405  add("--logpath", "logpath", "",
2406  "Writes logging messages to a file in the directory logpath with "
2407  "filenames in the format: applicationName.date.pid.log.\n"
2408  "This is typically used in combination with --daemon, and if used "
2409  "in combination with --pidfile, this can be used with log "
2410  "rotators, using the HUP call to inform MythTV to reload the "
2411  "file", "")
2412  ->SetGroup("Logging");
2413  add(QStringList{"-q", "--quiet"}, "quiet", 0,
2414  "Don't log to the console (-q). Don't log anywhere (-q -q)", "")
2415  ->SetGroup("Logging");
2416  add("--loglevel", "loglevel", logLevelStr,
2417  QString(
2418  "Set the logging level. All log messages at lower levels will be "
2419  "discarded.\n"
2420  "In descending order: emerg, alert, crit, err, warning, notice, "
2421  "info, debug\ndefaults to ") + logLevelStr, "")
2422  ->SetGroup("Logging");
2423  add("--syslog", "syslog", "none",
2424  "Set the syslog logging facility.\nSet to \"none\" to disable, "
2425  "defaults to none.", "")
2426  ->SetGroup("Logging");
2427 #if CONFIG_SYSTEMD_JOURNAL
2428  add("--systemd-journal", "systemd-journal", "false",
2429  "Use systemd-journal instead of syslog.", "")
2430  ->SetBlocks(QStringList()
2431  << "syslog"
2432  )
2433  ->SetGroup("Logging");
2434 #endif
2435  add("--nodblog", "nodblog", false, "Disable database logging.", "")
2436  ->SetGroup("Logging")
2437  ->SetDeprecated("this is now the default, see --enable-dblog");
2438  add("--enable-dblog", "enabledblog", false, "Enable logging to database.", "")
2439  ->SetGroup("Logging");
2440 
2441  add(QStringList{"-l", "--logfile"},
2442  "logfile", "", "", "")
2443  ->SetGroup("Logging")
2444  ->SetRemoved("This option has been removed as part of "
2445  "rewrite of the logging interface. Please update your init "
2446  "scripts to use --syslog to interface with your system's "
2447  "existing system logging daemon, or --logpath to specify a "
2448  "dirctory for MythTV to write its logs to.", "0.25");
2449 }
2450 
2454 {
2455  add(QStringList{"-p", "--pidfile"}, "pidfile", "",
2456  "Write PID of application to filename.",
2457  "Write the PID of the currently running process as a single "
2458  "line to this file. Used for init scripts to know what "
2459  "process to terminate, and with log rotators "
2460  "to send a HUP signal to process to have it re-open files.");
2461 }
2462 
2466 {
2467  add(QStringList{"-j", "--jobid"}, "jobid", 0, "",
2468  "Intended for internal use only, specify the JobID to match "
2469  "up with in the database for additional information and the "
2470  "ability to update runtime status in the database.");
2471 }
2472 
2476 {
2477  add("--infile", "infile", "", "Input file URI", "");
2478  if (addOutFile)
2479  add("--outfile", "outfile", "", "Output file URI", "");
2480 }
2481 
2485 {
2486 #ifdef USING_X11
2487  add(QStringList{"-display", "--display"}, "display", "",
2488  "Qt (QPA) X11 connection name when using xcb (X11) platform plugin", "")
2489  ->SetGroup("Qt");
2490 #endif
2491 }
2492 
2496 {
2497  add(QStringList{"-platform", "--platform"}, "platform", "", "Qt (QPA) platform argument",
2498  "Qt platform argument that is passed through to Qt")
2499  ->SetGroup("Qt");;
2500 }
2501 
2505 {
2506  QString logfile = toString("logpath");
2507  pid_t pid = getpid();
2508 
2509  if (logfile.isEmpty())
2510  return logfile;
2511 
2512  QFileInfo finfo(logfile);
2513  if (!finfo.isDir())
2514  {
2515  LOG(VB_GENERAL, LOG_ERR,
2516  QString("%1 is not a directory, disabling logfiles")
2517  .arg(logfile));
2518  return QString();
2519  }
2520 
2521  QString logdir = finfo.filePath();
2522  logfile = QCoreApplication::applicationName() + "." +
2524  QString(".%1").arg(pid) + ".log";
2525 
2526  SetValue("logdir", logdir);
2527  SetValue("logfile", logfile);
2528  SetValue("filepath", QFileInfo(QDir(logdir), logfile).filePath());
2529 
2530  return toString("filepath");
2531 }
2532 
2536 {
2537  QString setting = toString("syslog").toLower();
2538  if (setting == "none")
2539  return -2;
2540 
2541  return syslogGetFacility(setting);
2542 }
2543 
2547 {
2548  QString setting = toString("loglevel");
2549  if (setting.isEmpty())
2550  return LOG_INFO;
2551 
2552  LogLevel_t level = logLevelGet(setting);
2553  if (level == LOG_UNKNOWN)
2554  std::cerr << "Unknown log level: " << setting.toLocal8Bit().constData()
2555  << std::endl;
2556 
2557  return level;
2558 }
2559 
2564 bool MythCommandLineParser::SetValue(const QString &key, const QVariant& value)
2565 {
2566  CommandLineArg *arg = nullptr;
2567 
2568  if (!m_namedArgs.contains(key))
2569  {
2570  const QVariant& val(value);
2571  arg = new CommandLineArg(key, val.type(), val);
2572  m_namedArgs.insert(key, arg);
2573  }
2574  else
2575  {
2576  arg = m_namedArgs[key];
2577  if (arg->m_type != value.type())
2578  return false;
2579  }
2580 
2581  arg->Set(value);
2582  return true;
2583 }
2584 
2588 {
2589  int err = 0;
2590 
2591  // Setup the defaults
2592  verboseString = "";
2593  verboseMask = 0;
2594  verboseArgParse(mask);
2595 
2596  if (toBool("verbose"))
2597  {
2598  if ((err = verboseArgParse(toString("verbose"))) != 0)
2599  return err;
2600  }
2601  else if (toBool("verboseint"))
2602  verboseMask = toLongLong("verboseint");
2603 
2604  verboseMask |= VB_STDIO|VB_FLUSH;
2605 
2606  int quiet = toUInt("quiet");
2607  if (std::max(quiet, static_cast<int>(progress)) > 1)
2608  {
2609  verboseMask = VB_NONE|VB_FLUSH;
2610  verboseArgParse("none");
2611  }
2612 
2613  int facility = GetSyslogFacility();
2614 #if CONFIG_SYSTEMD_JOURNAL
2615  bool journal = toBool("systemd-journal");
2616  if (journal)
2617  {
2618  if (facility >= 0)
2620  facility = SYSTEMD_JOURNAL_FACILITY;
2621  }
2622 #endif
2623  bool dblog = toBool("enabledblog");
2624  LogLevel_t level = GetLogLevel();
2625  if (level == LOG_UNKNOWN)
2627 
2628  LOG(VB_GENERAL, LOG_CRIT,
2629  QString("%1 version: %2 [%3] www.mythtv.org")
2630  .arg(QCoreApplication::applicationName())
2632  LOG(VB_GENERAL, LOG_CRIT, QString("Qt version: compile: %1, runtime: %2")
2633  .arg(QT_VERSION_STR).arg(qVersion()));
2634  LOG(VB_GENERAL, LOG_INFO, QString("%1 (%2)")
2635  .arg(QSysInfo::prettyProductName()).arg(QSysInfo::currentCpuArchitecture()));
2636  LOG(VB_GENERAL, LOG_NOTICE,
2637  QString("Enabled verbose msgs: %1").arg(verboseString));
2638 
2639  QString logfile = GetLogFilePath();
2640  bool propagate = !logfile.isEmpty();
2641 
2642  if (toBool("daemon"))
2643  quiet = std::max(quiet, 1);
2644 
2645  logStart(logfile, progress, quiet, facility, level, dblog, propagate);
2646  qInstallMessageHandler([](QtMsgType /*unused*/, const QMessageLogContext& /*unused*/, const QString &Msg)
2647  { LOG(VB_GENERAL, LOG_INFO, "Qt: " + Msg); });
2648 
2649  return GENERIC_EXIT_OK;
2650 }
2651 
2657 {
2658  if (m_verbose)
2659  std::cerr << "Applying settings override" << std::endl;
2660 
2661  QMap<QString, QString> override = GetSettingsOverride();
2662  if (!override.empty())
2663  {
2664  QMap<QString, QString>::iterator it;
2665  for (it = override.begin(); it != override.end(); ++it)
2666  {
2667  LOG(VB_GENERAL, LOG_NOTICE,
2668  QString("Setting '%1' being forced to '%2'")
2669  .arg(it.key()).arg(*it));
2670  gCoreContext->OverrideSettingForSession(it.key(), *it);
2671  }
2672  }
2673 }
2674 
2675 bool openPidfile(std::ofstream &pidfs, const QString &pidfile)
2676 {
2677  if (!pidfile.isEmpty())
2678  {
2679  pidfs.open(pidfile.toLatin1().constData());
2680  if (!pidfs)
2681  {
2682  std::cerr << "Could not open pid file: " << ENO_STR << std::endl;
2683  return false;
2684  }
2685  }
2686  return true;
2687 }
2688 
2691 bool setUser(const QString &username)
2692 {
2693  if (username.isEmpty())
2694  return true;
2695 
2696 #ifdef _WIN32
2697  cerr << "--user option is not supported on Windows" << endl;
2698  return false;
2699 #else // ! _WIN32
2700 #if defined(__linux__) || defined(__LINUX__)
2701  // Check the current dumpability of core dumps, which will be disabled
2702  // by setuid, so we can re-enable, if appropriate
2703  int dumpability = prctl(PR_GET_DUMPABLE);
2704 #endif
2705  struct passwd *user_info = getpwnam(username.toLocal8Bit().constData());
2706  const uid_t user_id = geteuid();
2707 
2708  if (user_id && (!user_info || user_id != user_info->pw_uid))
2709  {
2710  std::cerr << "You must be running as root to use the --user switch." << std::endl;
2711  return false;
2712  }
2713  if (user_info && user_id == user_info->pw_uid)
2714  {
2715  LOG(VB_GENERAL, LOG_WARNING,
2716  QString("Already running as '%1'").arg(username));
2717  }
2718  else if (!user_id && user_info)
2719  {
2720  if (setenv("HOME", user_info->pw_dir,1) == -1)
2721  {
2722  std::cerr << "Error setting home directory." << std::endl;
2723  return false;
2724  }
2725  if (setgid(user_info->pw_gid) == -1)
2726  {
2727  std::cerr << "Error setting effective group." << std::endl;
2728  return false;
2729  }
2730  if (initgroups(user_info->pw_name, user_info->pw_gid) == -1)
2731  {
2732  std::cerr << "Error setting groups." << std::endl;
2733  return false;
2734  }
2735  if (setuid(user_info->pw_uid) == -1)
2736  {
2737  std::cerr << "Error setting effective user." << std::endl;
2738  return false;
2739  }
2740 #if defined(__linux__) || defined(__LINUX__)
2741  if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
2742  {
2743  LOG(VB_GENERAL, LOG_WARNING, "Unable to re-enable core file "
2744  "creation. Run without the --user argument to use "
2745  "shell-specified limits.");
2746  }
2747 #endif
2748  }
2749  else
2750  {
2751  std::cerr << QString("Invalid user '%1' specified with --user")
2752  .arg(username).toLocal8Bit().constData() << std::endl;
2753  return false;
2754  }
2755  return true;
2756 #endif // ! _WIN32
2757 }
2758 
2759 
2763 {
2764  std::ofstream pidfs;
2765  if (!openPidfile(pidfs, toString("pidfile")))
2767 
2768  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
2769  LOG(VB_GENERAL, LOG_WARNING, "Unable to ignore SIGPIPE");
2770 
2771 #if CONFIG_DARWIN
2772  if (toBool("daemon"))
2773  {
2774  std::cerr << "Daemonizing is unavailable in OSX" << std::endl;
2775  LOG(VB_GENERAL, LOG_WARNING, "Unable to daemonize");
2776  }
2777 #else
2778  if (toBool("daemon") && (daemon(0, 1) < 0))
2779  {
2780  std::cerr << "Failed to daemonize: " << ENO_STR << std::endl;
2782  }
2783 #endif
2784 
2785  QString username = toString("username");
2786  if (!username.isEmpty() && !setUser(username))
2788 
2789  if (pidfs)
2790  {
2791  pidfs << getpid() << std::endl;
2792  pidfs.close();
2793  }
2794 
2795  return GENERIC_EXIT_OK;
2796 }
force
bool force
Definition: mythtv/programs/mythcommflag/main.cpp:74
MythCommandLineParser::addDisplay
void addDisplay(void)
Canned argument definition for -display.
Definition: mythcommandlineparser.cpp:2484
MythCommandLineParser::addGeometry
void addGeometry(void)
Canned argument definition for –geometry.
Definition: mythcommandlineparser.cpp:2370
setuid
#define setuid(x)
Definition: compat.h:263
strip_quotes
QByteArray strip_quotes(QByteArray val)
Definition: mythcommandlineparser.cpp:105
build_compdb.args
args
Definition: build_compdb.py:11
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
MythCommandLineParser::Result
Result
Definition: mythcommandlineparser.h:120
CommandLineArg::SetChild
CommandLineArg * SetChild(const QString &opt)
Set argument as parent of given child.
Definition: mythcommandlineparser.cpp:609
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
CommandLineArg::SetParent
CommandLineArg * SetParent(const QString &opt)
Set argument as child of given parent.
Definition: mythcommandlineparser.cpp:575
MythCommandLineParser::m_appname
QString m_appname
Definition: mythcommandlineparser.h:309
MythCommandLineParser::operator[]
QVariant operator[](const QString &name)
Returned stored QVariant for given argument, or default value if not used.
Definition: mythcommandlineparser.cpp:1813
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:2260
CommandLineArg::AllowOneOf
static void AllowOneOf(const QList< CommandLineArg * > &args)
Mark a list of arguments as mutually exclusive.
Definition: mythcommandlineparser.cpp:836
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:2163
MythCommandLineParser::Result::kOptVal
@ kOptVal
CommandLineArg::GetKeywordLength
int GetKeywordLength(void) const
Return length of full keyword string for use in determining indent of help text.
Definition: mythcommandlineparser.cpp:236
MythCommandLineParser::m_verbose
bool m_verbose
Definition: mythcommandlineparser.h:314
CommandLineArg::m_keywords
QStringList m_keywords
Definition: mythcommandlineparser.h:102
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:262
MythCommandLineParser::addPlatform
void addPlatform(void)
Pass through the platform argument to Qt for GUI applications.
Definition: mythcommandlineparser.cpp:2495
MythCommandLineParser::~MythCommandLineParser
~MythCommandLineParser()
Definition: mythcommandlineparser.cpp:1177
MythCommandLineParser::Result::kPassthrough
@ kPassthrough
MythCoreContext::OverrideSettingForSession
void OverrideSettingForSession(const QString &key, const QString &value)
Definition: mythcorecontext.cpp:1342
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:2046
progress
bool progress
Definition: mythtv/programs/mythcommflag/main.cpp:73
CommandLineArg::m_removedversion
QString m_removedversion
Definition: mythcommandlineparser.h:97
MythCommandLineParser::addPIDFile
void addPIDFile(void)
Canned argument definition for –pidfile.
Definition: mythcommandlineparser.cpp:2453
CommandLineArg::PrintVerbose
void PrintVerbose(void) const
Internal use.
Definition: mythcommandlineparser.cpp:1036
logStart
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool dblog, bool propagate, bool testHarness)
Entry point to start logging for the application.
Definition: logging.cpp:703
syslogGetFacility
int syslogGetFacility(const QString &facility)
Map a syslog facility name back to the enumerated value.
Definition: logging.cpp:790
setenv
#define setenv(x, y, z)
Definition: compat.h:157
MythCommandLineParser::addVersion
void addVersion(void)
Canned argument definition for –version.
Definition: mythcommandlineparser.cpp:2290
arg
arg(title).arg(filename).arg(doDelete))
CommandLineArg::m_removed
QString m_removed
Definition: mythcommandlineparser.h:96
CommandLineArg::SetRequires
CommandLineArg * SetRequires(const QString &opt)
Set argument as requiring given option.
Definition: mythcommandlineparser.cpp:668
MythCommandLineParser::ReconcileLinks
bool ReconcileLinks(void)
Replace dummy arguments used to define interdependency with pointers to their real counterparts.
Definition: mythcommandlineparser.cpp:1656
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
CommandLineArg::m_default
QVariant m_default
Definition: mythcommandlineparser.h:99
MythCommandLineParser::m_overridesImported
bool m_overridesImported
Definition: mythcommandlineparser.h:313
MythCommandLineParser::addWindowed
void addWindowed(void)
Canned argument definition for –windowed and -no-windowed.
Definition: mythcommandlineparser.cpp:2300
GENERIC_EXIT_INVALID_CMDLINE
#define GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:15
CommandLineArg::SetRequiredChild
CommandLineArg * SetRequiredChild(const QString &opt)
Set argument as parent of given child and mark as required.
Definition: mythcommandlineparser.cpp:626
MythCommandLineParser::m_optionedArgs
QMap< QString, CommandLineArg * > m_optionedArgs
Definition: mythcommandlineparser.h:310
MythCommandLineParser::m_namedArgs
QMap< QString, CommandLineArg * > m_namedArgs
Definition: mythcommandlineparser.h:311
MythCommandLineParser::GetHelpString
QString GetHelpString(void) const
Generate command line option help text.
Definition: mythcommandlineparser.cpp:1292
CommandLineArg::m_parents
QList< CommandLineArg * > m_parents
Definition: mythcommandlineparser.h:105
MythCommandLineParser::addRecording
void addRecording(void)
Canned argument definition for –chanid and –starttime.
Definition: mythcommandlineparser.cpp:2357
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
MythCommandLineParser::Result::kArg
@ kArg
openPidfile
bool openPidfile(std::ofstream &pidfs, const QString &pidfile)
Definition: mythcommandlineparser.cpp:2675
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
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:2387
mythversion.h
CommandLineArg::GetLongHelpString
QString GetLongHelpString(QString keyword) const
Return string containing extended help text.
Definition: mythcommandlineparser.cpp:336
CommandLineArg::SetRemoved
CommandLineArg * SetRemoved(QString remstr="", QString remver="")
Set option as removed.
Definition: mythcommandlineparser.cpp:712
CommandLineArg::m_stored
QVariant m_stored
Definition: mythcommandlineparser.h:100
CommandLineArg::SetParentOf
CommandLineArg * SetParentOf(const QString &opt)
Set argument as parent of given child.
Definition: mythcommandlineparser.cpp:558
CommandLineArg::m_blocks
QList< CommandLineArg * > m_blocks
Definition: mythcommandlineparser.h:109
verboseString
QString verboseString
Definition: logging.cpp:103
CommandLineArg::SetChildOf
CommandLineArg * SetChildOf(const QString &opt)
Set argument as child of given parent.
Definition: mythcommandlineparser.cpp:592
MythCommandLineParser::Parse
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
Definition: mythcommandlineparser.cpp:1437
wrapList
void wrapList(QStringList &list, int width)
Definition: mythmiscutil.cpp:957
mythdate.h
CommandLineArg::m_given
bool m_given
Definition: mythcommandlineparser.h:91
MythCommandLineParser::addMouse
void addMouse(void)
Canned argument definition for –mouse-cursor and –no-mouse-cursor.
Definition: mythcommandlineparser.cpp:2315
mythlogging.h
logLevelGetName
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
Definition: logging.cpp:840
CommandLineArg::m_deprecated
QString m_deprecated
Definition: mythcommandlineparser.h:95
MythDate::kFilename
@ kFilename
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:15
MythCommandLineParser::getOpt
Result getOpt(int argc, const char *const *argv, int &argpos, QString &opt, QByteArray &val)
Internal use.
Definition: mythcommandlineparser.cpp:1356
setUser
bool setUser(const QString &username)
Drop permissions to the specified user.
Definition: mythcommandlineparser.cpp:2691
MythCommandLineParser::Result::kInvalid
@ kInvalid
logfile
QString logfile
Definition: backendcontext.cpp:14
verboseMask
uint64_t verboseMask
Definition: logging.cpp:102
daemon
#define daemon(x, y)
Definition: compat.h:322
CommandLineArg::m_longhelp
QString m_longhelp
Definition: mythcommandlineparser.h:112
CommandLineArg::m_help
QString m_help
Definition: mythcommandlineparser.h:111
MythCommandLineParser::MythCommandLineParser
MythCommandLineParser(QString appname)
Default constructor for MythCommandLineArg class.
Definition: mythcommandlineparser.cpp:1165
logLevelGet
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
Definition: logging.cpp:818
ENO_STR
#define ENO_STR
Definition: mythlogging.h:73
CommandLineArg::SetRequiredChildOf
CommandLineArg * SetRequiredChildOf(const QString &opt)
Set argument as child required by given parent.
Definition: mythcommandlineparser.cpp:647
CommandLineArg::Set
bool Set(const QString &opt)
Set option as provided on command line with no value.
Definition: mythcommandlineparser.cpp:442
MythCommandLineParser::GetArgs
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
Definition: mythcommandlineparser.cpp:1832
MythCommandLineParser::m_passthroughActive
bool m_passthroughActive
Definition: mythcommandlineparser.h:312
SIGPIPE
#define SIGPIPE
Definition: compat.h:219
MythCommandLineParser::PrintVersion
static void PrintVersion(void)
Print application version information.
Definition: mythcommandlineparser.cpp:1265
CommandLineArg::GetName
QString GetName(void) const
Definition: mythcommandlineparser.h:33
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:637
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:1840
CommandLineArg::PrintDeprecatedWarning
void PrintDeprecatedWarning(QString &keyword) const
Internal use.
Definition: mythcommandlineparser.cpp:1142
CommandLineArg::m_type
QVariant::Type m_type
Definition: mythcommandlineparser.h:98
MythCommandLineParser::toUInt
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:1992
CommandLineArg::m_requires
QList< CommandLineArg * > m_requires
Definition: mythcommandlineparser.h:107
f
QTextStream t & f
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:603
MythCommandLineParser::PrintHelp
void PrintHelp(void) const
Print command line option help.
Definition: mythcommandlineparser.cpp:1281
MythCommandLineParser::Daemonize
int Daemonize(void) const
Fork application into background, and detatch from terminal.
Definition: mythcommandlineparser.cpp:2762
quiet
int quiet
Definition: mythtv/programs/mythcommflag/main.cpp:72
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
pidfile
QString pidfile
Definition: backendcontext.cpp:13
GENERIC_EXIT_PERMISSIONS_ERROR
#define GENERIC_EXIT_PERMISSIONS_ERROR
File permissions error.
Definition: exitcodes.h:19
MythCommandLineParser::GetSyslogFacility
int GetSyslogFacility(void) const
Helper utility for logging interface to return syslog facility.
Definition: mythcommandlineparser.cpp:2535
MythCommandLineParser::ApplySettingsOverride
void ApplySettingsOverride(void)
Apply all overrides to the global context.
Definition: mythcommandlineparser.cpp:2656
QT_ENDL
#define QT_ENDL
Definition: mythcommandlineparser.cpp:68
MythCommandLineParser::GetSettingsOverride
QMap< QString, QString > GetSettingsOverride(void)
Return map of key/value pairs provided to override database options.
Definition: mythcommandlineparser.cpp:1859
CommandLineArg::GetPreferredKeyword
QString GetPreferredKeyword(void) const
Return the longest keyword for the argument.
Definition: mythcommandlineparser.cpp:921
GetMythSourcePath
const char * GetMythSourcePath()
Definition: mythcoreutil.cpp:318
CommandLineArg::TestLinks
bool TestLinks(void) const
Test all related arguments to make sure specified requirements are fulfilled.
Definition: mythcommandlineparser.cpp:943
CommandLineArg::SetBlocks
CommandLineArg * SetBlocks(const QString &opt)
Set argument as incompatible with given option.
Definition: mythcommandlineparser.cpp:685
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
nv_python_libs.vimeo.vimeo_api.user_info
def user_info(user, format="xml")
Definition: vimeo_api.py:515
verboseArgParse
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
Definition: logging.cpp:966
CommandLineArg::CleanupLinks
void CleanupLinks(void)
Clear out references to other arguments in preparation for deletion.
Definition: mythcommandlineparser.cpp:1015
TERMWIDTH
#define TERMWIDTH
Definition: mythcommandlineparser.cpp:81
CommandLineArg::m_usedKeyword
QString m_usedKeyword
Definition: mythcommandlineparser.h:103
MYTH_BINARY_VERSION
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:15
CommandLineArg::PrintRemovedWarning
void PrintRemovedWarning(QString &keyword) const
Internal use.
Definition: mythcommandlineparser.cpp:1126
MythCommandLineParser::allowArgs
void allowArgs(bool allow=true)
Specify that parser should allow and collect values provided independent of any keyword.
Definition: mythcommandlineparser.cpp:2224
MYTH_PROTO_VERSION
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:47
CommandLineArg::m_requiredby
QList< CommandLineArg * > m_requiredby
Definition: mythcommandlineparser.h:108
mythmiscutil.h
MythCommandLineParser::add
CommandLineArg * add(const QString &arg, const QString &name, bool def, QString help, QString longhelp)
Definition: mythcommandlineparser.h:145
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2100
CommandLineArg::m_group
QString m_group
Definition: mythcommandlineparser.h:94
CommandLineArg::m_name
QString m_name
Definition: mythcommandlineparser.h:93
mythcorecontext.h
MythCommandLineParser::addHelp
void addHelp(void)
Canned argument definition for –help.
Definition: mythcommandlineparser.cpp:2277
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:2564
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:1943
MythCommandLineParser::GetLogLevel
LogLevel_t GetLogLevel(void) const
Helper utility for logging interface to filtering level.
Definition: mythcommandlineparser.cpp:2546
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:2019
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:14
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:2131
MythCommandLineParser::NamedOptType
static const char * NamedOptType(Result type)
Definition: mythcommandlineparser.cpp:117
logging.h
CommandLineArg::SetGroup
CommandLineArg * SetGroup(const QString &group)
Definition: mythcommandlineparser.h:29
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:2465
GENERIC_EXIT_DAEMONIZING_ERROR
#define GENERIC_EXIT_DAEMONIZING_ERROR
Error daemonizing or execl.
Definition: exitcodes.h:28
MythCommandLineParser::toSize
QSize toSize(const QString &key) const
Returns stored QVariant as a QSize value, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2073
MythCommandLineParser::GetLogFilePath
QString GetLogFilePath(void)
Helper utility for logging interface to pull path from –logpath.
Definition: mythcommandlineparser.cpp:2504
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythcoreutil.cpp:313
CommandLineArg::m_converted
bool m_converted
Definition: mythcommandlineparser.h:92
MythCommandLineParser::ConfigureLogging
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
Definition: mythcommandlineparser.cpp:2587
MythCommandLineParser::addSettingsOverride
void addSettingsOverride(void)
Canned argument definition for –override-setting and –override-settings-file.
Definition: mythcommandlineparser.cpp:2341
CommandLineArg::SetDeprecated
CommandLineArg * SetDeprecated(QString depstr="")
Set option as deprecated.
Definition: mythcommandlineparser.cpp:702
MythCommandLineParser::GetHelpHeader
virtual QString GetHelpHeader(void) const
Definition: mythcommandlineparser.h:138
MythCommandLineParser::LoadArguments
virtual void LoadArguments(void)
Definition: mythcommandlineparser.h:134
CommandLineArg::CommandLineArg
CommandLineArg(const QString &name, QVariant::Type type, QVariant def, QString help, QString longhelp)
Default constructor for CommandLineArg class.
Definition: mythcommandlineparser.cpp:184
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:2241
MythCommandLineParser::addUPnP
void addUPnP(void)
Canned argument definition for –noupnp.
Definition: mythcommandlineparser.cpp:2379
MythCommandLineParser::addDaemon
void addDaemon(void)
Canned argument definition for –daemon.
Definition: mythcommandlineparser.cpp:2329
geteuid
#define geteuid()
Definition: compat.h:262
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:1965
CommandLineArg::m_children
QList< CommandLineArg * > m_children
Definition: mythcommandlineparser.h:106
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
mythcommandlineparser.h
MythCommandLineParser::GetPassthrough
QString GetPassthrough(void) const
Return any text supplied on the command line after a bare '–'.
Definition: mythcommandlineparser.cpp:1847
MythCommandLineParser::Result::kEnd
@ kEnd
MythCommandLineParser::Result::kCombOptVal
@ kCombOptVal
GetTermWidth
int GetTermWidth(void)
returns terminal width, or 79 on error
Definition: mythcommandlineparser.cpp:91
MythCommandLineParser::toDateTime
QDateTime toDateTime(const QString &key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2197
MythCommandLineParser::addInFile
void addInFile(bool addOutFile=false)
Canned argument definition for –infile and –outfile.
Definition: mythcommandlineparser.cpp:2475
CommandLineArg::Convert
void Convert(void)
Convert stored string value from QByteArray to QString.
Definition: mythcommandlineparser.cpp:864
ReferenceCounter
General purpose reference counter.
Definition: referencecounter.h:27
CommandLineArg::GetKeywordString
QString GetKeywordString(void) const
Return string containing all possible keyword triggers for this argument.
Definition: mythcommandlineparser.cpp:226