23#if defined ANDROID && __ANDROID_API__ < 24
41# include <sys/ioctl.h>
44# if defined(__linux__) || defined(__LINUX__)
45# include <sys/prctl.h>
51#include <QCoreApplication>
56#include <QRegularExpression>
61#include <QVariantList>
69#include "mythconfig.h"
71#include "mythversion.h"
83#if defined(_WIN32) || defined(Q_OS_ANDROID)
88 if (ioctl(0, TIOCGWINSZ, &ws) != 0)
91 return static_cast<int>(ws.ws_col);
97 return ((array.startsWith(
'"') && array.endsWith(
'"') ) ||
98 (array.startsWith(
'\'') && array.endsWith(
'\''))
99 ) ? array.mid(1, array.size() - 2) : array;
106 width = std::max(width, 5);
108 for (
int i = 0; i < list.size(); i++)
110 QString
string = list.at(i);
112 if(
string.size() <= width )
115 QString left =
string.left(width);
116 bool inserted =
false;
118 while( !inserted && !left.endsWith(
" " ))
120 if(
string.mid(left.size(), 1) ==
" " )
122 list.replace(i, left);
123 list.insert(i+1,
string.mid(left.size()).trimmed());
129 if( !left.contains(
" ") )
132 list.replace(i, left +
"-");
133 list.insert(i+1,
string.mid(left.size()));
142 list.replace(i, left);
143 list.insert(i+1,
string.mid(left.size()).trimmed());
158 enum states : std::uint8_t {
167 states state =
START;
170 for (
int i = 0; i < line.size(); i++)
172 const QChar c = line.at(i);
177 if (c.isSpace())
break;
178 if (c ==
'\'') state = INSQUOTE;
179 else if (c ==
'\"') state = INDQUOTE;
180 else if (c ==
'\\') state = ESCTEXT;
185 fields += line.mid(tokenStart, i - tokenStart);
189 else if (c ==
'\'') {
191 }
else if (c ==
'\"') {
193 }
else if (c ==
'\\') {
198 if (c ==
'\'') state = INTEXT;
199 else if (c ==
'\\') state = ESCSQUOTE;
202 if (c ==
'\"') state = INTEXT;
203 else if (c ==
'\\') state = ESCDQUOTE;
205 case ESCTEXT: state = INTEXT;
break;
206 case ESCSQUOTE: state = INSQUOTE;
break;
207 case ESCDQUOTE: state = INDQUOTE;
break;
212 fields += line.mid(tokenStart);
236 return "kCombOptVal";
242 return "kPassthrough";
285 QVariant def, QString
help, QString longhelp) :
287 m_name(name), m_type(
type), m_default(
std::move(def)),
288 m_help(
std::move(
help)), m_longhelp(
std::move(longhelp))
290 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
291 (
m_type != QMetaType::QVariantMap))
303 m_name(name), m_type(
type), m_default(
std::move(def))
305 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
306 (
m_type != QMetaType::QVariantMap))
340 QList<CommandLineArg*>::const_iterator i1;
342 len = std::max(len, (*i1)->GetKeywordLength()+2);
365 QTextStream msg(&helpstr, QIODevice::WriteOnly);
410 QStringList hlist =
m_help.split(
'\n');
416 << hlist.takeFirst() << Qt::endl;
419 for (
const auto & line : std::as_const(hlist))
420 msg << pad << line << Qt::endl;
424 msg << arg->GetHelpString(off, group,
true);
440 QTextStream msg(&helpstr, QIODevice::WriteOnly);
458 msg <<
"Option: " << keyword << Qt::endl << Qt::endl;
463 for (
const auto & word : std::as_const(
m_keywords))
469 msg <<
"Aliases: " << word << Qt::endl;
474 msg <<
" " << word << Qt::endl;
480 msg <<
"Type: " << QMetaType(
m_type).name() << Qt::endl;
482 msg <<
"Default: " <<
m_default.toString() << Qt::endl;
492 msg <<
"Description: " <<
help.takeFirst() << Qt::endl;
493 for (
const auto & line : std::as_const(
help))
494 msg <<
" " << line << Qt::endl;
496 QList<CommandLineArg*>::const_iterator i2;
501 msg << Qt::endl <<
"Can be used in combination with:" << Qt::endl;
502 for (
auto * parent : std::as_const(
m_parents))
503 msg <<
" " << parent->GetPreferredKeyword()
504 .toLocal8Bit().constData();
510 msg << Qt::endl <<
"Allows the use of:" << Qt::endl;
512 msg <<
" " << (*i2)->GetPreferredKeyword()
513 .toLocal8Bit().constData();
519 msg << Qt::endl <<
"Requires the use of:" << Qt::endl;
521 msg <<
" " << (*i2)->GetPreferredKeyword()
522 .toLocal8Bit().constData();
528 msg << Qt::endl <<
"Prevents the use of:" << Qt::endl;
530 msg <<
" " << (*i2)->GetPreferredKeyword()
531 .toLocal8Bit().constData();
551 case QMetaType::Bool:
562 case QMetaType::QString:
567 std::cerr <<
"Command line option did not receive value:" << std::endl
568 <<
" " << opt.toLocal8Bit().constData() << std::endl;
581 QList<QByteArray> blist;
587 case QMetaType::Bool:
588 std::cerr <<
"Boolean type options do not accept values:" << std::endl
589 <<
" " << opt.toLocal8Bit().constData() << std::endl;
592 case QMetaType::QString:
600 case QMetaType::UInt:
604 case QMetaType::LongLong:
605 m_stored = QVariant(val.toLongLong());
608 case QMetaType::Double:
609 m_stored = QVariant(val.toDouble());
612 case QMetaType::QDateTime:
616 case QMetaType::QStringList:
623 case QMetaType::QVariantMap:
624 if (!val.contains(
'='))
626 std::cerr <<
"Command line option did not get expected "
627 <<
"key/value pair" << std::endl;
631 blist = val.split(
'=');
639 case QMetaType::QSize:
640 if (!val.contains(
'x'))
642 std::cerr <<
"Command line option did not get expected "
643 <<
"XxY pair" << std::endl;
647 blist = val.split(
'x');
648 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
671 for (
const auto& opt : std::as_const(
opts))
688 for (
const auto& opt : std::as_const(
opts))
705 for (
const auto& opt : std::as_const(
opts))
722 for (
const auto& opt : std::as_const(
opts))
740 for (
const auto& opt : std::as_const(
opts))
761 for (
const auto& opt : std::as_const(
opts))
781 for (
const auto& opt : std::as_const(
opts))
798 for (
const auto& opt : std::as_const(
opts))
807 if (depstr.isEmpty())
808 depstr =
"and will be removed in a future version.";
817 if (remstr.isEmpty())
818 remstr =
"and is no longer available in this version.";
831 bool replaced =
false;
859 bool replaced =
false;
862 for (
int i = 0; i <
m_parents.size(); i++)
887 bool replaced =
false;
916 bool replaced =
false;
919 for (
int i = 0; i <
m_blocks.size(); i++)
947 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
951 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
953 (*i1)->SetBlocks(*i2);
956 if ((*i1)->m_type == QMetaType::UnknownType)
969 if (!QCoreApplication::instance())
984#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
985 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
987 auto storedType =
m_stored.typeId();
989 if (
m_type == QMetaType::QString)
991 if (storedType == QMetaType::QByteArray)
999 else if (
m_type == QMetaType::QStringList)
1001 if (storedType == QMetaType::QVariantList)
1003 QVariantList vlist =
m_stored.toList();
1005 for (
const auto& item : std::as_const(vlist))
1006 slist << QString::fromLocal8Bit(item.toByteArray());
1010 else if (
m_type == QMetaType::QVariantMap)
1012 QVariantMap vmap =
m_stored.toMap();
1014 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1015 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1033 QStringList::const_iterator it;
1039 int len2 = (*it).size();
1058 QList<CommandLineArg*>::const_iterator i;
1060 bool passes =
false;
1072 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1073 <<
" requires at least one of the following arguments" << std::endl;
1076 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1077 std::cerr << std::endl << std::endl;
1088 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1089 <<
" requires all of the following be defined as well"
1094 << (*i)->GetPreferredKeyword().toLocal8Bit()
1097 std::cerr << std::endl << std::endl;
1107 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1108 <<
" requires that none of the following be defined" << std::endl;
1112 << (*i)->GetPreferredKeyword().toLocal8Bit()
1115 std::cerr << std::endl << std::endl;
1151 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1154 QMap<QString, QVariant> tmpmap;
1155 QMap<QString, QVariant>::const_iterator it;
1161 case QMetaType::Bool:
1162 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1165 case QMetaType::Int:
1166 std::cerr <<
m_stored.toInt() << std::endl;
1169 case QMetaType::UInt:
1170 std::cerr <<
m_stored.toUInt() << std::endl;
1173 case QMetaType::LongLong:
1174 std::cerr <<
m_stored.toLongLong() << std::endl;
1177 case QMetaType::Double:
1178 std::cerr <<
m_stored.toDouble() << std::endl;
1181 case QMetaType::QSize:
1183 std::cerr <<
"x=" << tmpsize.width()
1184 <<
" y=" << tmpsize.height()
1188 case QMetaType::QString:
1189 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1190 <<
'"' << std::endl;
1193 case QMetaType::QStringList:
1195 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1196 for (
const auto& str : std::as_const(vlist))
1202 std::cerr << std::endl;
1205 case QMetaType::QVariantMap:
1207 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1212 std::cerr << QString(
"").leftJustified(32)
1213 .toLocal8Bit().constData();
1215 std::cerr << it.key().toLocal8Bit().constData()
1217 << it->toByteArray().constData()
1223 case QMetaType::QDateTime:
1225 .toLocal8Bit().constData()
1230 std::cerr << std::endl;
1238 QString warn = QString(
"%1 has been removed").arg(keyword);
1242 std::cerr << QString(
"****************************************************\n"
1245 "****************************************************\n\n")
1247 .toLocal8Bit().constData();
1254 std::cerr << QString(
"****************************************************\n"
1255 " WARNING: %1 has been deprecated\n"
1257 "****************************************************\n\n")
1259 .toLocal8Bit().constData();
1276 : m_appname(
std::move(appname))
1278 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1280 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1289 QString pidfile =
toString(
"pidfile");
1290 if (!pidfile.isEmpty())
1292 QFile::remove(pidfile);
1295 QMap<QString, CommandLineArg*>::iterator i;
1300 (*i)->CleanupLinks();
1347 const QString& name, QMetaType::Type
type, QVariant def,
1348 QString
help, QString longhelp)
1360 for (
const auto & str : std::as_const(arglist))
1367 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1368 <<
" as taking type '"
1369#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1370 << QVariant::typeToName(
static_cast<int>(
type))
1372 << QMetaType(
type).name()
1374 <<
"'" << std::endl;
1388 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1391 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1392 std::cout <<
"Library API : " << MYTH_BINARY_VERSION << std::endl;
1393 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1394#ifdef MYTH_BUILD_CONFIG
1395 std::cout <<
"Options compiled in:" <<std::endl;
1396 std::cout << MYTH_BUILD_CONFIG << std::endl;
1405 std::cerr <<
help.toLocal8Bit().constData();
1416 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1418 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1420 msg << versionStr << Qt::endl;
1422 if (
toString(
"showhelp").isEmpty())
1427 if (descr.size() > 0)
1428 msg << Qt::endl << descr << Qt::endl << Qt::endl;
1431 QStringList groups(
"");
1435 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1436 if (!groups.contains(cmdarg->m_group))
1437 groups << cmdarg->m_group;
1443 for (
const auto & group : std::as_const(groups))
1445 if (group.isEmpty())
1446 msg <<
"Misc. Options:" << Qt::endl << Qt::endl;
1448 msg << group.toLocal8Bit().constData() <<
" Options:" << Qt::endl << Qt::endl;
1451 msg << cmdarg->GetHelpString(maxlen, group);
1458 QString optstr =
"-" +
toString(
"showhelp");
1461 optstr =
"-" + optstr;
1463 return QString(
"Could not find option matching '%1'\n")
1478 int &argpos, QString &opt, QByteArray &val)
1487 QByteArray
tmp(argv[argpos]);
1499 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1508 if (
tmp.contains(
'='))
1511 QList<QByteArray> blist =
tmp.split(
'=');
1513 if (blist.size() != 2)
1527 if (argpos+1 >= argc)
1531 tmp = QByteArray(argv[++argpos]);
1536 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1570 for (
int argpos = 1; argpos < argc; ++argpos)
1574 res =
getOpt(argc, argv, argpos, opt, val);
1579 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1580 <<
"val: " << val.constData() << std::endl << std::endl;
1586 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1603 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1604 << opt.toLocal8Bit().constData();
1621 std::cerr <<
"Received '"
1623 <<
"' but unassociated arguments have not been enabled"
1636 std::cerr <<
"Command line arguments received out of sequence"
1643 if (opt.startsWith(
"-psn_"))
1645 std::cerr <<
"Ignoring Process Serial Number from command line"
1658 QByteArray
tmp = opt.toLocal8Bit();
1667 std::cerr <<
"Unhandled option given on command line:" << std::endl
1668 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1691 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1697 if (!argdef->
Set(opt))
1706 if (!argdef->
Set(opt, val))
1727 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1733 std::cerr <<
"Processed option list:" << std::endl;
1735 cmdarg->PrintVerbose();
1739 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1741 for (
const auto& lopt : std::as_const(slist))
1742 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1747 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1748 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1751 std::cerr << std::endl;
1757 if (!cmdarg->TestLinks())
1759 QString keyword = cmdarg->m_usedKeyword;
1760 if (keyword.startsWith(
'-'))
1762 if (keyword.startsWith(
"--"))
1763 keyword.remove(0,2);
1765 keyword.remove(0,1);
1777 QString
help, QString longhelp)
1779 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1783 QString
help, QString longhelp)
1785 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1789 QString
help, QString longhelp)
1791 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1795 QString
help, QString longhelp)
1797 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1801 QString
help, QString longhelp)
1803 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1807 QString
help, QString longhelp)
1809 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1813 QString
help, QString longhelp)
1815 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1819 QString
help, QString longhelp)
1821 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1825 QString
help, QString longhelp)
1827 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1831 QString
help, QString longhelp)
1833 return add(QStringList(arg), name,
type,
1834#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1835 QVariant(
static_cast<QVariant::Type
>(
type)),
1837 QVariant(QMetaType(
type)),
1839 std::move(
help), std::move(longhelp));
1843 QMetaType::Type
type,
1844 QVariant def, QString
help, QString longhelp)
1846 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1850 QString
help, QString longhelp)
1852 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1856 QString
help, QString longhelp)
1858 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1862 QString
help, QString longhelp)
1864 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1868 QString
help, QString longhelp)
1870 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1874 QString
help, QString longhelp)
1876 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1880 QString
help, QString longhelp)
1882 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1886 QString
help, QString longhelp)
1888 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1892 QString
help, QString longhelp)
1894 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1898 QString
help, QString longhelp)
1900 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1904 QMetaType::Type
type,
1905 QString
help, QString longhelp)
1907 return add(std::move(arglist), name,
type,
1908#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1909 QVariant(
static_cast<QVariant::Type
>(
type)),
1911 QVariant(QMetaType(
type)),
1913 std::move(
help), std::move(longhelp));
1922 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1924 QMap<QString,CommandLineArg*>::iterator args_it;
1927 QList<CommandLineArg*> links = (*args_it)->m_parents;
1928 QList<CommandLineArg*>::iterator links_it;
1929 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1931 if ((*links_it)->m_type != QMetaType::UnknownType)
1937 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1938 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1939 <<
"' could not find '"
1940 << (*links_it)->m_name.toLocal8Bit().constData()
1941 <<
"'." << std::endl
1942 <<
" Please resolve dependency and recompile." << std::endl;
1949 std::cerr << QString(
" Setting %1 as child of %2")
1950 .arg((*args_it)->m_name, (*links_it)->m_name)
1951 .toLocal8Bit().constData()
1954 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1957 links = (*args_it)->m_children;
1958 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1960 if ((*links_it)->m_type != QMetaType::UnknownType)
1966 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1967 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1968 <<
"' could not find '"
1969 << (*links_it)->m_name.toLocal8Bit().constData()
1970 <<
"'." << std::endl
1971 <<
" Please resolve dependency and recompile." << std::endl;
1978 std::cerr << QString(
" Setting %1 as parent of %2")
1979 .arg((*args_it)->m_name, (*links_it)->m_name)
1980 .toLocal8Bit().constData()
1983 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1986 links = (*args_it)->m_requires;
1987 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1989 if ((*links_it)->m_type != QMetaType::UnknownType)
1995 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1996 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1997 <<
"' could not find '"
1998 << (*links_it)->m_name.toLocal8Bit().constData()
1999 <<
"'." << std::endl
2000 <<
" Please resolve dependency and recompile." << std::endl;
2007 std::cerr << QString(
" Setting %1 as requiring %2")
2008 .arg((*args_it)->m_name, (*links_it)->m_name)
2009 .toLocal8Bit().constData()
2012 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2015 QList<CommandLineArg*>::iterator req_it =
2016 (*args_it)->m_requiredby.begin();
2017 while (req_it != (*args_it)->m_requiredby.end())
2019 if ((*req_it)->m_type == QMetaType::UnknownType)
2024 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2027 std::cerr << QString(
" Setting %1 as blocking %2")
2028 .arg((*args_it)->m_name,
2030 .toLocal8Bit().constData()
2036 (*req_it)->DecrRef();
2037 req_it = (*args_it)->m_requiredby.erase(req_it);
2040 QList<CommandLineArg*>::iterator block_it =
2041 (*args_it)->m_blocks.begin();
2042 while (block_it != (*args_it)->m_blocks.end())
2044 if ((*block_it)->m_type != QMetaType::UnknownType)
2052 (*block_it)->DecrRef();
2053 block_it = (*args_it)->m_blocks.erase(block_it);
2060 std::cerr << QString(
" Setting %1 as blocking %2")
2061 .arg((*args_it)->m_name, (*block_it)->m_name)
2062 .toLocal8Bit().constData()
2065 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2105 return toMap(
"_extra");
2124 QMap<QString,QString> smap =
toMap(
"overridesettings");
2128 if (
toBool(
"overridesettingsfile"))
2134 if (f.open(QIODevice::ReadOnly))
2137 while (!in.atEnd()) {
2138 QString line = in.readLine().trimmed();
2139 QStringList tokens = line.split(
"=",
2140 Qt::SkipEmptyParts);
2141 if (tokens.size() == 2)
2143 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2144 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2145 tokens[0].remove(kQuoteStartRE);
2146 tokens[0].remove(kQuoteEndRE);
2147 tokens[1].remove(kQuoteStartRE);
2148 tokens[1].remove(kQuoteEndRE);
2149 if (!tokens[0].isEmpty())
2150 smap[tokens[0]] = tokens[1];
2157 std::cerr <<
"Failed to open the override settings file: '"
2158 <<
tmp.constData() <<
"'" << std::endl;
2164 smap[
"RunFrontendInWindow"] =
"1";
2165 else if (
toBool(
"notwindowed"))
2166 smap[
"RunFrontendInWindow"] =
"0";
2168 if (
toBool(
"mousecursor"))
2169 smap[
"HideMouseCursor"] =
"0";
2170 else if (
toBool(
"nomousecursor"))
2171 smap[
"HideMouseCursor"] =
"1";
2175 if (!smap.isEmpty())
2178 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2179 vmap[it.key()] = QVariant(it.value());
2181 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2187 std::cerr <<
"Option Overrides:" << std::endl;
2188 QMap<QString, QString>::const_iterator it;
2189 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2190 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2191 .toLocal8Bit().constData() << std::endl;
2212 if (arg->
m_type == QMetaType::Bool)
2237 if (arg->
m_stored.canConvert<
int>())
2291 if (arg->
m_stored.canConvert<
long long>())
2296 if (arg->
m_default.canConvert<
long long>())
2318 if (arg->
m_stored.canConvert<
double>())
2323 if (arg->
m_default.canConvert<
double>())
2345 if (arg->
m_stored.canConvert<QSize>())
2375 if (arg->
m_stored.canConvert<QString>())
2380 if (arg->
m_default.canConvert<QString>())
2414 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2415 val = varval.toString().split(sep);
2416 else if (varval.canConvert<QStringList>())
2417 val = varval.toStringList();
2427 QMap<QString, QString> val;
2428 QMap<QString, QVariant>
tmp;
2441 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2446 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2450 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2451 val[i.key()] = i.value().toString();
2471 if (arg->
m_stored.canConvert<QDateTime>())
2476 if (arg->
m_default.canConvert<QDateTime>())
2498 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2517 QMap<QString,QVariant> vmap;
2518 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2539 QMetaType::QStringList, QStringList());
2547 add(QStringList{
"-h",
"--help",
"--usage"},
2548 "showhelp",
"",
"Display this help printout, or give detailed "
2549 "information of selected option.",
2550 "Displays a list of all commands available for use with "
2551 "this application. If another option is provided as an "
2552 "argument, it will provide detailed information on that "
2560 add(
"--version",
"showversion",
false,
"Display version information.",
2561 "Display informtion about build, including:\n"
2562 " version, branch, protocol, library API, Qt "
2563 "and compiled options.");
2570 add(QStringList{
"-nw",
"--no-windowed"},
2571 "notwindowed",
false,
2572 "Prevent application from running in a window.",
"")
2573 ->SetBlocks(
"windowed")
2576 add(QStringList{
"-w",
"--windowed"},
"windowed",
2577 false,
"Force application to run in a window.",
"")
2578 ->SetGroup(
"User Interface");
2585 add(
"--mouse-cursor",
"mousecursor",
false,
2586 "Force visibility of the mouse cursor.",
"")
2590 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2591 "Force the mouse cursor to be hidden.",
"")
2599 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2600 "Fork application into background after startup.",
2601 "Fork application into background, detatching from "
2602 "the local terminal.\nOften used with: "
2603 " --logpath --pidfile --user");
2611 add(QStringList{
"-O",
"--override-setting"},
2612 "overridesettings", QMetaType::QVariantMap,
2613 "Override a single setting defined by a key=value pair.",
2614 "Override a single setting from the database using "
2615 "options defined as one or more key=value pairs\n"
2616 "Multiple can be defined by multiple uses of the "
2618 add(
"--override-settings-file",
"overridesettingsfile",
"",
2619 "Define a file of key=value pairs to be "
2620 "loaded for setting overrides.",
"");
2627 add(
"--chanid",
"chanid", 0U,
2628 "Specify chanid of recording to operate on.",
"")
2631 add(
"--starttime",
"starttime", QDateTime(),
2632 "Specify start time of recording to operate on.",
"")
2640 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2641 "",
"Specify window size and position (WxH[+X+Y])",
"")
2642 ->SetGroup(
"User Interface");
2649 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2656 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2663 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2666 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2667 LOG_INFO : defaultLogLevel;
2671 add(QStringList{
"-v",
"--verbose"},
"verbose",
2673 "Specify log filtering. Use '-v help' for level info.",
"")
2674 ->SetGroup(
"Logging");
2675 add(
"-V",
"verboseint", 0LL,
"",
2676 "This option is intended for internal use only.\n"
2677 "This option takes an unsigned value corresponding "
2678 "to the bitwise log verbosity operator.")
2680 add(
"--logpath",
"logpath",
"",
2681 "Writes logging messages to a file in the directory logpath with "
2682 "filenames in the format: applicationName.date.pid.log.\n"
2683 "This is typically used in combination with --daemon, and if used "
2684 "in combination with --pidfile, this can be used with log "
2685 "rotators, using the HUP call to inform MythTV to reload the "
2688 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2689 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2690 ->SetGroup(
"Logging");
2691 add(
"--loglong",
"loglong", 0,
2692 "Use long log format for the console, i.e. show file, line number, etc. in the console log.",
"")
2694 add(
"--loglevel",
"loglevel", logLevelStr,
2696 "Set the logging level. All log messages at lower levels will be "
2698 "In descending order: emerg, alert, crit, err, warning, notice, "
2699 "info, debug, trace\ndefaults to ") + logLevelStr,
"")
2701 add(
"--syslog",
"syslog",
"none",
2702 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2703 "defaults to none.",
"")
2705#if CONFIG_SYSTEMD_JOURNAL
2706 add(
"--systemd-journal",
"systemd-journal",
"false",
2707 "Use systemd-journal instead of syslog.",
"")
2713 add(
"--nodblog",
"nodblog",
false,
"",
"")
2715 ->
SetRemoved(
"Database logging has been removed.",
"34");
2716 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2718 ->
SetRemoved(
"Database logging has been removed.",
"34");
2720 add(QStringList{
"-l",
"--logfile"},
2721 "logfile",
"",
"",
"")
2722 ->SetGroup(
"Logging")
2723 ->
SetRemoved(
"This option has been removed as part of "
2724 "rewrite of the logging interface. Please update your init "
2725 "scripts to use --syslog to interface with your system's "
2726 "existing system logging daemon, or --logpath to specify a "
2727 "dirctory for MythTV to write its logs to.",
"0.25");
2734 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2735 "Write PID of application to filename.",
2736 "Write the PID of the currently running process as a single "
2737 "line to this file. Used for init scripts to know what "
2738 "process to terminate, and with log rotators "
2739 "to send a HUP signal to process to have it re-open files.");
2746 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2747 "Intended for internal use only, specify the JobID to match "
2748 "up with in the database for additional information and the "
2749 "ability to update runtime status in the database.");
2756 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2758 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2766 add(QStringList{
"-display",
"--display"},
"display",
"",
2767 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2776 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2777 "Qt platform argument that is passed through to Qt")
2785 QString logfile =
toString(
"logpath");
2786 pid_t pid = getpid();
2788 if (logfile.isEmpty())
2791 QFileInfo finfo(logfile);
2794 LOG(VB_GENERAL, LOG_ERR,
2795 QString(
"%1 is not a directory, disabling logfiles")
2800 QString logdir = finfo.filePath();
2801 logfile = QCoreApplication::applicationName() +
"." +
2803 QString(
".%1").arg(pid) +
".log";
2807 SetValue(
"filepath", QFileInfo(QDir(logdir), logfile).filePath());
2816 QString setting =
toString(
"syslog").toLower();
2817 if (setting ==
"none")
2827 QString setting =
toString(
"loglevel");
2828 if (setting.isEmpty())
2832 if (level == LOG_UNKNOWN)
2833 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2849 const QVariant& val(value);
2850#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2851 auto type =
static_cast<QMetaType::Type
>(val.type());
2853 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2861#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2862 auto type =
static_cast<QMetaType::Type
>(value.type());
2864 auto type = value.typeId();
2889 else if (
toBool(
"verboseint"))
2903 bool loglong =
toBool(
"loglong");
2906#if CONFIG_SYSTEMD_JOURNAL
2907 bool journal =
toBool(
"systemd-journal");
2912 facility = SYSTEMD_JOURNAL_FACILITY;
2916 if (level == LOG_UNKNOWN)
2919 LOG(VB_GENERAL, LOG_CRIT,
2920 QString(
"%1 version: %2 [%3] www.mythtv.org")
2921 .arg(QCoreApplication::applicationName(),
2923 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2924 .arg(QT_VERSION_STR, qVersion()));
2925 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2926 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2927 LOG(VB_GENERAL, LOG_NOTICE,
2931 bool propagate = !logfile.isEmpty();
2937 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2938 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2950 std::cerr <<
"Applying settings override" << std::endl;
2953 if (!
override.empty())
2955 QMap<QString, QString>::iterator it;
2956 for (it =
override.begin(); it !=
override.end(); ++it)
2958 LOG(VB_GENERAL, LOG_NOTICE,
2959 QString(
"Setting '%1' being forced to '%2'")
2960 .arg(it.key(), *it));
2968 if (!pidfile.isEmpty())
2970 pidfs.open(pidfile.toLatin1().constData());
2973 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2984 if (username.isEmpty())
2988 std::cerr <<
"--user option is not supported on Windows" << std::endl;
2991#if defined(__linux__) || defined(__LINUX__)
2994 int dumpability = prctl(PR_GET_DUMPABLE);
2996 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
2997 const uid_t user_id =
geteuid();
3001 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
3006 LOG(VB_GENERAL, LOG_WARNING,
3007 QString(
"Already running as '%1'").arg(username));
3013 std::cerr <<
"Error setting home directory." << std::endl;
3018 std::cerr <<
"Error setting effective group." << std::endl;
3023 std::cerr <<
"Error setting groups." << std::endl;
3028 std::cerr <<
"Error setting effective user." << std::endl;
3031#if defined(__linux__) || defined(__LINUX__)
3032 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3034 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3035 "creation. Run without the --user argument to use "
3036 "shell-specified limits.");
3042 std::cerr << QString(
"Invalid user '%1' specified with --user")
3043 .arg(username).toLocal8Bit().constData() << std::endl;
3055 std::ofstream pidfs;
3059 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3060 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3065 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
3066 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3071 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
3076 QString username =
toString(
"username");
3077 if (!username.isEmpty() && !
setUser(username))
3082 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")