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 
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(std::move(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(std::move(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(std::move(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(std::move(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(std::move(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(std::move(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  int i;
717  bool replaced = false;
718  other->IncrRef();
719 
720  for (i = 0; i < m_children.size(); i++)
721  {
722  if (m_children[i]->m_name == other->m_name)
723  {
724  m_children[i]->DecrRef();
725  m_children.replace(i, other);
726  replaced = true;
727  break;
728  }
729  }
730 
731  if (!replaced)
732  m_children << other;
733 
734  if (forward)
735  other->SetChildOf(this, false);
736 }
737 
743 void CommandLineArg::SetChildOf(CommandLineArg *other, bool forward)
744 {
745  int i;
746  bool replaced = false;
747  other->IncrRef();
748 
749  for (i = 0; i < m_parents.size(); i++)
750  {
751  if (m_parents[i]->m_name == other->m_name)
752  {
753  m_parents[i]->DecrRef();
754  m_parents.replace(i, other);
755  replaced = true;
756  break;
757  }
758  }
759 
760  if (!replaced)
761  m_parents << other;
762 
763  if (forward)
764  other->SetParentOf(this, false);
765 }
766 
772 void CommandLineArg::SetRequires(CommandLineArg *other, bool /*forward*/)
773 {
774  int i;
775  bool replaced = false;
776  other->IncrRef();
777 
778  for (i = 0; i < m_requires.size(); i++)
779  {
780  if (m_requires[i]->m_name == other->m_name)
781  {
782  m_requires[i]->DecrRef();
783  m_requires.replace(i, other);
784  replaced = true;
785  break;
786  }
787  }
788 
789  if (!replaced)
790  m_requires << other;
791 
792 // requirements need not be reciprocal
793 // if (forward)
794 // other->SetRequires(this, false);
795 }
796 
802 void CommandLineArg::SetBlocks(CommandLineArg *other, bool forward)
803 {
804  int i;
805  bool replaced = false;
806  other->IncrRef();
807 
808  for (i = 0; i < m_blocks.size(); i++)
809  {
810  if (m_blocks[i]->m_name == other->m_name)
811  {
812  m_blocks[i]->DecrRef();
813  m_blocks.replace(i, other);
814  replaced = true;
815  break;
816  }
817  }
818 
819  if (!replaced)
820  m_blocks << other;
821 
822  if (forward)
823  other->SetBlocks(this, false);
824 }
825 
828 void CommandLineArg::AllowOneOf(QList<CommandLineArg*> args)
829 {
830  // TODO: blocks do not get set properly if multiple dummy arguments
831  // are provided. since this method will not have access to the
832  // argument list, this issue will have to be resolved later in
833  // ReconcileLinks().
834  QList<CommandLineArg*>::const_iterator i1,i2;
835 
836  // loop through all but the last entry
837  for (i1 = args.begin(); i1 != args.end()-1; ++i1)
838  {
839  // loop through the next to the last entry
840  // and block use with the current
841  for (i2 = i1+1; i2 != args.end(); ++i2)
842  {
843  (*i1)->SetBlocks(*i2);
844  }
845 
846  if ((*i1)->m_type == QVariant::Invalid)
847  (*i1)->DecrRef();
848  }
849 }
850 
858 {
859  if (!QCoreApplication::instance())
860  // QApplication not available, no sense doing anything yet
861  return;
862 
863  if (m_converted)
864  // already run, abort
865  return;
866 
867  if (!m_given)
868  {
869  // nothing to work on, abort
870  m_converted = true;
871  return;
872  }
873 
874  if (m_type == QVariant::String)
875  {
876  if (m_stored.type() == QVariant::ByteArray)
877  {
878  m_stored = QString::fromLocal8Bit(m_stored.toByteArray());
879  }
880  // else
881  // not sure why this isnt a bytearray, but ignore it and
882  // set it as converted
883  }
884  else if (m_type == QVariant::StringList)
885  {
886  if (m_stored.type() == QVariant::List)
887  {
888  QVariantList vlist = m_stored.toList();
889  QVariantList::const_iterator iter = vlist.begin();
890  QStringList slist;
891  for (; iter != vlist.end(); ++iter)
892  slist << QString::fromLocal8Bit(iter->toByteArray());
893  m_stored = QVariant(slist);
894  }
895  }
896  else if (m_type == QVariant::Map)
897  {
898  QVariantMap vmap = m_stored.toMap();
899  QVariantMap::iterator iter = vmap.begin();
900  for (; iter != vmap.end(); ++iter)
901  (*iter) = QString::fromLocal8Bit(iter->toByteArray());
902  }
903  else
904  return;
905 
906  m_converted = true;
907 }
908 
909 
916 {
917  QStringList::const_iterator it;
918  QString preferred;
919  int len = 0, len2;
920 
921  for (it = m_keywords.constBegin(); it != m_keywords.constEnd(); ++it)
922  {
923  len2 = (*it).size();
924  if (len2 > len)
925  {
926  preferred = *it;
927  len = len2;
928  }
929  }
930 
931  return preferred;
932 }
933 
938 {
939  if (!m_given)
940  return true; // not in use, no need for checks
941 
942  QList<CommandLineArg*>::const_iterator i;
943 
944  bool passes = false;
945  for (i = m_parents.constBegin(); i != m_parents.constEnd(); ++i)
946  {
947  // one of these must have been defined
948  if ((*i)->m_given)
949  {
950  passes = true;
951  break;
952  }
953  }
954  if (!passes && !m_parents.isEmpty())
955  {
956  cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
957  << " requires at least one of the following arguments" << endl;
958  for (i = m_parents.constBegin(); i != m_parents.constEnd(); ++i)
959  cerr << " "
960  << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
961  cerr << endl << endl;
962  return false;
963  }
964 
965  // we dont care about children
966 
967  for (i = m_requires.constBegin(); i != m_requires.constEnd(); ++i)
968  {
969  // all of these must have been defined
970  if (!(*i)->m_given)
971  {
972  cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
973  << " requires all of the following be defined as well"
974  << endl;
975  for (i = m_requires.constBegin(); i != m_requires.constEnd(); ++i)
976  cerr << " "
977  << (*i)->GetPreferredKeyword().toLocal8Bit()
978  .constData();
979  cerr << endl << endl;
980  return false;
981  }
982  }
983 
984  for (i = m_blocks.constBegin(); i != m_blocks.constEnd(); ++i)
985  {
986  // none of these can be defined
987  if ((*i)->m_given)
988  {
989  cerr << "ERROR: " << m_usedKeyword.toLocal8Bit().constData()
990  << " requires that none of the following be defined" << endl;
991  for (i = m_blocks.constBegin(); i != m_blocks.constEnd(); ++i)
992  cerr << " "
993  << (*i)->GetPreferredKeyword().toLocal8Bit()
994  .constData();
995  cerr << endl << endl;
996  return false;
997  }
998  }
999 
1000  return true;
1001 }
1002 
1006 {
1007  // clear out interdependent pointers in preparation for deletion
1008  while (!m_parents.isEmpty())
1009  m_parents.takeFirst()->DecrRef();
1010 
1011  while (!m_children.isEmpty())
1012  m_children.takeFirst()->DecrRef();
1013 
1014  while (!m_blocks.isEmpty())
1015  m_blocks.takeFirst()->DecrRef();
1016 
1017  while (!m_requires.isEmpty())
1018  m_requires.takeFirst()->DecrRef();
1019 
1020  while (!m_requiredby.isEmpty())
1021  m_requiredby.takeFirst()->DecrRef();
1022 }
1023 
1027 {
1028  if (!m_given)
1029  return;
1030 
1031  cerr << " " << m_name.leftJustified(30).toLocal8Bit().constData();
1032 
1033  QSize tmpsize;
1034  QMap<QString, QVariant> tmpmap;
1035  QMap<QString, QVariant>::const_iterator it;
1036  QVariantList vlist;
1037  QVariantList::const_iterator it2;
1038  bool first;
1039 
1040  switch (m_type)
1041  {
1042  case QVariant::Bool:
1043  cerr << (m_stored.toBool() ? "True" : "False") << endl;
1044  break;
1045 
1046  case QVariant::Int:
1047  cerr << m_stored.toInt() << endl;
1048  break;
1049 
1050  case QVariant::UInt:
1051  cerr << m_stored.toUInt() << endl;
1052  break;
1053 
1054  case QVariant::LongLong:
1055  cerr << m_stored.toLongLong() << endl;
1056  break;
1057 
1058  case QVariant::Double:
1059  cerr << m_stored.toDouble() << endl;
1060  break;
1061 
1062  case QVariant::Size:
1063  tmpsize = m_stored.toSize();
1064  cerr << "x=" << tmpsize.width()
1065  << " y=" << tmpsize.height()
1066  << endl;
1067  break;
1068 
1069  case QVariant::String:
1070  cerr << '"' << m_stored.toByteArray().constData()
1071  << '"' << endl;
1072  break;
1073 
1074  case QVariant::StringList:
1075  vlist = m_stored.toList();
1076  it2 = vlist.begin();
1077  cerr << '"' << it2->toByteArray().constData() << '"';
1078  ++it2;
1079  for (; it2 != vlist.end(); ++it2)
1080  cerr << ", \""
1081  << it2->constData()
1082  << '"';
1083  cerr << endl;
1084  break;
1085 
1086  case QVariant::Map:
1087  tmpmap = m_stored.toMap();
1088  first = true;
1089 
1090  for (it = tmpmap.begin(); it != tmpmap.end(); ++it)
1091  {
1092  if (first)
1093  first = false;
1094  else
1095  cerr << QString("").leftJustified(32)
1096  .toLocal8Bit().constData();
1097 
1098  cerr << it.key().toLocal8Bit().constData()
1099  << '='
1100  << it->toByteArray().constData()
1101  << endl;
1102  }
1103 
1104  break;
1105 
1106  case QVariant::DateTime:
1107  cerr << m_stored.toDateTime().toString(Qt::ISODate)
1108  .toLocal8Bit().constData()
1109  << endl;
1110  break;
1111 
1112  default:
1113  cerr << endl;
1114  }
1115 }
1116 
1119 void CommandLineArg::PrintRemovedWarning(QString &keyword) const
1120 {
1121  QString warn = QString("%1 has been removed").arg(keyword);
1122  if (!m_removedversion.isEmpty())
1123  warn += QString(" as of MythTV %1").arg(m_removedversion);
1124 
1125  cerr << QString("****************************************************\n"
1126  " WARNING: %1\n"
1127  " %2\n"
1128  "****************************************************\n\n")
1129  .arg(warn).arg(m_removed)
1130  .toLocal8Bit().constData();
1131 }
1132 
1135 void CommandLineArg::PrintDeprecatedWarning(QString &keyword) const
1136 {
1137  cerr << QString("****************************************************\n"
1138  " WARNING: %1 has been deprecated\n"
1139  " %2\n"
1140  "****************************************************\n\n")
1141  .arg(keyword).arg(m_deprecated)
1142  .toLocal8Bit().constData();
1143 }
1144 
1159  m_appname(std::move(appname))
1160 {
1161  char *verbose = getenv("VERBOSE_PARSER");
1162  if (verbose != nullptr)
1163  {
1164  cerr << "MythCommandLineParser is now operating verbosely." << endl;
1165  m_verbose = true;
1166  }
1167 
1169 }
1170 
1172 {
1173  QMap<QString, CommandLineArg*>::iterator i;
1174 
1175  i = m_namedArgs.begin();
1176  while (i != m_namedArgs.end())
1177  {
1178  (*i)->CleanupLinks();
1179  (*i)->DecrRef();
1180  i = m_namedArgs.erase(i);
1181  }
1182 
1183  i = m_optionedArgs.begin();
1184  while (i != m_optionedArgs.end())
1185  {
1186  (*i)->DecrRef();
1187  i = m_optionedArgs.erase(i);
1188  }
1189 }
1190 
1225  const QString& name, QVariant::Type type, QVariant def,
1226  QString help, QString longhelp)
1227 {
1228  CommandLineArg *arg;
1229 
1230  if (m_namedArgs.contains(name))
1231  arg = m_namedArgs[name];
1232  else
1233  {
1234  arg = new CommandLineArg(name, type, std::move(def), std::move(help), std::move(longhelp));
1235  m_namedArgs.insert(name, arg);
1236  }
1237 
1238  QStringList::const_iterator i;
1239  for (i = arglist.begin(); i != arglist.end(); ++i)
1240  {
1241  if (!m_optionedArgs.contains(*i))
1242  {
1243  arg->AddKeyword(*i);
1244  if (m_verbose)
1245  cerr << "Adding " << (*i).toLocal8Bit().constData()
1246  << " as taking type '" << QVariant::typeToName(type)
1247  << "'" << endl;
1248  arg->IncrRef();
1249  m_optionedArgs.insert(*i, arg);
1250  }
1251  }
1252 
1253  return arg;
1254 }
1255 
1259 {
1260  cout << "Please attach all output as a file in bug reports." << endl;
1261  cout << "MythTV Version : " << MYTH_SOURCE_VERSION << endl;
1262  cout << "MythTV Branch : " << MYTH_SOURCE_PATH << endl;
1263  cout << "Network Protocol : " << MYTH_PROTO_VERSION << endl;
1264  cout << "Library API : " << MYTH_BINARY_VERSION << endl;
1265  cout << "QT Version : " << QT_VERSION_STR << endl;
1266 #ifdef MYTH_BUILD_CONFIG
1267  cout << "Options compiled in:" <<endl;
1268  cout << MYTH_BUILD_CONFIG << endl;
1269 #endif
1270 }
1271 
1275 {
1276  QString help = GetHelpString();
1277  cerr << help.toLocal8Bit().constData();
1278 }
1279 
1286 {
1287  QString helpstr;
1288  QTextStream msg(&helpstr, QIODevice::WriteOnly);
1289 
1290  QString versionStr = QString("%1 version: %2 [%3] www.mythtv.org")
1291  .arg(m_appname).arg(MYTH_SOURCE_PATH).arg(MYTH_SOURCE_VERSION);
1292  msg << versionStr << endl;
1293 
1294  if (toString("showhelp").isEmpty())
1295  {
1296  // build generic help text
1297 
1298  QString descr = GetHelpHeader();
1299  if (descr.size() > 0)
1300  msg << endl << descr << endl << endl;
1301 
1302  // loop through registered arguments to populate list of groups
1303  QStringList groups("");
1304  int maxlen = 0;
1305  QMap<QString, CommandLineArg*>::const_iterator i1;
1306  for (i1 = m_namedArgs.begin(); i1 != m_namedArgs.end(); ++i1)
1307  {
1308  maxlen = max((*i1)->GetKeywordLength(), maxlen);
1309  if (!groups.contains((*i1)->m_group))
1310  groups << (*i1)->m_group;
1311  }
1312 
1313  // loop through list of groups and print help string for each
1314  // arguments will filter themselves if they are not in the group
1315  maxlen += 4;
1316  QStringList::const_iterator i2;
1317  for (i2 = groups.begin(); i2 != groups.end(); ++i2)
1318  {
1319  if ((*i2).isEmpty())
1320  msg << "Misc. Options:" << endl;
1321  else
1322  msg << (*i2).toLocal8Bit().constData() << " Options:" << endl;
1323 
1324  for (i1 = m_namedArgs.begin(); i1 != m_namedArgs.end(); ++i1)
1325  msg << (*i1)->GetHelpString(maxlen, *i2);
1326  msg << endl;
1327  }
1328  }
1329  else
1330  {
1331  // build help for a specific argument
1332  QString optstr = "-" + toString("showhelp");
1333  if (!m_optionedArgs.contains(optstr))
1334  {
1335  optstr = "-" + optstr;
1336  if (!m_optionedArgs.contains(optstr))
1337  return QString("Could not find option matching '%1'\n")
1338  .arg(toString("showhelp"));
1339  }
1340 
1341  msg << m_optionedArgs[optstr]->GetLongHelpString(optstr);
1342  }
1343 
1344  msg.flush();
1345  return helpstr;
1346 }
1347 
1350 int MythCommandLineParser::getOpt(int argc, const char * const * argv,
1351  int &argpos, QString &opt, QByteArray &val)
1352 {
1353  opt.clear();
1354  val.clear();
1355 
1356  if (argpos >= argc)
1357  // this shouldnt happen, return and exit
1358  return kEnd;
1359 
1360  QByteArray tmp(argv[argpos]);
1361  if (tmp.isEmpty())
1362  // string is empty, return and loop
1363  return kEmpty;
1364 
1365  if (m_passthroughActive)
1366  {
1367  // pass through has been activated
1368  val = tmp;
1369  return kArg;
1370  }
1371 
1372  if (tmp.startsWith('-') && tmp.size() > 1)
1373  {
1374  if (tmp == "--")
1375  {
1376  // all options beyond this will be passed as a single string
1377  m_passthroughActive = true;
1378  return kPassthrough;
1379  }
1380 
1381  if (tmp.contains('='))
1382  {
1383  // option contains '=', split
1384  QList<QByteArray> blist = tmp.split('=');
1385 
1386  if (blist.size() != 2)
1387  {
1388  // more than one '=' in option, this is not handled
1389  opt = QString(tmp);
1390  return kInvalid;
1391  }
1392 
1393  opt = QString(blist[0]);
1394  val = blist[1];
1395  return kCombOptVal;
1396  }
1397 
1398  opt = QString(tmp);
1399 
1400  if (argpos+1 >= argc)
1401  // end of input, option only
1402  return kOptOnly;
1403 
1404  tmp = QByteArray(argv[++argpos]);
1405  if (tmp.isEmpty())
1406  // empty string, option only
1407  return kOptOnly;
1408 
1409  if (tmp.startsWith("-") && tmp.size() > 1)
1410  {
1411  // no value found for option, backtrack
1412  argpos--;
1413  return kOptOnly;
1414  }
1415 
1416  val = tmp;
1417  return kOptVal;
1418  }
1419 
1420  // input is not an option string, return as arg
1421  val = tmp;
1422  return kArg;
1423 }
1424 
1431 bool MythCommandLineParser::Parse(int argc, const char * const * argv)
1432 {
1433  int res;
1434  QString opt;
1435  QByteArray val;
1436  CommandLineArg *argdef;
1437 
1438  // reconnect interdependencies between command line options
1439  if (!ReconcileLinks())
1440  return false;
1441 
1442  // loop through command line arguments until all are spent
1443  for (int argpos = 1; argpos < argc; ++argpos)
1444  {
1445 
1446  // pull next option
1447  res = getOpt(argc, argv, argpos, opt, val);
1448 
1449  if (m_verbose)
1450  cerr << "res: " << NamedOptType(res) << endl
1451  << "opt: " << opt.toLocal8Bit().constData() << endl
1452  << "val: " << val.constData() << endl << endl;
1453 
1454  // '--' found on command line, enable passthrough mode
1455  if (res == kPassthrough && !m_namedArgs.contains("_passthrough"))
1456  {
1457  cerr << "Received '--' but passthrough has not been enabled" << endl;
1458  SetValue("showhelp", "");
1459  return false;
1460  }
1461 
1462  // end of options found, terminate loop
1463  if (res == kEnd)
1464  break;
1465 
1466  // GetOpt pulled an empty option, this shouldnt happen by ignore
1467  // it and continue
1468  if (res == kEmpty)
1469  continue;
1470 
1471  // more than one equal found in key/value pair, fault out
1472  if (res == kInvalid)
1473  {
1474  cerr << "Invalid option received:" << endl << " "
1475  << opt.toLocal8Bit().constData();
1476  SetValue("showhelp", "");
1477  return false;
1478  }
1479 
1480  // passthrough is active, so add the data to the stringlist
1481  if (m_passthroughActive)
1482  {
1483  m_namedArgs["_passthrough"]->Set("", val);
1484  continue;
1485  }
1486 
1487  // argument with no preceeding '-' encountered, add to stringlist
1488  if (res == kArg)
1489  {
1490  if (!m_namedArgs.contains("_args"))
1491  {
1492  cerr << "Received '"
1493  << val.constData()
1494  << "' but unassociated arguments have not been enabled"
1495  << endl;
1496  SetValue("showhelp", "");
1497  return false;
1498  }
1499 
1500  m_namedArgs["_args"]->Set("", val);
1501  continue;
1502  }
1503 
1504  // this line should not be passed once arguments have started collecting
1505  if (toBool("_args"))
1506  {
1507  cerr << "Command line arguments received out of sequence"
1508  << endl;
1509  SetValue("showhelp", "");
1510  return false;
1511  }
1512 
1513 #ifdef Q_OS_MAC
1514  if (opt.startsWith("-psn_"))
1515  {
1516  cerr << "Ignoring Process Serial Number from command line"
1517  << endl;
1518  continue;
1519  }
1520 #endif
1521 
1522  if (!m_optionedArgs.contains(opt))
1523  {
1524  // argument is unhandled, check if parser allows arbitrary input
1525  if (m_namedArgs.contains("_extra"))
1526  {
1527  // arbitrary allowed, specify general collection pool
1528  argdef = m_namedArgs["_extra"];
1529  QByteArray tmp = opt.toLocal8Bit();
1530  tmp += '=';
1531  tmp += val;
1532  val = tmp;
1533  res = kOptVal;
1534  }
1535  else
1536  {
1537  // arbitrary not allowed, fault out
1538  cerr << "Unhandled option given on command line:" << endl
1539  << " " << opt.toLocal8Bit().constData() << endl;
1540  SetValue("showhelp", "");
1541  return false;
1542  }
1543  }
1544  else
1545  argdef = m_optionedArgs[opt];
1546 
1547  // argument has been marked as removed, warn user and fail
1548  if (!argdef->m_removed.isEmpty())
1549  {
1550  argdef->PrintRemovedWarning(opt);
1551  SetValue("showhelp", "");
1552  return false;
1553  }
1554 
1555  // argument has been marked as deprecated, warn user
1556  if (!argdef->m_deprecated.isEmpty())
1557  argdef->PrintDeprecatedWarning(opt);
1558 
1559  if (m_verbose)
1560  cerr << "name: " << argdef->GetName().toLocal8Bit().constData()
1561  << endl;
1562 
1563  // argument is keyword only, no value
1564  if (res == kOptOnly)
1565  {
1566  if (!argdef->Set(opt))
1567  {
1568  SetValue("showhelp", "");
1569  return false;
1570  }
1571  }
1572  // argument has keyword and value
1573  else if ((res == kOptVal) || (res == kCombOptVal))
1574  {
1575  if (!argdef->Set(opt, val))
1576  {
1577  // if option and value were combined with a '=', abort directly
1578  // otherwise, attempt processing them independenly
1579  if ((res == kCombOptVal) || !argdef->Set(opt))
1580  {
1581  SetValue("showhelp", "");
1582  return false;
1583  }
1584  // drop back an iteration so the unused value will get
1585  // processed a second time as a keyword-less argument
1586  --argpos;
1587  }
1588  }
1589  else
1590  {
1591  SetValue("showhelp", "");
1592  return false; // this should not occur
1593  }
1594 
1595  if (m_verbose)
1596  cerr << "value: " << argdef->m_stored.toString().toLocal8Bit().constData()
1597  << endl;
1598  }
1599 
1600  QMap<QString, CommandLineArg*>::const_iterator it;
1601 
1602  if (m_verbose)
1603  {
1604  cerr << "Processed option list:" << endl;
1605  for (it = m_namedArgs.begin(); it != m_namedArgs.end(); ++it)
1606  (*it)->PrintVerbose();
1607 
1608  if (m_namedArgs.contains("_args"))
1609  {
1610  cerr << endl << "Extra argument list:" << endl;
1611  QStringList slist = toStringList("_args");
1612  QStringList::const_iterator it2 = slist.begin();
1613  for (; it2 != slist.end(); ++it2)
1614  cerr << " " << (*it2).toLocal8Bit().constData() << endl;
1615  }
1616 
1617  if (m_namedArgs.contains("_passthrough"))
1618  {
1619  cerr << endl << "Passthrough string:" << endl;
1620  cerr << " " << GetPassthrough().toLocal8Bit().constData() << endl;
1621  }
1622 
1623  cerr << endl;
1624  }
1625 
1626  // make sure all interdependencies are fulfilled
1627  for (it = m_namedArgs.begin(); it != m_namedArgs.end(); ++it)
1628  {
1629  if (!(*it)->TestLinks())
1630  {
1631  QString keyword = (*it)->m_usedKeyword;
1632  if (keyword.startsWith('-'))
1633  {
1634  if (keyword.startsWith("--"))
1635  keyword.remove(0,2);
1636  else
1637  keyword.remove(0,1);
1638  }
1639 
1640  SetValue("showhelp", keyword);
1641  return false;
1642  }
1643  }
1644 
1645  return true;
1646 }
1647 
1652 {
1653  if (m_verbose)
1654  cerr << "Reconciling links for option interdependencies." << endl;
1655 
1656  QMap<QString,CommandLineArg*>::iterator args_it;
1657  for (args_it = m_namedArgs.begin(); args_it != m_namedArgs.end(); ++args_it)
1658  {
1659  QList<CommandLineArg*> links = (*args_it)->m_parents;
1660  QList<CommandLineArg*>::iterator links_it;
1661  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1662  {
1663  if ((*links_it)->m_type != QVariant::Invalid)
1664  continue; // already handled
1665 
1666  if (!m_namedArgs.contains((*links_it)->m_name))
1667  {
1668  // not found
1669  cerr << "ERROR: could not reconcile linked argument." << endl
1670  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1671  << "' could not find '"
1672  << (*links_it)->m_name.toLocal8Bit().constData()
1673  << "'." << endl
1674  << " Please resolve dependency and recompile." << endl;
1675  return false;
1676  }
1677 
1678  // replace linked argument
1679  if (m_verbose)
1680  cerr << QString(" Setting %1 as child of %2")
1681  .arg((*args_it)->m_name).arg((*links_it)->m_name)
1682  .toLocal8Bit().constData()
1683  << endl;
1684  (*args_it)->SetChildOf(m_namedArgs[(*links_it)->m_name]);
1685  }
1686 
1687  links = (*args_it)->m_children;
1688  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1689  {
1690  if ((*links_it)->m_type != QVariant::Invalid)
1691  continue; // already handled
1692 
1693  if (!m_namedArgs.contains((*links_it)->m_name))
1694  {
1695  // not found
1696  cerr << "ERROR: could not reconcile linked argument." << endl
1697  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1698  << "' could not find '"
1699  << (*links_it)->m_name.toLocal8Bit().constData()
1700  << "'." << endl
1701  << " Please resolve dependency and recompile." << endl;
1702  return false;
1703  }
1704 
1705  // replace linked argument
1706  if (m_verbose)
1707  cerr << QString(" Setting %1 as parent of %2")
1708  .arg((*args_it)->m_name).arg((*links_it)->m_name)
1709  .toLocal8Bit().constData()
1710  << endl;
1711  (*args_it)->SetParentOf(m_namedArgs[(*links_it)->m_name]);
1712  }
1713 
1714  links = (*args_it)->m_requires;
1715  for (links_it = links.begin(); links_it != links.end(); ++links_it)
1716  {
1717  if ((*links_it)->m_type != QVariant::Invalid)
1718  continue; // already handled
1719 
1720  if (!m_namedArgs.contains((*links_it)->m_name))
1721  {
1722  // not found
1723  cerr << "ERROR: could not reconcile linked argument." << endl
1724  << " '" << (*args_it)->m_name.toLocal8Bit().constData()
1725  << "' could not find '"
1726  << (*links_it)->m_name.toLocal8Bit().constData()
1727  << "'." << endl
1728  << " Please resolve dependency and recompile." << endl;
1729  return false;
1730  }
1731 
1732  // replace linked argument
1733  if (m_verbose)
1734  cerr << QString(" Setting %1 as requiring %2")
1735  .arg((*args_it)->m_name).arg((*links_it)->m_name)
1736  .toLocal8Bit().constData()
1737  << endl;
1738  (*args_it)->SetRequires(m_namedArgs[(*links_it)->m_name]);
1739  }
1740 
1741  QList<CommandLineArg*>::iterator req_it =
1742  (*args_it)->m_requiredby.begin();
1743  while (req_it != (*args_it)->m_requiredby.end())
1744  {
1745  if ((*req_it)->m_type == QVariant::Invalid)
1746  {
1747  // if its not an invalid, it shouldnt be here anyway
1748  if (m_namedArgs.contains((*req_it)->m_name))
1749  {
1750  m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
1751  if (m_verbose)
1752  {
1753  cerr << QString(" Setting %1 as blocking %2")
1754  .arg((*args_it)->m_name)
1755  .arg((*req_it)->m_name)
1756  .toLocal8Bit().constData()
1757  << endl;
1758  }
1759  }
1760  }
1761 
1762  (*req_it)->DecrRef();
1763  req_it = (*args_it)->m_requiredby.erase(req_it);
1764  }
1765 
1766  QList<CommandLineArg*>::iterator block_it =
1767  (*args_it)->m_blocks.begin();
1768  while (block_it != (*args_it)->m_blocks.end())
1769  {
1770  if ((*block_it)->m_type != QVariant::Invalid)
1771  {
1772  ++block_it;
1773  continue; // already handled
1774  }
1775 
1776  if (!m_namedArgs.contains((*block_it)->m_name))
1777  {
1778  (*block_it)->DecrRef();
1779  block_it = (*args_it)->m_blocks.erase(block_it);
1780  continue; // if it doesnt exist, it cant block this command
1781  }
1782 
1783  // replace linked argument
1784  if (m_verbose)
1785  {
1786  cerr << QString(" Setting %1 as blocking %2")
1787  .arg((*args_it)->m_name).arg((*block_it)->m_name)
1788  .toLocal8Bit().constData()
1789  << endl;
1790  }
1791  (*args_it)->SetBlocks(m_namedArgs[(*block_it)->m_name]);
1792  ++block_it;
1793  }
1794  }
1795 
1796  return true;
1797 }
1798 
1802 QVariant MythCommandLineParser::operator[](const QString &name)
1803 {
1804  QVariant var("");
1805  if (!m_namedArgs.contains(name))
1806  return var;
1807 
1809 
1810  if (arg->m_given)
1811  var = arg->m_stored;
1812  else
1813  var = arg->m_default;
1814 
1815  return var;
1816 }
1817 
1821 QStringList MythCommandLineParser::GetArgs(void) const
1822 {
1823  return toStringList("_args");
1824 }
1825 
1829 QMap<QString,QString> MythCommandLineParser::GetExtra(void) const
1830 {
1831  return toMap("_extra");
1832 }
1833 
1837 {
1838  return toStringList("_passthrough").join(" ");
1839 }
1840 
1849 {
1850  QMap<QString,QString> smap = toMap("overridesettings");
1851 
1852  if (!m_overridesImported)
1853  {
1854  if (toBool("overridesettingsfile"))
1855  {
1856  QString filename = toString("overridesettingsfile");
1857  if (!filename.isEmpty())
1858  {
1859  QFile f(filename);
1860  if (f.open(QIODevice::ReadOnly))
1861  {
1862  char buf[1024];
1863  int64_t len = f.readLine(buf, sizeof(buf) - 1);
1864  while (len != -1)
1865  {
1866  if (len >= 1 && buf[len-1]=='\n')
1867  buf[len-1] = 0;
1868  QString line(buf);
1869  QStringList tokens = line.split("=",
1870  QString::SkipEmptyParts);
1871  if (tokens.size() == 2)
1872  {
1873  tokens[0].replace(QRegExp("^[\"']"), "");
1874  tokens[0].replace(QRegExp("[\"']$"), "");
1875  tokens[1].replace(QRegExp("^[\"']"), "");
1876  tokens[1].replace(QRegExp("[\"']$"), "");
1877  if (!tokens[0].isEmpty())
1878  smap[tokens[0]] = tokens[1];
1879  }
1880  len = f.readLine(buf, sizeof(buf) - 1);
1881  }
1882  }
1883  else
1884  {
1885  QByteArray tmp = filename.toLatin1();
1886  cerr << "Failed to open the override settings file: '"
1887  << tmp.constData() << "'" << endl;
1888  }
1889  }
1890  }
1891 
1892  if (toBool("windowed"))
1893  smap["RunFrontendInWindow"] = "1";
1894  else if (toBool("notwindowed"))
1895  smap["RunFrontendInWindow"] = "0";
1896 
1897  if (toBool("mousecursor"))
1898  smap["HideMouseCursor"] = "0";
1899  else if (toBool("nomousecursor"))
1900  smap["HideMouseCursor"] = "1";
1901 
1902  m_overridesImported = true;
1903 
1904  if (!smap.isEmpty())
1905  {
1906  QVariantMap vmap;
1907  QMap<QString, QString>::const_iterator it;
1908  for (it = smap.begin(); it != smap.end(); ++it)
1909  vmap[it.key()] = QVariant(it.value());
1910 
1911  m_namedArgs["overridesettings"]->Set(QVariant(vmap));
1912  }
1913  }
1914 
1915  if (m_verbose)
1916  {
1917  cerr << "Option Overrides:" << endl;
1918  QMap<QString, QString>::const_iterator it;
1919  for (it = smap.constBegin(); it != smap.constEnd(); ++it)
1920  cerr << QString(" %1 - %2").arg(it.key(), 30).arg(*it)
1921  .toLocal8Bit().constData() << endl;
1922  }
1923 
1924  return smap;
1925 }
1926 
1933 bool MythCommandLineParser::toBool(const QString& key) const
1934 {
1935  if (!m_namedArgs.contains(key))
1936  return false;
1937 
1938  CommandLineArg *arg = m_namedArgs[key];
1939 
1940  if (arg->m_type == QVariant::Bool)
1941  {
1942  if (arg->m_given)
1943  return arg->m_stored.toBool();
1944  return arg->m_default.toBool();
1945  }
1946 
1947  return arg->m_given;
1948 }
1949 
1953 int MythCommandLineParser::toInt(const QString& key) const
1954 {
1955  int val = 0;
1956  if (!m_namedArgs.contains(key))
1957  return val;
1958 
1959  CommandLineArg *arg = m_namedArgs[key];
1960 
1961  if (arg->m_given)
1962  {
1963  if (arg->m_stored.canConvert(QVariant::Int))
1964  val = arg->m_stored.toInt();
1965  }
1966  else
1967  {
1968  if (arg->m_default.canConvert(QVariant::Int))
1969  val = arg->m_default.toInt();
1970  }
1971 
1972  return val;
1973 }
1974 
1978 uint MythCommandLineParser::toUInt(const QString& key) const
1979 {
1980  uint val = 0;
1981  if (!m_namedArgs.contains(key))
1982  return val;
1983 
1984  CommandLineArg *arg = m_namedArgs[key];
1985 
1986  if (arg->m_given)
1987  {
1988  if (arg->m_stored.canConvert(QVariant::UInt))
1989  val = arg->m_stored.toUInt();
1990  }
1991  else
1992  {
1993  if (arg->m_default.canConvert(QVariant::UInt))
1994  val = arg->m_default.toUInt();
1995  }
1996 
1997  return val;
1998 }
1999 
2003 long long MythCommandLineParser::toLongLong(const QString& key) const
2004 {
2005  long long val = 0;
2006  if (!m_namedArgs.contains(key))
2007  return val;
2008 
2009  CommandLineArg *arg = m_namedArgs[key];
2010 
2011  if (arg->m_given)
2012  {
2013  if (arg->m_stored.canConvert(QVariant::LongLong))
2014  val = arg->m_stored.toLongLong();
2015  }
2016  else
2017  {
2018  if (arg->m_default.canConvert(QVariant::LongLong))
2019  val = arg->m_default.toLongLong();
2020  }
2021 
2022  return val;
2023 }
2024 
2028 double MythCommandLineParser::toDouble(const QString& key) const
2029 {
2030  double val = 0.0;
2031  if (!m_namedArgs.contains(key))
2032  return val;
2033 
2034  CommandLineArg *arg = m_namedArgs[key];
2035 
2036  if (arg->m_given)
2037  {
2038  if (arg->m_stored.canConvert(QVariant::Double))
2039  val = arg->m_stored.toDouble();
2040  }
2041  else
2042  {
2043  if (arg->m_default.canConvert(QVariant::Double))
2044  val = arg->m_default.toDouble();
2045  }
2046 
2047  return val;
2048 }
2049 
2053 QSize MythCommandLineParser::toSize(const QString& key) const
2054 {
2055  QSize val(0,0);
2056  if (!m_namedArgs.contains(key))
2057  return val;
2058 
2059  CommandLineArg *arg = m_namedArgs[key];
2060 
2061  if (arg->m_given)
2062  {
2063  if (arg->m_stored.canConvert(QVariant::Size))
2064  val = arg->m_stored.toSize();
2065  }
2066  else
2067  {
2068  if (arg->m_default.canConvert(QVariant::Size))
2069  val = arg->m_default.toSize();
2070  }
2071 
2072  return val;
2073 }
2074 
2078 QString MythCommandLineParser::toString(const QString& key) const
2079 {
2080  QString val("");
2081  if (!m_namedArgs.contains(key))
2082  return val;
2083 
2084  CommandLineArg *arg = m_namedArgs[key];
2085 
2086  if (arg->m_given)
2087  {
2088  if (!arg->m_converted)
2089  arg->Convert();
2090 
2091  if (arg->m_stored.canConvert(QVariant::String))
2092  val = arg->m_stored.toString();
2093  }
2094  else
2095  {
2096  if (arg->m_default.canConvert(QVariant::String))
2097  val = arg->m_default.toString();
2098  }
2099 
2100  return val;
2101 }
2102 
2107 QStringList MythCommandLineParser::toStringList(const QString& key, const QString& sep) const
2108 {
2109  QVariant varval;
2110  QStringList val;
2111  if (!m_namedArgs.contains(key))
2112  return val;
2113 
2114  CommandLineArg *arg = m_namedArgs[key];
2115 
2116  if (arg->m_given)
2117  {
2118  if (!arg->m_converted)
2119  arg->Convert();
2120 
2121  varval = arg->m_stored;
2122  }
2123  else
2124  varval = arg->m_default;
2125 
2126  if (arg->m_type == QVariant::String && !sep.isEmpty())
2127  val = varval.toString().split(sep);
2128  else if (varval.canConvert(QVariant::StringList))
2129  val = varval.toStringList();
2130 
2131  return val;
2132 }
2133 
2137 QMap<QString,QString> MythCommandLineParser::toMap(const QString& key) const
2138 {
2139  QMap<QString, QString> val;
2140  QMap<QString, QVariant> tmp;
2141  if (!m_namedArgs.contains(key))
2142  return val;
2143 
2144  CommandLineArg *arg = m_namedArgs[key];
2145 
2146  if (arg->m_given)
2147  {
2148  if (!arg->m_converted)
2149  arg->Convert();
2150 
2151  if (arg->m_stored.canConvert(QVariant::Map))
2152  tmp = arg->m_stored.toMap();
2153  }
2154  else
2155  {
2156  if (arg->m_default.canConvert(QVariant::Map))
2157  tmp = arg->m_default.toMap();
2158  }
2159 
2160  QMap<QString, QVariant>::const_iterator i;
2161  for (i = tmp.begin(); i != tmp.end(); ++i)
2162  val[i.key()] = i.value().toString();
2163 
2164  return val;
2165 }
2166 
2170 QDateTime MythCommandLineParser::toDateTime(const QString& key) const
2171 {
2172  QDateTime val;
2173  if (!m_namedArgs.contains(key))
2174  return val;
2175 
2176  CommandLineArg *arg = m_namedArgs[key];
2177 
2178  if (arg->m_given)
2179  {
2180  if (arg->m_stored.canConvert(QVariant::DateTime))
2181  val = arg->m_stored.toDateTime();
2182  }
2183  else
2184  {
2185  if (arg->m_default.canConvert(QVariant::DateTime))
2186  val = arg->m_default.toDateTime();
2187  }
2188 
2189  return val;
2190 }
2191 
2196 {
2197  if (m_namedArgs.contains("_args"))
2198  {
2199  if (!allow)
2200  m_namedArgs.remove("_args");
2201  }
2202  else if (!allow)
2203  return;
2204 
2205  CommandLineArg *arg = new CommandLineArg("_args", QVariant::StringList,
2206  QStringList());
2207  m_namedArgs["_args"] = arg;
2208 }
2209 
2214 {
2215  if (m_namedArgs.contains("_extra"))
2216  {
2217  if (!allow)
2218  m_namedArgs.remove("_extra");
2219  }
2220  else if (!allow)
2221  return;
2222 
2223  QMap<QString,QVariant> vmap;
2224  CommandLineArg *arg = new CommandLineArg("_extra", QVariant::Map, vmap);
2225 
2226  m_namedArgs["_extra"] = arg;
2227 }
2228 
2233 {
2234  if (m_namedArgs.contains("_passthrough"))
2235  {
2236  if (!allow)
2237  m_namedArgs.remove("_passthrough");
2238  }
2239  else if (!allow)
2240  return;
2241 
2242  CommandLineArg *arg = new CommandLineArg("_passthrough",
2243  QVariant::StringList, QStringList());
2244  m_namedArgs["_passthrough"] = arg;
2245 }
2246 
2250 {
2251  add(QStringList{"-h", "--help", "--usage"},
2252  "showhelp", "", "Display this help printout, or give detailed "
2253  "information of selected option.",
2254  "Displays a list of all commands available for use with "
2255  "this application. If another option is provided as an "
2256  "argument, it will provide detailed information on that "
2257  "option.");
2258 }
2259 
2263 {
2264  add("--version", "showversion", false, "Display version information.",
2265  "Display informtion about build, including:\n"
2266  " version, branch, protocol, library API, Qt "
2267  "and compiled options.");
2268 }
2269 
2273 {
2274  add(QStringList{"-nw", "--no-windowed"},
2275  "notwindowed", false,
2276  "Prevent application from running in a window.", "")
2277  ->SetBlocks("windowed")
2278  ->SetGroup("User Interface");
2279 
2280  add(QStringList{"-w", "--windowed"}, "windowed",
2281  false, "Force application to run in a window.", "")
2282  ->SetGroup("User Interface");
2283 }
2284 
2288 {
2289  add("--mouse-cursor", "mousecursor", false,
2290  "Force visibility of the mouse cursor.", "")
2291  ->SetBlocks("nomousecursor")
2292  ->SetGroup("User Interface");
2293 
2294  add("--no-mouse-cursor", "nomousecursor", false,
2295  "Force the mouse cursor to be hidden.", "")
2296  ->SetGroup("User Interface");
2297 }
2298 
2302 {
2303  add(QStringList{"-d", "--daemon"}, "daemon", false,
2304  "Fork application into background after startup.",
2305  "Fork application into background, detatching from "
2306  "the local terminal.\nOften used with: "
2307  " --logpath --pidfile --user");
2308 }
2309 
2314 {
2315  add(QStringList{"-O", "--override-setting"},
2316  "overridesettings", QVariant::Map,
2317  "Override a single setting defined by a key=value pair.",
2318  "Override a single setting from the database using "
2319  "options defined as one or more key=value pairs\n"
2320  "Multiple can be defined by multiple uses of the "
2321  "-O option.");
2322  add("--override-settings-file", "overridesettingsfile", "",
2323  "Define a file of key=value pairs to be "
2324  "loaded for setting overrides.", "");
2325 }
2326 
2330 {
2331  add("--chanid", "chanid", 0U,
2332  "Specify chanid of recording to operate on.", "")
2333  ->SetRequires("starttime");
2334 
2335  add("--starttime", "starttime", QDateTime(),
2336  "Specify start time of recording to operate on.", "")
2337  ->SetRequires("chanid");
2338 }
2339 
2343 {
2344  add(QStringList{"-geometry", "--geometry"}, "geometry",
2345  "", "Specify window size and position (WxH[+X+Y])", "")
2346  ->SetGroup("User Interface");
2347 }
2348 
2352 {
2353 #ifdef USING_X11
2354  add("-display", "display", "", "Specify X server to use.", "")
2355  ->SetGroup("User Interface");
2356 #endif
2357 }
2358 
2362 {
2363  add("--noupnp", "noupnp", false, "Disable use of UPnP.", "");
2364 }
2365 
2370  const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2371 {
2372  defaultLogLevel =
2373  ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2374  LOG_INFO : defaultLogLevel;
2375 
2376  QString logLevelStr = logLevelGetName(defaultLogLevel);
2377 
2378  add(QStringList{"-v", "--verbose"}, "verbose",
2379  defaultVerbosity,
2380  "Specify log filtering. Use '-v help' for level info.", "")
2381  ->SetGroup("Logging");
2382  add("-V", "verboseint", 0LL, "",
2383  "This option is intended for internal use only.\n"
2384  "This option takes an unsigned value corresponding "
2385  "to the bitwise log verbosity operator.")
2386  ->SetGroup("Logging");
2387  add("--logpath", "logpath", "",
2388  "Writes logging messages to a file in the directory logpath with "
2389  "filenames in the format: applicationName.date.pid.log.\n"
2390  "This is typically used in combination with --daemon, and if used "
2391  "in combination with --pidfile, this can be used with log "
2392  "rotators, using the HUP call to inform MythTV to reload the "
2393  "file", "")
2394  ->SetGroup("Logging");
2395  add(QStringList{"-q", "--quiet"}, "quiet", 0,
2396  "Don't log to the console (-q). Don't log anywhere (-q -q)", "")
2397  ->SetGroup("Logging");
2398  add("--loglevel", "loglevel", logLevelStr,
2399  QString(
2400  "Set the logging level. All log messages at lower levels will be "
2401  "discarded.\n"
2402  "In descending order: emerg, alert, crit, err, warning, notice, "
2403  "info, debug\ndefaults to ") + logLevelStr, "")
2404  ->SetGroup("Logging");
2405  add("--syslog", "syslog", "none",
2406  "Set the syslog logging facility.\nSet to \"none\" to disable, "
2407  "defaults to none.", "")
2408  ->SetGroup("Logging");
2409 #if CONFIG_SYSTEMD_JOURNAL
2410  add("--systemd-journal", "systemd-journal", "false",
2411  "Use systemd-journal instead of syslog.", "")
2412  ->SetBlocks(QStringList()
2413  << "syslog"
2414  )
2415  ->SetGroup("Logging");
2416 #endif
2417  add("--nodblog", "nodblog", false, "Disable database logging.", "")
2418  ->SetGroup("Logging")
2419  ->SetDeprecated("this is now the default, see --enable-dblog");
2420  add("--enable-dblog", "enabledblog", false, "Enable logging to database.", "")
2421  ->SetGroup("Logging");
2422 
2423  add(QStringList{"-l", "--logfile"},
2424  "logfile", "", "", "")
2425  ->SetGroup("Logging")
2426  ->SetRemoved("This option has been removed as part of "
2427  "rewrite of the logging interface. Please update your init "
2428  "scripts to use --syslog to interface with your system's "
2429  "existing system logging daemon, or --logpath to specify a "
2430  "dirctory for MythTV to write its logs to.", "0.25");
2431 }
2432 
2436 {
2437  add(QStringList{"-p", "--pidfile"}, "pidfile", "",
2438  "Write PID of application to filename.",
2439  "Write the PID of the currently running process as a single "
2440  "line to this file. Used for init scripts to know what "
2441  "process to terminate, and with log rotators "
2442  "to send a HUP signal to process to have it re-open files.");
2443 }
2444 
2448 {
2449  add(QStringList{"-j", "--jobid"}, "jobid", 0, "",
2450  "Intended for internal use only, specify the JobID to match "
2451  "up with in the database for additional information and the "
2452  "ability to update runtime status in the database.");
2453 }
2454 
2458 {
2459  add("--infile", "infile", "", "Input file URI", "");
2460  if (addOutFile)
2461  add("--outfile", "outfile", "", "Output file URI", "");
2462 }
2463 
2467 {
2468  QString logfile = toString("logpath");
2469  pid_t pid = getpid();
2470 
2471  if (logfile.isEmpty())
2472  return logfile;
2473 
2474  QString logdir;
2475  QString filepath;
2476 
2477  QFileInfo finfo(logfile);
2478  if (!finfo.isDir())
2479  {
2480  LOG(VB_GENERAL, LOG_ERR,
2481  QString("%1 is not a directory, disabling logfiles")
2482  .arg(logfile));
2483  return QString();
2484  }
2485 
2486  logdir = finfo.filePath();
2487  logfile = QCoreApplication::applicationName() + "." +
2489  QString(".%1").arg(pid) + ".log";
2490 
2491  SetValue("logdir", logdir);
2492  SetValue("logfile", logfile);
2493  SetValue("filepath", QFileInfo(QDir(logdir), logfile).filePath());
2494 
2495  return toString("filepath");
2496 }
2497 
2501 {
2502  QString setting = toString("syslog").toLower();
2503  if (setting == "none")
2504  return -2;
2505 
2506  return syslogGetFacility(setting);
2507 }
2508 
2512 {
2513  QString setting = toString("loglevel");
2514  if (setting.isEmpty())
2515  return LOG_INFO;
2516 
2517  LogLevel_t level = logLevelGet(setting);
2518  if (level == LOG_UNKNOWN)
2519  cerr << "Unknown log level: " << setting.toLocal8Bit().constData() <<
2520  endl;
2521 
2522  return level;
2523 }
2524 
2529 bool MythCommandLineParser::SetValue(const QString &key, const QVariant& value)
2530 {
2531  CommandLineArg *arg;
2532 
2533  if (!m_namedArgs.contains(key))
2534  {
2535  const QVariant& val(value);
2536  arg = new CommandLineArg(key, val.type(), val);
2537  m_namedArgs.insert(key, arg);
2538  }
2539  else
2540  {
2541  arg = m_namedArgs[key];
2542  if (arg->m_type != value.type())
2543  return false;
2544  }
2545 
2546  arg->Set(value);
2547  return true;
2548 }
2549 
2552 int MythCommandLineParser::ConfigureLogging(QString mask, unsigned int progress)
2553 {
2554  int err = 0;
2555 
2556  // Setup the defaults
2557  verboseString = "";
2558  verboseMask = 0;
2559  verboseArgParse(std::move(mask));
2560 
2561  if (toBool("verbose"))
2562  {
2563  if ((err = verboseArgParse(toString("verbose"))))
2564  return err;
2565  }
2566  else if (toBool("verboseint"))
2567  verboseMask = toLongLong("verboseint");
2568 
2569  verboseMask |= VB_STDIO|VB_FLUSH;
2570 
2571  int quiet = toUInt("quiet");
2572  if (max(quiet, (int)progress) > 1)
2573  {
2574  verboseMask = VB_NONE|VB_FLUSH;
2575  verboseArgParse("none");
2576  }
2577 
2578  int facility = GetSyslogFacility();
2579 #if CONFIG_SYSTEMD_JOURNAL
2580  bool journal = toBool("systemd-journal");
2581  if (journal)
2582  {
2583  if (facility >= 0)
2585  facility = SYSTEMD_JOURNAL_FACILITY;
2586  }
2587 #endif
2588  bool dblog = toBool("enabledblog");
2589  LogLevel_t level = GetLogLevel();
2590  if (level == LOG_UNKNOWN)
2592 
2593  LOG(VB_GENERAL, LOG_CRIT,
2594  QString("%1 version: %2 [%3] www.mythtv.org")
2595  .arg(QCoreApplication::applicationName())
2596  .arg(MYTH_SOURCE_PATH).arg(MYTH_SOURCE_VERSION));
2597  LOG(VB_GENERAL, LOG_CRIT, QString("Qt version: compile: %1, runtime: %2")
2598  .arg(QT_VERSION_STR).arg(qVersion()));
2599  LOG(VB_GENERAL, LOG_NOTICE,
2600  QString("Enabled verbose msgs: %1").arg(verboseString));
2601 
2602  QString logfile = GetLogFilePath();
2603  bool propagate = !logfile.isEmpty();
2604 
2605  if (toBool("daemon"))
2606  quiet = max(quiet, 1);
2607 
2608  logStart(logfile, progress, quiet, facility, level, dblog, propagate);
2609 
2610  return GENERIC_EXIT_OK;
2611 }
2612 
2618 {
2619  if (m_verbose)
2620  cerr << "Applying settings override" << endl;
2621 
2622  QMap<QString, QString> override = GetSettingsOverride();
2623  if (!override.empty())
2624  {
2625  QMap<QString, QString>::iterator it;
2626  for (it = override.begin(); it != override.end(); ++it)
2627  {
2628  LOG(VB_GENERAL, LOG_NOTICE,
2629  QString("Setting '%1' being forced to '%2'")
2630  .arg(it.key()).arg(*it));
2631  gCoreContext->OverrideSettingForSession(it.key(), *it);
2632  }
2633  }
2634 }
2635 
2636 bool openPidfile(ofstream &pidfs, const QString &pidfile)
2637 {
2638  if (!pidfile.isEmpty())
2639  {
2640  pidfs.open(pidfile.toLatin1().constData());
2641  if (!pidfs)
2642  {
2643  cerr << "Could not open pid file: " << ENO_STR << endl;
2644  return false;
2645  }
2646  }
2647  return true;
2648 }
2649 
2652 bool setUser(const QString &username)
2653 {
2654  if (username.isEmpty())
2655  return true;
2656 
2657 #ifdef _WIN32
2658  cerr << "--user option is not supported on Windows" << endl;
2659  return false;
2660 #else // ! _WIN32
2661 #if defined(__linux__) || defined(__LINUX__)
2662  // Check the current dumpability of core dumps, which will be disabled
2663  // by setuid, so we can re-enable, if appropriate
2664  int dumpability = prctl(PR_GET_DUMPABLE);
2665 #endif
2666  struct passwd *user_info = getpwnam(username.toLocal8Bit().constData());
2667  const uid_t user_id = geteuid();
2668 
2669  if (user_id && (!user_info || user_id != user_info->pw_uid))
2670  {
2671  cerr << "You must be running as root to use the --user switch." << endl;
2672  return false;
2673  }
2674  if (user_info && user_id == user_info->pw_uid)
2675  {
2676  LOG(VB_GENERAL, LOG_WARNING,
2677  QString("Already running as '%1'").arg(username));
2678  }
2679  else if (!user_id && user_info)
2680  {
2681  if (setenv("HOME", user_info->pw_dir,1) == -1)
2682  {
2683  cerr << "Error setting home directory." << endl;
2684  return false;
2685  }
2686  if (setgid(user_info->pw_gid) == -1)
2687  {
2688  cerr << "Error setting effective group." << endl;
2689  return false;
2690  }
2691  if (initgroups(user_info->pw_name, user_info->pw_gid) == -1)
2692  {
2693  cerr << "Error setting groups." << endl;
2694  return false;
2695  }
2696  if (setuid(user_info->pw_uid) == -1)
2697  {
2698  cerr << "Error setting effective user." << endl;
2699  return false;
2700  }
2701 #if defined(__linux__) || defined(__LINUX__)
2702  if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
2703  LOG(VB_GENERAL, LOG_WARNING, "Unable to re-enable core file "
2704  "creation. Run without the --user argument to use "
2705  "shell-specified limits.");
2706 #endif
2707  }
2708  else
2709  {
2710  cerr << QString("Invalid user '%1' specified with --user")
2711  .arg(username).toLocal8Bit().constData() << endl;
2712  return false;
2713  }
2714  return true;
2715 #endif // ! _WIN32
2716 }
2717 
2718 
2722 {
2723  ofstream pidfs;
2724  if (!openPidfile(pidfs, toString("pidfile")))
2726 
2727  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
2728  LOG(VB_GENERAL, LOG_WARNING, "Unable to ignore SIGPIPE");
2729 
2730 #if CONFIG_DARWIN
2731  if (toBool("daemon"))
2732  {
2733  cerr << "Daemonizing is unavailable in OSX" << endl;
2734  LOG(VB_GENERAL, LOG_WARNING, "Unable to daemonize");
2735  }
2736 #else
2737  if (toBool("daemon") && (daemon(0, 1) < 0))
2738  {
2739  cerr << "Failed to daemonize: " << ENO_STR << endl;
2741  }
2742 #endif
2743 
2744  QString username = toString("username");
2745  if (!username.isEmpty() && !setUser(username))
2747 
2748  if (pidfs)
2749  {
2750  pidfs << getpid() << endl;
2751  pidfs.close();
2752  }
2753 
2754  return GENERIC_EXIT_OK;
2755 }
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:857
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
CommandLineArg * SetRequires(QString opt)
Set argument as requiring given option.
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
QMap< QString, CommandLineArg * > m_optionedArgs
General purpose reference counter.
QVariant::Type m_type
void PrintHelp(void) const
Print command line option help.
Default UTC, "yyyyMMddhhmmss".
Definition: mythdate.h:15
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:805
unsigned int uint
Definition: compat.h:140
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.
CommandLineArg * SetBlocks(QString opt)
Set argument as incompatible with given option.
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.
QMap< QString, CommandLineArg * > m_namedArgs
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
CommandLineArg * SetParent(QString opt)
Set argument as child of given parent.
virtual int IncrRef(void)
Increments reference count.
void AddKeyword(const QString &keyword)
CommandLineArg * SetParentOf(QString opt)
Set argument as parent of given child.
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.
CommandLineArg * SetChildOf(QString opt)
Set argument as child of given parent.
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
double toDouble(const QString &key) const
Returns stored QVariant as double floating point value, falling to default if not provided.
const char * name
Definition: ParseText.cpp:328
const int kArg
QList< CommandLineArg * > m_requiredby
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
const int kCombOptVal
#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 * SetChild(QString opt)
Set argument as parent of given child.
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:984
int ConfigureLogging(QString mask="general", unsigned int progress=0)
Read in logging options and initialize the logging interface.
#define SIGPIPE
Definition: compat.h:218
QList< CommandLineArg * > m_children
#define GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.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:833
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.
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 PrintVersion(void) const
Print application version information.
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.
Default UTC.
Definition: mythdate.h:14
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.
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:720
int getOpt(int argc, const char *const *argv, int &argpos, QString &opt, QByteArray &val)
Internal use.
void Convert(void)
Convert stored string value from QByteArray to QString.
QString verboseString
Definition: logging.cpp:108