24#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
25#include <QtSystemDetection>
28#if defined ANDROID && __ANDROID_API__ < 24
46# include <sys/ioctl.h>
50# include <sys/prctl.h>
55#include <QCoreApplication>
60#include <QRegularExpression>
65#include <QVariantList>
73#include "mythconfig.h"
75#include "mythversion.h"
87#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
92 if (ioctl(0, TIOCGWINSZ, &ws) != 0)
95 return static_cast<int>(ws.ws_col);
101 return ((array.startsWith(
'"') && array.endsWith(
'"') ) ||
102 (array.startsWith(
'\'') && array.endsWith(
'\''))
103 ) ? array.mid(1, array.size() - 2) : array;
110 width = std::max(width, 5);
112 for (
int i = 0; i < list.size(); i++)
114 QString
string = list.at(i);
116 if(
string.size() <= width )
119 QString left =
string.left(width);
120 bool inserted =
false;
122 while( !inserted && !left.endsWith(
" " ))
124 if(
string.mid(left.size(), 1) ==
" " )
126 list.replace(i, left);
127 list.insert(i+1,
string.mid(left.size()).trimmed());
133 if( !left.contains(
" ") )
136 list.replace(i, left +
"-");
137 list.insert(i+1,
string.mid(left.size()));
146 list.replace(i, left);
147 list.insert(i+1,
string.mid(left.size()).trimmed());
162 enum states : std::uint8_t {
171 states state =
START;
174 for (
int i = 0; i < line.size(); i++)
176 const QChar c = line.at(i);
181 if (c.isSpace())
break;
182 if (c ==
'\'') state = INSQUOTE;
183 else if (c ==
'\"') state = INDQUOTE;
184 else if (c ==
'\\') state = ESCTEXT;
189 fields += line.mid(tokenStart, i - tokenStart);
193 else if (c ==
'\'') {
195 }
else if (c ==
'\"') {
197 }
else if (c ==
'\\') {
202 if (c ==
'\'') state = INTEXT;
203 else if (c ==
'\\') state = ESCSQUOTE;
206 if (c ==
'\"') state = INTEXT;
207 else if (c ==
'\\') state = ESCDQUOTE;
209 case ESCTEXT: state = INTEXT;
break;
210 case ESCSQUOTE: state = INSQUOTE;
break;
211 case ESCDQUOTE: state = INDQUOTE;
break;
216 fields += line.mid(tokenStart);
240 return "kCombOptVal";
246 return "kPassthrough";
289 QVariant def, QString
help, QString longhelp) :
291 m_name(name), m_type(
type), m_default(
std::move(def)),
292 m_help(
std::move(
help)), m_longhelp(
std::move(longhelp))
294 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
295 (
m_type != QMetaType::QVariantMap))
307 m_name(name), m_type(
type), m_default(
std::move(def))
309 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
310 (
m_type != QMetaType::QVariantMap))
344 QList<CommandLineArg*>::const_iterator i1;
346 len = std::max(len, (*i1)->GetKeywordLength()+2);
369 QTextStream msg(&helpstr, QIODevice::WriteOnly);
414 QStringList hlist =
m_help.split(
'\n');
420 << hlist.takeFirst() << Qt::endl;
423 for (
const auto & line : std::as_const(hlist))
424 msg << pad << line << Qt::endl;
428 msg << arg->GetHelpString(off, group,
true);
444 QTextStream msg(&helpstr, QIODevice::WriteOnly);
462 msg <<
"Option: " << keyword << Qt::endl << Qt::endl;
467 for (
const auto & word : std::as_const(
m_keywords))
473 msg <<
"Aliases: " << word << Qt::endl;
478 msg <<
" " << word << Qt::endl;
484 msg <<
"Type: " << QMetaType(
m_type).name() << Qt::endl;
486 msg <<
"Default: " <<
m_default.toString() << Qt::endl;
496 msg <<
"Description: " <<
help.takeFirst() << Qt::endl;
497 for (
const auto & line : std::as_const(
help))
498 msg <<
" " << line << Qt::endl;
500 QList<CommandLineArg*>::const_iterator i2;
505 msg << Qt::endl <<
"Can be used in combination with:" << Qt::endl;
506 for (
auto * parent : std::as_const(
m_parents))
507 msg <<
" " << parent->GetPreferredKeyword()
508 .toLocal8Bit().constData();
514 msg << Qt::endl <<
"Allows the use of:" << Qt::endl;
516 msg <<
" " << (*i2)->GetPreferredKeyword()
517 .toLocal8Bit().constData();
523 msg << Qt::endl <<
"Requires the use of:" << Qt::endl;
525 msg <<
" " << (*i2)->GetPreferredKeyword()
526 .toLocal8Bit().constData();
532 msg << Qt::endl <<
"Prevents the use of:" << Qt::endl;
534 msg <<
" " << (*i2)->GetPreferredKeyword()
535 .toLocal8Bit().constData();
555 case QMetaType::Bool:
566 case QMetaType::QString:
571 std::cerr <<
"Command line option did not receive value:" << std::endl
572 <<
" " << opt.toLocal8Bit().constData() << std::endl;
585 QList<QByteArray> blist;
591 case QMetaType::Bool:
592 std::cerr <<
"Boolean type options do not accept values:" << std::endl
593 <<
" " << opt.toLocal8Bit().constData() << std::endl;
596 case QMetaType::QString:
604 case QMetaType::UInt:
608 case QMetaType::LongLong:
609 m_stored = QVariant(val.toLongLong());
612 case QMetaType::Double:
613 m_stored = QVariant(val.toDouble());
616 case QMetaType::QDateTime:
620 case QMetaType::QStringList:
627 case QMetaType::QVariantMap:
628 if (!val.contains(
'='))
630 std::cerr <<
"Command line option did not get expected "
631 <<
"key/value pair" << std::endl;
635 blist = val.split(
'=');
643 case QMetaType::QSize:
644 if (!val.contains(
'x'))
646 std::cerr <<
"Command line option did not get expected "
647 <<
"XxY pair" << std::endl;
651 blist = val.split(
'x');
652 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
675 for (
const auto& opt : std::as_const(
opts))
692 for (
const auto& opt : std::as_const(
opts))
709 for (
const auto& opt : std::as_const(
opts))
726 for (
const auto& opt : std::as_const(
opts))
744 for (
const auto& opt : std::as_const(
opts))
765 for (
const auto& opt : std::as_const(
opts))
785 for (
const auto& opt : std::as_const(
opts))
802 for (
const auto& opt : std::as_const(
opts))
811 if (depstr.isEmpty())
812 depstr =
"and will be removed in a future version.";
821 if (remstr.isEmpty())
822 remstr =
"and is no longer available in this version.";
835 bool replaced =
false;
863 bool replaced =
false;
866 for (
int i = 0; i <
m_parents.size(); i++)
891 bool replaced =
false;
920 bool replaced =
false;
923 for (
int i = 0; i <
m_blocks.size(); i++)
951 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
955 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
957 (*i1)->SetBlocks(*i2);
960 if ((*i1)->m_type == QMetaType::UnknownType)
973 if (!QCoreApplication::instance())
988#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
989 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
991 auto storedType =
m_stored.typeId();
993 if (
m_type == QMetaType::QString)
995 if (storedType == QMetaType::QByteArray)
1003 else if (
m_type == QMetaType::QStringList)
1005 if (storedType == QMetaType::QVariantList)
1007 QVariantList vlist =
m_stored.toList();
1009 for (
const auto& item : std::as_const(vlist))
1010 slist << QString::fromLocal8Bit(item.toByteArray());
1014 else if (
m_type == QMetaType::QVariantMap)
1016 QVariantMap vmap =
m_stored.toMap();
1018 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1019 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1037 QStringList::const_iterator it;
1043 int len2 = (*it).size();
1062 QList<CommandLineArg*>::const_iterator i;
1064 bool passes =
false;
1076 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1077 <<
" requires at least one of the following arguments" << std::endl;
1080 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1081 std::cerr << std::endl << std::endl;
1092 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1093 <<
" requires all of the following be defined as well"
1098 << (*i)->GetPreferredKeyword().toLocal8Bit()
1101 std::cerr << std::endl << std::endl;
1111 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1112 <<
" requires that none of the following be defined" << std::endl;
1116 << (*i)->GetPreferredKeyword().toLocal8Bit()
1119 std::cerr << std::endl << std::endl;
1155 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1158 QMap<QString, QVariant> tmpmap;
1159 QMap<QString, QVariant>::const_iterator it;
1165 case QMetaType::Bool:
1166 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1169 case QMetaType::Int:
1170 std::cerr <<
m_stored.toInt() << std::endl;
1173 case QMetaType::UInt:
1174 std::cerr <<
m_stored.toUInt() << std::endl;
1177 case QMetaType::LongLong:
1178 std::cerr <<
m_stored.toLongLong() << std::endl;
1181 case QMetaType::Double:
1182 std::cerr <<
m_stored.toDouble() << std::endl;
1185 case QMetaType::QSize:
1187 std::cerr <<
"x=" << tmpsize.width()
1188 <<
" y=" << tmpsize.height()
1192 case QMetaType::QString:
1193 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1194 <<
'"' << std::endl;
1197 case QMetaType::QStringList:
1199 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1200 for (
const auto& str : std::as_const(vlist))
1206 std::cerr << std::endl;
1209 case QMetaType::QVariantMap:
1211 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1216 std::cerr << QString(
"").leftJustified(32)
1217 .toLocal8Bit().constData();
1219 std::cerr << it.key().toLocal8Bit().constData()
1221 << it->toByteArray().constData()
1227 case QMetaType::QDateTime:
1229 .toLocal8Bit().constData()
1234 std::cerr << std::endl;
1242 QString warn = QString(
"%1 has been removed").arg(keyword);
1246 std::cerr << QString(
"****************************************************\n"
1249 "****************************************************\n\n")
1251 .toLocal8Bit().constData();
1258 std::cerr << QString(
"****************************************************\n"
1259 " WARNING: %1 has been deprecated\n"
1261 "****************************************************\n\n")
1263 .toLocal8Bit().constData();
1280 : m_appname(
std::move(appname))
1282 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1284 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1293 QString pidfile =
toString(
"pidfile");
1294 if (!pidfile.isEmpty())
1296 QFile::remove(pidfile);
1299 QMap<QString, CommandLineArg*>::iterator i;
1304 (*i)->CleanupLinks();
1351 const QString& name, QMetaType::Type
type, QVariant def,
1352 QString
help, QString longhelp)
1364 for (
const auto & str : std::as_const(arglist))
1371 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1372 <<
" as taking type '"
1373#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1374 << QVariant::typeToName(
static_cast<int>(
type))
1376 << QMetaType(
type).name()
1378 <<
"'" << std::endl;
1392 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1395 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1396 std::cout <<
"Library API : " << MYTH_BINARY_VERSION << std::endl;
1397 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1398#ifdef MYTH_BUILD_CONFIG
1399 std::cout <<
"Options compiled in:" <<std::endl;
1400 std::cout << MYTH_BUILD_CONFIG << std::endl;
1409 std::cerr <<
help.toLocal8Bit().constData();
1420 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1422 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1424 msg << versionStr << Qt::endl;
1426 if (
toString(
"showhelp").isEmpty())
1431 if (descr.size() > 0)
1432 msg << Qt::endl << descr << Qt::endl << Qt::endl;
1435 QStringList groups(
"");
1439 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1440 if (!groups.contains(cmdarg->m_group))
1441 groups << cmdarg->m_group;
1447 for (
const auto & group : std::as_const(groups))
1449 if (group.isEmpty())
1450 msg <<
"Misc. Options:" << Qt::endl << Qt::endl;
1452 msg << group.toLocal8Bit().constData() <<
" Options:" << Qt::endl << Qt::endl;
1455 msg << cmdarg->GetHelpString(maxlen, group);
1462 QString optstr =
"-" +
toString(
"showhelp");
1465 optstr =
"-" + optstr;
1467 return QString(
"Could not find option matching '%1'\n")
1482 int &argpos, QString &opt, QByteArray &val)
1491 QByteArray
tmp(argv[argpos]);
1503 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1512 if (
tmp.contains(
'='))
1515 QList<QByteArray> blist =
tmp.split(
'=');
1517 if (blist.size() != 2)
1531 if (argpos+1 >= argc)
1535 tmp = QByteArray(argv[++argpos]);
1540 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1574 for (
int argpos = 1; argpos < argc; ++argpos)
1578 res =
getOpt(argc, argv, argpos, opt, val);
1583 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1584 <<
"val: " << val.constData() << std::endl << std::endl;
1590 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1607 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1608 << opt.toLocal8Bit().constData();
1625 std::cerr <<
"Received '"
1627 <<
"' but unassociated arguments have not been enabled"
1640 std::cerr <<
"Command line arguments received out of sequence"
1647 if (opt.startsWith(
"-psn_"))
1649 std::cerr <<
"Ignoring Process Serial Number from command line"
1662 QByteArray
tmp = opt.toLocal8Bit();
1671 std::cerr <<
"Unhandled option given on command line:" << std::endl
1672 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1695 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1701 if (!argdef->
Set(opt))
1710 if (!argdef->
Set(opt, val))
1731 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1737 std::cerr <<
"Processed option list:" << std::endl;
1739 cmdarg->PrintVerbose();
1743 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1745 for (
const auto& lopt : std::as_const(slist))
1746 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1751 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1752 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1755 std::cerr << std::endl;
1761 if (!cmdarg->TestLinks())
1763 QString keyword = cmdarg->m_usedKeyword;
1764 if (keyword.startsWith(
'-'))
1766 if (keyword.startsWith(
"--"))
1767 keyword.remove(0,2);
1769 keyword.remove(0,1);
1781 QString
help, QString longhelp)
1783 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1787 QString
help, QString longhelp)
1789 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1793 QString
help, QString longhelp)
1795 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1799 QString
help, QString longhelp)
1801 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1805 QString
help, QString longhelp)
1807 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1811 QString
help, QString longhelp)
1813 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1817 QString
help, QString longhelp)
1819 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1823 QString
help, QString longhelp)
1825 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1829 QString
help, QString longhelp)
1831 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1835 QString
help, QString longhelp)
1837 return add(QStringList(arg), name,
type,
1838#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1839 QVariant(
static_cast<QVariant::Type
>(
type)),
1841 QVariant(QMetaType(
type)),
1843 std::move(
help), std::move(longhelp));
1847 QMetaType::Type
type,
1848 QVariant def, QString
help, QString longhelp)
1850 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1854 QString
help, QString longhelp)
1856 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1860 QString
help, QString longhelp)
1862 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1866 QString
help, QString longhelp)
1868 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1872 QString
help, QString longhelp)
1874 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1878 QString
help, QString longhelp)
1880 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1884 QString
help, QString longhelp)
1886 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1890 QString
help, QString longhelp)
1892 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1896 QString
help, QString longhelp)
1898 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1902 QString
help, QString longhelp)
1904 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1908 QMetaType::Type
type,
1909 QString
help, QString longhelp)
1911 return add(std::move(arglist), name,
type,
1912#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1913 QVariant(
static_cast<QVariant::Type
>(
type)),
1915 QVariant(QMetaType(
type)),
1917 std::move(
help), std::move(longhelp));
1926 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1928 QMap<QString,CommandLineArg*>::iterator args_it;
1931 QList<CommandLineArg*> links = (*args_it)->m_parents;
1932 QList<CommandLineArg*>::iterator links_it;
1933 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1935 if ((*links_it)->m_type != QMetaType::UnknownType)
1941 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1942 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1943 <<
"' could not find '"
1944 << (*links_it)->m_name.toLocal8Bit().constData()
1945 <<
"'." << std::endl
1946 <<
" Please resolve dependency and recompile." << std::endl;
1953 std::cerr << QString(
" Setting %1 as child of %2")
1954 .arg((*args_it)->m_name, (*links_it)->m_name)
1955 .toLocal8Bit().constData()
1958 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1961 links = (*args_it)->m_children;
1962 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1964 if ((*links_it)->m_type != QMetaType::UnknownType)
1970 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1971 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1972 <<
"' could not find '"
1973 << (*links_it)->m_name.toLocal8Bit().constData()
1974 <<
"'." << std::endl
1975 <<
" Please resolve dependency and recompile." << std::endl;
1982 std::cerr << QString(
" Setting %1 as parent of %2")
1983 .arg((*args_it)->m_name, (*links_it)->m_name)
1984 .toLocal8Bit().constData()
1987 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1990 links = (*args_it)->m_requires;
1991 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1993 if ((*links_it)->m_type != QMetaType::UnknownType)
1999 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
2000 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
2001 <<
"' could not find '"
2002 << (*links_it)->m_name.toLocal8Bit().constData()
2003 <<
"'." << std::endl
2004 <<
" Please resolve dependency and recompile." << std::endl;
2011 std::cerr << QString(
" Setting %1 as requiring %2")
2012 .arg((*args_it)->m_name, (*links_it)->m_name)
2013 .toLocal8Bit().constData()
2016 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2019 QList<CommandLineArg*>::iterator req_it =
2020 (*args_it)->m_requiredby.begin();
2021 while (req_it != (*args_it)->m_requiredby.end())
2023 if ((*req_it)->m_type == QMetaType::UnknownType)
2028 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2031 std::cerr << QString(
" Setting %1 as blocking %2")
2032 .arg((*args_it)->m_name,
2034 .toLocal8Bit().constData()
2040 (*req_it)->DecrRef();
2041 req_it = (*args_it)->m_requiredby.erase(req_it);
2044 QList<CommandLineArg*>::iterator block_it =
2045 (*args_it)->m_blocks.begin();
2046 while (block_it != (*args_it)->m_blocks.end())
2048 if ((*block_it)->m_type != QMetaType::UnknownType)
2056 (*block_it)->DecrRef();
2057 block_it = (*args_it)->m_blocks.erase(block_it);
2064 std::cerr << QString(
" Setting %1 as blocking %2")
2065 .arg((*args_it)->m_name, (*block_it)->m_name)
2066 .toLocal8Bit().constData()
2069 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2109 return toMap(
"_extra");
2128 QMap<QString,QString> smap =
toMap(
"overridesettings");
2132 if (
toBool(
"overridesettingsfile"))
2138 if (f.open(QIODevice::ReadOnly))
2141 while (!in.atEnd()) {
2142 QString line = in.readLine().trimmed();
2143 QStringList tokens = line.split(
"=",
2144 Qt::SkipEmptyParts);
2145 if (tokens.size() == 2)
2147 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2148 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2149 tokens[0].remove(kQuoteStartRE);
2150 tokens[0].remove(kQuoteEndRE);
2151 tokens[1].remove(kQuoteStartRE);
2152 tokens[1].remove(kQuoteEndRE);
2153 if (!tokens[0].isEmpty())
2154 smap[tokens[0]] = tokens[1];
2161 std::cerr <<
"Failed to open the override settings file: '"
2162 <<
tmp.constData() <<
"'" << std::endl;
2168 smap[
"RunFrontendInWindow"] =
"1";
2169 else if (
toBool(
"notwindowed"))
2170 smap[
"RunFrontendInWindow"] =
"0";
2172 if (
toBool(
"mousecursor"))
2173 smap[
"HideMouseCursor"] =
"0";
2174 else if (
toBool(
"nomousecursor"))
2175 smap[
"HideMouseCursor"] =
"1";
2179 if (!smap.isEmpty())
2182 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2183 vmap[it.key()] = QVariant(it.value());
2185 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2191 std::cerr <<
"Option Overrides:" << std::endl;
2192 QMap<QString, QString>::const_iterator it;
2193 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2194 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2195 .toLocal8Bit().constData() << std::endl;
2216 if (arg->
m_type == QMetaType::Bool)
2241 if (arg->
m_stored.canConvert<
int>())
2295 if (arg->
m_stored.canConvert<
long long>())
2300 if (arg->
m_default.canConvert<
long long>())
2322 if (arg->
m_stored.canConvert<
double>())
2327 if (arg->
m_default.canConvert<
double>())
2349 if (arg->
m_stored.canConvert<QSize>())
2379 if (arg->
m_stored.canConvert<QString>())
2384 if (arg->
m_default.canConvert<QString>())
2418 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2419 val = varval.toString().split(sep);
2420 else if (varval.canConvert<QStringList>())
2421 val = varval.toStringList();
2431 QMap<QString, QString> val;
2432 QMap<QString, QVariant>
tmp;
2445 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2450 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2454 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2455 val[i.key()] = i.value().toString();
2475 if (arg->
m_stored.canConvert<QDateTime>())
2480 if (arg->
m_default.canConvert<QDateTime>())
2502 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2521 QMap<QString,QVariant> vmap;
2522 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2543 QMetaType::QStringList, QStringList());
2551 add(QStringList{
"-h",
"--help",
"--usage"},
2552 "showhelp",
"",
"Display this help printout, or give detailed "
2553 "information of selected option.",
2554 "Displays a list of all commands available for use with "
2555 "this application. If another option is provided as an "
2556 "argument, it will provide detailed information on that "
2564 add(
"--version",
"showversion",
false,
"Display version information.",
2565 "Display informtion about build, including:\n"
2566 " version, branch, protocol, library API, Qt "
2567 "and compiled options.");
2574 add(QStringList{
"-nw",
"--no-windowed"},
2575 "notwindowed",
false,
2576 "Prevent application from running in a window.",
"")
2577 ->SetBlocks(
"windowed")
2580 add(QStringList{
"-w",
"--windowed"},
"windowed",
2581 false,
"Force application to run in a window.",
"")
2582 ->SetGroup(
"User Interface");
2589 add(
"--mouse-cursor",
"mousecursor",
false,
2590 "Force visibility of the mouse cursor.",
"")
2594 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2595 "Force the mouse cursor to be hidden.",
"")
2603 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2604 "Fork application into background after startup.",
2605 "Fork application into background, detatching from "
2606 "the local terminal.\nOften used with: "
2607 " --logpath --pidfile --user");
2615 add(QStringList{
"-O",
"--override-setting"},
2616 "overridesettings", QMetaType::QVariantMap,
2617 "Override a single setting defined by a key=value pair.",
2618 "Override a single setting from the database using "
2619 "options defined as one or more key=value pairs\n"
2620 "Multiple can be defined by multiple uses of the "
2622 add(
"--override-settings-file",
"overridesettingsfile",
"",
2623 "Define a file of key=value pairs to be "
2624 "loaded for setting overrides.",
"");
2631 add(
"--chanid",
"chanid", 0U,
2632 "Specify chanid of recording to operate on.",
"")
2635 add(
"--starttime",
"starttime", QDateTime(),
2636 "Specify start time of recording to operate on.",
"")
2644 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2645 "",
"Specify window size and position (WxH[+X+Y])",
"")
2646 ->SetGroup(
"User Interface");
2653 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2660 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2667 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2670 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2671 LOG_INFO : defaultLogLevel;
2675 add(QStringList{
"-v",
"--verbose"},
"verbose",
2677 "Specify log filtering. Use '-v help' for level info.",
"")
2678 ->SetGroup(
"Logging");
2679 add(
"-V",
"verboseint", 0LL,
"",
2680 "This option is intended for internal use only.\n"
2681 "This option takes an unsigned value corresponding "
2682 "to the bitwise log verbosity operator.")
2684 add(
"--logpath",
"logpath",
"",
2685 "Writes logging messages to a file in the directory logpath with "
2686 "filenames in the format: applicationName.date.pid.log.\n"
2687 "This is typically used in combination with --daemon, and if used "
2688 "in combination with --pidfile, this can be used with log "
2689 "rotators, using the HUP call to inform MythTV to reload the "
2692 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2693 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2694 ->SetGroup(
"Logging");
2695 add(
"--loglong",
"loglong", 0,
2696 "Use long log format for the console, i.e. show file, line number, etc. in the console log.",
"")
2698 add(
"--loglevel",
"loglevel", logLevelStr,
2700 "Set the logging level. All log messages at lower levels will be "
2702 "In descending order: emerg, alert, crit, err, warning, notice, "
2703 "info, debug, trace\ndefaults to ") + logLevelStr,
"")
2705 add(
"--syslog",
"syslog",
"none",
2706 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2707 "defaults to none.",
"")
2709#if CONFIG_SYSTEMD_JOURNAL
2710 add(
"--systemd-journal",
"systemd-journal",
"false",
2711 "Use systemd-journal instead of syslog.",
"")
2717 add(
"--nodblog",
"nodblog",
false,
"",
"")
2719 ->
SetRemoved(
"Database logging has been removed.",
"34");
2720 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2722 ->
SetRemoved(
"Database logging has been removed.",
"34");
2724 add(QStringList{
"-l",
"--logfile"},
2725 "logfile",
"",
"",
"")
2726 ->SetGroup(
"Logging")
2727 ->
SetRemoved(
"This option has been removed as part of "
2728 "rewrite of the logging interface. Please update your init "
2729 "scripts to use --syslog to interface with your system's "
2730 "existing system logging daemon, or --logpath to specify a "
2731 "dirctory for MythTV to write its logs to.",
"0.25");
2738 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2739 "Write PID of application to filename.",
2740 "Write the PID of the currently running process as a single "
2741 "line to this file. Used for init scripts to know what "
2742 "process to terminate, and with log rotators "
2743 "to send a HUP signal to process to have it re-open files.");
2750 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2751 "Intended for internal use only, specify the JobID to match "
2752 "up with in the database for additional information and the "
2753 "ability to update runtime status in the database.");
2760 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2762 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2770 add(QStringList{
"-display",
"--display"},
"display",
"",
2771 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2780 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2781 "Qt platform argument that is passed through to Qt")
2789 QString logfile =
toString(
"logpath");
2790 pid_t pid = getpid();
2792 if (logfile.isEmpty())
2795 QFileInfo finfo(logfile);
2798 LOG(VB_GENERAL, LOG_ERR,
2799 QString(
"%1 is not a directory, disabling logfiles")
2804 QString logdir = finfo.filePath();
2805 logfile = QCoreApplication::applicationName() +
"." +
2807 QString(
".%1").arg(pid) +
".log";
2811 SetValue(
"filepath", QFileInfo(QDir(logdir), logfile).filePath());
2820 QString setting =
toString(
"syslog").toLower();
2821 if (setting ==
"none")
2831 QString setting =
toString(
"loglevel");
2832 if (setting.isEmpty())
2836 if (level == LOG_UNKNOWN)
2837 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2853 const QVariant& val(value);
2854#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2855 auto type =
static_cast<QMetaType::Type
>(val.type());
2857 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2865#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2866 auto type =
static_cast<QMetaType::Type
>(value.type());
2868 auto type = value.typeId();
2893 else if (
toBool(
"verboseint"))
2900 int quiet =
toInt(
"quiet");
2901 if (std::max(quiet,
static_cast<int>(
progress)) > 1)
2907 bool loglong =
toBool(
"loglong");
2910#if CONFIG_SYSTEMD_JOURNAL
2911 bool journal =
toBool(
"systemd-journal");
2916 facility = SYSTEMD_JOURNAL_FACILITY;
2920 if (level == LOG_UNKNOWN)
2923 LOG(VB_GENERAL, LOG_CRIT,
2924 QString(
"%1 version: %2 [%3] www.mythtv.org")
2925 .arg(QCoreApplication::applicationName(),
2927 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2928 .arg(QT_VERSION_STR, qVersion()));
2929 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2930 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2931 LOG(VB_GENERAL, LOG_NOTICE,
2935 bool propagate = !logfile.isEmpty();
2938 quiet = std::max(quiet, 1);
2941 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2942 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2954 std::cerr <<
"Applying settings override" << std::endl;
2957 if (!
override.empty())
2959 QMap<QString, QString>::iterator it;
2960 for (it =
override.begin(); it !=
override.end(); ++it)
2962 LOG(VB_GENERAL, LOG_NOTICE,
2963 QString(
"Setting '%1' being forced to '%2'")
2964 .arg(it.key(), *it));
2972 if (!pidfile.isEmpty())
2974 pidfs.open(pidfile.toLatin1().constData());
2977 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2988 if (username.isEmpty())
2992 std::cerr <<
"--user option is not supported on Windows" << std::endl;
2998 int dumpability = prctl(PR_GET_DUMPABLE);
3000 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
3001 const uid_t user_id =
geteuid();
3005 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
3010 LOG(VB_GENERAL, LOG_WARNING,
3011 QString(
"Already running as '%1'").arg(username));
3017 std::cerr <<
"Error setting home directory." << std::endl;
3022 std::cerr <<
"Error setting effective group." << std::endl;
3027 std::cerr <<
"Error setting groups." << std::endl;
3032 std::cerr <<
"Error setting effective user." << std::endl;
3036 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3038 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3039 "creation. Run without the --user argument to use "
3040 "shell-specified limits.");
3046 std::cerr << QString(
"Invalid user '%1' specified with --user")
3047 .arg(username).toLocal8Bit().constData() << std::endl;
3059 std::ofstream pidfs;
3063 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3064 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3069 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
3070 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3075 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
3080 QString username =
toString(
"username");
3081 if (!username.isEmpty() && !
setUser(username))
3086 pidfs << getpid() << std::endl;
Definition for a single command line option.
CommandLineArg * SetRequires(const QString &opt)
Set argument as requiring given option.
static void AllowOneOf(const QList< CommandLineArg * > &args)
Mark a list of arguments as mutually exclusive.
QList< CommandLineArg * > m_requiredby
CommandLineArg * SetParent(const QString &opt)
Set argument as child of given parent.
int GetKeywordLength(void) const
Return length of full keyword string for use in determining indent of help text.
CommandLineArg * SetRequiredChild(const QString &opt)
Set argument as parent of given child and mark as required.
CommandLineArg * SetChildOf(const QString &opt)
Set argument as child of given parent.
CommandLineArg(const QString &name, QMetaType::Type type, QVariant def, QString help, QString longhelp)
Default constructor for CommandLineArg class.
void PrintVerbose(void) const
Internal use.
QString GetKeywordString(void) const
Return string containing all possible keyword triggers for this argument.
CommandLineArg * SetRemoved(QString remstr="", QString remver="")
Set option as removed.
bool TestLinks(void) const
Test all related arguments to make sure specified requirements are fulfilled.
CommandLineArg * SetDeprecated(QString depstr="")
Set option as deprecated.
void PrintDeprecatedWarning(QString &keyword) const
Internal use.
bool Set(const QString &opt)
Set option as provided on command line with no value.
CommandLineArg * SetChild(const QString &opt)
Set argument as parent of given child.
CommandLineArg * SetGroup(const QString &group)
CommandLineArg * SetParentOf(const QString &opt)
Set argument as parent of given child.
CommandLineArg * SetBlocks(const QString &opt)
Set argument as incompatible with given option.
void CleanupLinks(void)
Clear out references to other arguments in preparation for deletion.
QList< CommandLineArg * > m_children
QList< CommandLineArg * > m_blocks
QList< CommandLineArg * > m_requires
void PrintRemovedWarning(QString &keyword) const
Internal use.
QString GetName(void) const
void AddKeyword(const QString &keyword)
QString GetPreferredKeyword(void) const
Return the longest keyword for the argument.
QString GetLongHelpString(QString keyword) const
Return string containing extended help text.
QString GetHelpString(int off, const QString &group="", bool force=false) const
Return string containing help text with desired offset.
void Convert(void)
Convert stored string value from QByteArray to QString.
QList< CommandLineArg * > m_parents
CommandLineArg * SetRequiredChildOf(const QString &opt)
Set argument as child required by given parent.
static const char * NamedOptType(Result type)
void addVersion(void)
Canned argument definition for –version.
QMap< QString, CommandLineArg * > m_optionedArgs
void addPlatform(void)
Pass through the platform argument to Qt for GUI applications.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
static QStringList MythSplitCommandString(const QString &line)
Parse a string into separate tokens.
Result getOpt(int argc, const char *const *argv, int &argpos, QString &opt, QByteArray &val)
Internal use.
MythCommandLineParser(QString appname)
Default constructor for MythCommandLineArg class.
virtual bool Parse(int argc, const char *const *argv)
Loop through argv and populate arguments with values.
double toDouble(const QString &key) const
Returns stored QVariant as double floating point value, falling to default if not provided.
int GetSyslogFacility(void) const
Helper utility for logging interface to return syslog facility.
void ApplySettingsOverride(void)
Apply all overrides to the global context.
QSize toSize(const QString &key) const
Returns stored QVariant as a QSize value, falling to default if not provided.
void addWindowed(void)
Canned argument definition for –windowed and -no-windowed.
void addPIDFile(void)
Canned argument definition for –pidfile.
void addSettingsOverride(void)
Canned argument definition for –override-setting and –override-settings-file.
int Daemonize(void) const
Fork application into background, and detatch from terminal.
void addDisplay(void)
Canned argument definition for -display.
void addRecording(void)
Canned argument definition for –chanid and –starttime.
int ConfigureLogging(const QString &mask="general", bool progress=false)
Read in logging options and initialize the logging interface.
void addLogging(const QString &defaultVerbosity="general", LogLevel_t defaultLogLevel=LOG_INFO)
Canned argument definition for all logging options, including –verbose, –logpath, –quiet,...
QMap< QString, QString > GetExtra(void) const
Return map of additional key/value pairs provided on the command line independent of any registered a...
void addDVBv3(void)
Canned argument definition for –dvbv3.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
QString GetPassthrough(void) const
Return any text supplied on the command line after a bare '–'.
long long toLongLong(const QString &key) const
Returns stored QVariant as a long integer, falling to default if not provided.
QMap< QString, CommandLineArg * > m_namedArgs
virtual ~MythCommandLineParser()
QMap< QString, QString > GetSettingsOverride(void)
Return map of key/value pairs provided to override database options.
static void PrintVersion(void)
Print application version information.
QString GetLogFilePath(void)
Helper utility for logging interface to pull path from –logpath.
CommandLineArg * add(const QString &arg, const QString &name, bool def, QString help, QString longhelp)
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 addMouse(void)
Canned argument definition for –mouse-cursor and –no-mouse-cursor.
LogLevel_t GetLogLevel(void) const
Helper utility for logging interface to filtering level.
void addHelp(void)
Canned argument definition for –help.
QVariant operator[](const QString &name)
Returned stored QVariant for given argument, or default value if not used.
QString GetHelpString(void) const
Generate command line option help text.
QDateTime toDateTime(const QString &key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
QMap< QString, QString > toMap(const QString &key) const
Returns stored QVariant as a QMap, falling to default if not provided.
void addGeometry(void)
Canned argument definition for –geometry.
void allowPassthrough(bool allow=true)
Specify that parser should allow a bare '–', and collect all subsequent text as a QString.
void addUPnP(void)
Canned argument definition for –noupnp.
void addDaemon(void)
Canned argument definition for –daemon.
void addInFile(bool addOutFile=false)
Canned argument definition for –infile and –outfile.
virtual QString GetHelpHeader(void) const
QStringList toStringList(const QString &key, const QString &sep="") const
Returns stored QVariant as a QStringList, falling to default if not provided.
virtual void LoadArguments(void)
void allowArgs(bool allow=true)
Specify that parser should allow and collect values provided independent of any keyword.
void allowExtras(bool allow=true)
Specify that parser should allow and collect additional key/value pairs not explicitly defined for pr...
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
QStringList GetArgs(void) const
Return list of additional values provided on the command line independent of any keyword.
void PrintHelp(void) const
Print command line option help.
bool ReconcileLinks(void)
Replace dummy arguments used to define interdependency with pointers to their real counterparts.
void addJob(void)
Canned argument definition for –jobid.
void OverrideSettingForSession(const QString &key, const QString &value)
General purpose reference counter.
virtual int IncrRef(void)
Increments reference count.
@ GENERIC_EXIT_PERMISSIONS_ERROR
File permissions error.
@ GENERIC_EXIT_OK
Exited with no error.
@ GENERIC_EXIT_DAEMONIZING_ERROR
Error daemonizing or execl.
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
static constexpr uint8_t START
int verboseArgParse(const QString &arg)
Parse the –verbose commandline argument and set the verbose level.
QString logLevelGetName(LogLevel_t level)
Map a log level enumerated value back to the name.
LogLevel_t logLevelGet(const QString &level)
Map a log level name back to the enumerated value.
void logStart(const QString &logfile, bool progress, int quiet, int facility, LogLevel_t level, bool propagate, bool loglong, bool testHarness)
Entry point to start logging for the application.
int syslogGetFacility(const QString &facility)
Map a syslog facility name back to the enumerated value.
static int GetTermWidth(void)
returns terminal width, or 79 on error
static constexpr int k_defaultWidth
static QByteArray strip_quotes(const QByteArray &array)
static bool setUser(const QString &username)
Drop permissions to the specified user.
static bool openPidfile(std::ofstream &pidfs, const QString &pidfile)
static void wrapList(QStringList &list, int width)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
const char * GetMythSourceVersion()
const char * GetMythSourcePath()
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
@ kFilename
Default UTC, "yyyyMMddhhmmss".
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
def user_info(user, format="xml")