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