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