24#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
25#include <QtEnvironmentVariables>
26#include <QtSystemDetection>
29#if defined ANDROID && __ANDROID_API__ < 24
47# include <sys/ioctl.h>
51# include <sys/prctl.h>
56#include <QCoreApplication>
61#include <QRegularExpression>
66#include <QVariantList>
74#include "mythconfig.h"
76#include "mythversion.h"
88#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
93 if (ioctl(0, TIOCGWINSZ, &ws) != 0)
96 return static_cast<int>(ws.ws_col);
102 return ((array.startsWith(
'"') && array.endsWith(
'"') ) ||
103 (array.startsWith(
'\'') && array.endsWith(
'\''))
104 ) ? array.mid(1, array.size() - 2) : array;
111 width = std::max(width, 5);
113 for (
int i = 0; i < list.size(); i++)
115 QString
string = list.at(i);
117 if(
string.size() <= width )
120 QString left =
string.left(width);
121 bool inserted =
false;
123 while( !inserted && !left.endsWith(
" " ))
125 if(
string.mid(left.size(), 1) ==
" " )
127 list.replace(i, left);
128 list.insert(i+1,
string.mid(left.size()).trimmed());
134 if( !left.contains(
" ") )
137 list.replace(i, left +
"-");
138 list.insert(i+1,
string.mid(left.size()));
147 list.replace(i, left);
148 list.insert(i+1,
string.mid(left.size()).trimmed());
163 enum states : std::uint8_t {
172 states state =
START;
175 for (
int i = 0; i < line.size(); i++)
177 const QChar c = line.at(i);
182 if (c.isSpace())
break;
183 if (c ==
'\'') state = INSQUOTE;
184 else if (c ==
'\"') state = INDQUOTE;
185 else if (c ==
'\\') state = ESCTEXT;
190 fields += line.mid(tokenStart, i - tokenStart);
194 else if (c ==
'\'') {
196 }
else if (c ==
'\"') {
198 }
else if (c ==
'\\') {
203 if (c ==
'\'') state = INTEXT;
204 else if (c ==
'\\') state = ESCSQUOTE;
207 if (c ==
'\"') state = INTEXT;
208 else if (c ==
'\\') state = ESCDQUOTE;
210 case ESCTEXT: state = INTEXT;
break;
211 case ESCSQUOTE: state = INSQUOTE;
break;
212 case ESCDQUOTE: state = INDQUOTE;
break;
217 fields += line.mid(tokenStart);
241 return "kCombOptVal";
247 return "kPassthrough";
290 QVariant def, QString
help, QString longhelp) :
292 m_name(name), m_type(
type), m_default(std::move(def)),
293 m_help(std::move(
help)), m_longhelp(std::move(longhelp))
295 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
296 (
m_type != QMetaType::QVariantMap))
308 m_name(name), m_type(
type), m_default(std::move(def))
310 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
311 (
m_type != QMetaType::QVariantMap))
345 QList<CommandLineArg*>::const_iterator i1;
347 len = std::max(len, (*i1)->GetKeywordLength()+2);
370#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
371 QTextStream msg(&helpstr, QIODevice::WriteOnly);
373 QTextStream msg(&helpstr, QIODeviceBase::WriteOnly);
419 QStringList hlist =
m_help.split(
'\n');
425 << hlist.takeFirst() << Qt::endl;
428 for (
const auto & line : std::as_const(hlist))
429 msg << pad << line << Qt::endl;
433 msg << arg->GetHelpString(off, group,
true);
449#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
450 QTextStream msg(&helpstr, QIODevice::WriteOnly);
452 QTextStream msg(&helpstr, QIODeviceBase::WriteOnly);
471 msg <<
"Option: " << keyword << Qt::endl << Qt::endl;
476 for (
const auto & word : std::as_const(
m_keywords))
482 msg <<
"Aliases: " << word << Qt::endl;
487 msg <<
" " << word << Qt::endl;
493 msg <<
"Type: " << QMetaType(
m_type).name() << Qt::endl;
495 msg <<
"Default: " <<
m_default.toString() << Qt::endl;
505 msg <<
"Description: " <<
help.takeFirst() << Qt::endl;
506 for (
const auto & line : std::as_const(
help))
507 msg <<
" " << line << Qt::endl;
509 QList<CommandLineArg*>::const_iterator i2;
514 msg << Qt::endl <<
"Can be used in combination with:" << Qt::endl;
515 for (
auto * parent : std::as_const(
m_parents))
516 msg <<
" " << parent->GetPreferredKeyword()
517 .toLocal8Bit().constData();
523 msg << Qt::endl <<
"Allows the use of:" << Qt::endl;
525 msg <<
" " << (*i2)->GetPreferredKeyword()
526 .toLocal8Bit().constData();
532 msg << Qt::endl <<
"Requires the use of:" << Qt::endl;
534 msg <<
" " << (*i2)->GetPreferredKeyword()
535 .toLocal8Bit().constData();
541 msg << Qt::endl <<
"Prevents the use of:" << Qt::endl;
543 msg <<
" " << (*i2)->GetPreferredKeyword()
544 .toLocal8Bit().constData();
564 case QMetaType::Bool:
575 case QMetaType::QString:
580 std::cerr <<
"Command line option did not receive value:\n"
581 <<
" " << opt.toLocal8Bit().constData() <<
'\n';
594 QList<QByteArray> blist;
600 case QMetaType::Bool:
601 std::cerr <<
"Boolean type options do not accept values:\n"
602 <<
" " << opt.toLocal8Bit().constData() <<
'\n';
605 case QMetaType::QString:
613 case QMetaType::UInt:
617 case QMetaType::LongLong:
618 m_stored = QVariant(val.toLongLong());
621 case QMetaType::Double:
622 m_stored = QVariant(val.toDouble());
625 case QMetaType::QDateTime:
629 case QMetaType::QStringList:
636 case QMetaType::QVariantMap:
637 if (!val.contains(
'='))
639 std::cerr <<
"Command line option did not get expected "
640 <<
"key/value pair\n";
644 blist = val.split(
'=');
652 case QMetaType::QSize:
653 if (!val.contains(
'x'))
655 std::cerr <<
"Command line option did not get expected "
660 blist = val.split(
'x');
661 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
684 for (
const auto& opt : std::as_const(
opts))
701 for (
const auto& opt : std::as_const(
opts))
718 for (
const auto& opt : std::as_const(
opts))
735 for (
const auto& opt : std::as_const(
opts))
753 for (
const auto& opt : std::as_const(
opts))
774 for (
const auto& opt : std::as_const(
opts))
794 for (
const auto& opt : std::as_const(
opts))
811 for (
const auto& opt : std::as_const(
opts))
820 if (depstr.isEmpty())
821 depstr =
"and will be removed in a future version.";
830 if (remstr.isEmpty())
831 remstr =
"and is no longer available in this version.";
844 bool replaced =
false;
872 bool replaced =
false;
875 for (
int i = 0; i <
m_parents.size(); i++)
900 bool replaced =
false;
929 bool replaced =
false;
932 for (
int i = 0; i <
m_blocks.size(); i++)
960 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
964 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
966 (*i1)->SetBlocks(*i2);
969 if ((*i1)->m_type == QMetaType::UnknownType)
982 if (!QCoreApplication::instance())
997#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
998 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
1000 auto storedType =
m_stored.typeId();
1002 if (
m_type == QMetaType::QString)
1004 if (storedType == QMetaType::QByteArray)
1012 else if (
m_type == QMetaType::QStringList)
1014 if (storedType == QMetaType::QVariantList)
1016 QVariantList vlist =
m_stored.toList();
1018 for (
const auto& item : std::as_const(vlist))
1019 slist << QString::fromLocal8Bit(item.toByteArray());
1023 else if (
m_type == QMetaType::QVariantMap)
1025 QVariantMap vmap =
m_stored.toMap();
1027 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1028 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1046 QStringList::const_iterator it;
1052 int len2 = (*it).size();
1071 QList<CommandLineArg*>::const_iterator i;
1073 bool passes =
false;
1085 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1086 <<
" requires at least one of the following arguments\n";
1089 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1090 std::cerr <<
"\n\n";
1101 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1102 <<
" requires all of the following be defined as well\n";
1106 << (*i)->GetPreferredKeyword().toLocal8Bit()
1109 std::cerr <<
"\n\n";
1119 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1120 <<
" requires that none of the following be defined\n";
1124 << (*i)->GetPreferredKeyword().toLocal8Bit()
1127 std::cerr <<
"\n\n";
1163 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1166 QMap<QString, QVariant> tmpmap;
1167 QMap<QString, QVariant>::const_iterator it;
1173 case QMetaType::Bool:
1174 std::cerr << (
m_stored.toBool() ?
"True" :
"False") <<
'\n';
1177 case QMetaType::Int:
1178 std::cerr <<
m_stored.toInt() <<
'\n';
1181 case QMetaType::UInt:
1182 std::cerr <<
m_stored.toUInt() <<
'\n';
1185 case QMetaType::LongLong:
1186 std::cerr <<
m_stored.toLongLong() <<
'\n';
1189 case QMetaType::Double:
1190 std::cerr <<
m_stored.toDouble() <<
'\n';
1193 case QMetaType::QSize:
1195 std::cerr <<
"x=" << tmpsize.width()
1196 <<
" y=" << tmpsize.height()
1200 case QMetaType::QString:
1201 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1205 case QMetaType::QStringList:
1207 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1208 for (
const auto& str : std::as_const(vlist))
1217 case QMetaType::QVariantMap:
1219 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1224 std::cerr << QString(
"").leftJustified(32)
1225 .toLocal8Bit().constData();
1227 std::cerr << it.key().toLocal8Bit().constData()
1229 << it->toByteArray().constData()
1235 case QMetaType::QDateTime:
1237 .toLocal8Bit().constData()
1250 QString warn = QString(
"%1 has been removed").arg(keyword);
1254 std::cerr << QString(
"****************************************************\n"
1257 "****************************************************\n\n")
1259 .toLocal8Bit().constData();
1266 std::cerr << QString(
"****************************************************\n"
1267 " WARNING: %1 has been deprecated\n"
1269 "****************************************************\n\n")
1271 .toLocal8Bit().constData();
1288 : m_appname(std::move(appname))
1290 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1292 std::cerr <<
"MythCommandLineParser is now operating verbosely.\n";
1301 QString pidfile =
toString(
"pidfile");
1302 if (!pidfile.isEmpty())
1304 QFile::remove(pidfile);
1307 QMap<QString, CommandLineArg*>::iterator i;
1312 (*i)->CleanupLinks();
1359 const QString& name, QMetaType::Type
type, QVariant def,
1360 QString
help, QString longhelp)
1374 for (
const auto & str : std::as_const(arglist))
1381 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1382 <<
" as taking type '"
1383#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1384 << QVariant::typeToName(
static_cast<int>(
type))
1386 << QMetaType(
type).name()
1402 std::cout <<
"Please attach all output as a file in bug reports.\n";
1405 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION <<
'\n';
1406 std::cout <<
"Library API : " << MYTH_BINARY_VERSION <<
'\n';
1407 std::cout <<
"QT Version : " << QT_VERSION_STR <<
'\n';
1408#ifdef MYTH_BUILD_CONFIG
1409 std::cout <<
"Options compiled in:\n";
1410 std::cout << MYTH_BUILD_CONFIG <<
'\n';
1419 std::cerr <<
help.toLocal8Bit().constData();
1430#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1431 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1433 QTextStream msg(&helpstr, QIODeviceBase::WriteOnly);
1436 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1438 msg << versionStr << Qt::endl;
1440 if (
toString(
"showhelp").isEmpty())
1445 if (descr.size() > 0)
1446 msg << Qt::endl << descr << Qt::endl << Qt::endl;
1449 QStringList groups(
"");
1453 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1454 if (!groups.contains(cmdarg->m_group))
1455 groups << cmdarg->m_group;
1461 for (
const auto & group : std::as_const(groups))
1463 if (group.isEmpty())
1464 msg <<
"Misc. Options:" << Qt::endl << Qt::endl;
1466 msg << group.toLocal8Bit().constData() <<
" Options:" << Qt::endl << Qt::endl;
1469 msg << cmdarg->GetHelpString(maxlen, group);
1476 QString optstr =
"-" +
toString(
"showhelp");
1479 optstr =
"-" + optstr;
1481 return QString(
"Could not find option matching '%1'\n")
1496 int &argpos, QString &opt, QByteArray &val)
1505 QByteArray tmp(argv[argpos]);
1517 if (tmp.startsWith(
'-') && tmp.size() > 1)
1526 if (tmp.contains(
'='))
1529 QList<QByteArray> blist = tmp.split(
'=');
1531 if (blist.size() != 2)
1545 if (argpos+1 >= argc)
1549 tmp = QByteArray(argv[++argpos]);
1554 if (tmp.startsWith(
"-") && tmp.size() > 1)
1588 for (
int argpos = 1; argpos < argc; ++argpos)
1592 res =
getOpt(argc, argv, argpos, opt, val);
1597 <<
"opt: " << opt.toLocal8Bit().constData() <<
'\n'
1598 <<
"val: " << val.constData() <<
"\n\n";
1604 std::cerr <<
"Received '--' but passthrough has not been enabled\n";
1621 std::cerr <<
"Invalid option received:\n "
1622 << opt.toLocal8Bit().constData();
1639 std::cerr <<
"Received '"
1641 <<
"' but unassociated arguments have not been enabled\n";
1653 std::cerr <<
"Command line arguments received out of sequence\n";
1659 if (opt.startsWith(
"-psn_"))
1661 std::cerr <<
"Ignoring Process Serial Number from command line\n";
1673 QByteArray tmp = opt.toLocal8Bit();
1682 std::cerr <<
"Unhandled option given on command line:\n"
1683 <<
" " << opt.toLocal8Bit().constData() <<
'\n';
1706 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1712 if (!argdef->
Set(opt))
1721 if (!argdef->
Set(opt, val))
1742 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1748 std::cerr <<
"Processed option list:\n";
1750 cmdarg->PrintVerbose();
1754 std::cerr <<
"\nExtra argument list:\n";
1756 for (
const auto& lopt : std::as_const(slist))
1757 std::cerr <<
" " << lopt.toLocal8Bit().constData() <<
'\n';
1762 std::cerr <<
"\nPassthrough string:\n";
1763 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() <<
'\n';
1772 if (!cmdarg->TestLinks())
1774 QString keyword = cmdarg->m_usedKeyword;
1775 if (keyword.startsWith(
'-'))
1777 if (keyword.startsWith(
"--"))
1778 keyword.remove(0,2);
1780 keyword.remove(0,1);
1792 QString
help, QString longhelp)
1794 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1798 QString
help, QString longhelp)
1800 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1804 QString
help, QString longhelp)
1806 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1810 QString
help, QString longhelp)
1812 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1816 QString
help, QString longhelp)
1818 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1822 QString
help, QString longhelp)
1824 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1828 QString
help, QString longhelp)
1830 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1834 QString
help, QString longhelp)
1836 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1840 QString
help, QString longhelp)
1842 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1846 QString
help, QString longhelp)
1848 return add(QStringList(arg), name,
type,
1849#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1850 QVariant(
static_cast<QVariant::Type
>(
type)),
1852 QVariant(QMetaType(
type)),
1854 std::move(
help), std::move(longhelp));
1858 QMetaType::Type
type,
1859 QVariant def, QString
help, QString longhelp)
1861 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1865 QString
help, QString longhelp)
1867 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1871 QString
help, QString longhelp)
1873 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1877 QString
help, QString longhelp)
1879 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1883 QString
help, QString longhelp)
1885 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1889 QString
help, QString longhelp)
1891 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1895 QString
help, QString longhelp)
1897 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1901 QString
help, QString longhelp)
1903 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1907 QString
help, QString longhelp)
1909 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1913 QString
help, QString longhelp)
1915 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1919 QMetaType::Type
type,
1920 QString
help, QString longhelp)
1922 return add(std::move(arglist), name,
type,
1923#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1924 QVariant(
static_cast<QVariant::Type
>(
type)),
1926 QVariant(QMetaType(
type)),
1928 std::move(
help), std::move(longhelp));
1937 std::cerr <<
"Reconciling links for option interdependencies.\n";
1939 QMap<QString,CommandLineArg*>::iterator args_it;
1942 QList<CommandLineArg*> links = (*args_it)->m_parents;
1943 QList<CommandLineArg*>::iterator links_it;
1944 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1946 if ((*links_it)->m_type != QMetaType::UnknownType)
1952 std::cerr <<
"ERROR: could not reconcile linked argument.\n"
1953 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1954 <<
"' could not find '"
1955 << (*links_it)->m_name.toLocal8Bit().constData()
1957 <<
" Please resolve dependency and recompile.\n";
1964 std::cerr << QString(
" Setting %1 as child of %2")
1965 .arg((*args_it)->m_name, (*links_it)->m_name)
1966 .toLocal8Bit().constData()
1969 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1972 links = (*args_it)->m_children;
1973 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1975 if ((*links_it)->m_type != QMetaType::UnknownType)
1981 std::cerr <<
"ERROR: could not reconcile linked argument.\n"
1982 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1983 <<
"' could not find '"
1984 << (*links_it)->m_name.toLocal8Bit().constData()
1986 <<
" Please resolve dependency and recompile.\n";
1993 std::cerr << QString(
" Setting %1 as parent of %2")
1994 .arg((*args_it)->m_name, (*links_it)->m_name)
1995 .toLocal8Bit().constData()
1998 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
2001 links = (*args_it)->m_requires;
2002 for (links_it = links.begin(); links_it != links.end(); ++links_it)
2004 if ((*links_it)->m_type != QMetaType::UnknownType)
2010 std::cerr <<
"ERROR: could not reconcile linked argument.\n"
2011 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
2012 <<
"' could not find '"
2013 << (*links_it)->m_name.toLocal8Bit().constData()
2015 <<
" Please resolve dependency and recompile.\n";
2022 std::cerr << QString(
" Setting %1 as requiring %2")
2023 .arg((*args_it)->m_name, (*links_it)->m_name)
2024 .toLocal8Bit().constData()
2027 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2030 QList<CommandLineArg*>::iterator req_it =
2031 (*args_it)->m_requiredby.begin();
2032 while (req_it != (*args_it)->m_requiredby.end())
2034 if ((*req_it)->m_type == QMetaType::UnknownType)
2039 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2042 std::cerr << QString(
" Setting %1 as blocking %2")
2043 .arg((*args_it)->m_name,
2045 .toLocal8Bit().constData()
2051 (*req_it)->DecrRef();
2052 req_it = (*args_it)->m_requiredby.erase(req_it);
2055 QList<CommandLineArg*>::iterator block_it =
2056 (*args_it)->m_blocks.begin();
2057 while (block_it != (*args_it)->m_blocks.end())
2059 if ((*block_it)->m_type != QMetaType::UnknownType)
2067 (*block_it)->DecrRef();
2068 block_it = (*args_it)->m_blocks.erase(block_it);
2075 std::cerr << QString(
" Setting %1 as blocking %2")
2076 .arg((*args_it)->m_name, (*block_it)->m_name)
2077 .toLocal8Bit().constData()
2080 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2120 return toMap(
"_extra");
2139 QMap<QString,QString> smap =
toMap(
"overridesettings");
2143 if (
toBool(
"overridesettingsfile"))
2149 if (f.open(QIODevice::ReadOnly))
2152 while (!in.atEnd()) {
2153 QString line = in.readLine().trimmed();
2154 QStringList tokens = line.split(
"=",
2155 Qt::SkipEmptyParts);
2156 if (tokens.size() == 2)
2158 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2159 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2160 tokens[0].remove(kQuoteStartRE);
2161 tokens[0].remove(kQuoteEndRE);
2162 tokens[1].remove(kQuoteStartRE);
2163 tokens[1].remove(kQuoteEndRE);
2164 if (!tokens[0].isEmpty())
2165 smap[tokens[0]] = tokens[1];
2171 QByteArray tmp =
filename.toLatin1();
2172 std::cerr <<
"Failed to open the override settings file: '"
2173 << tmp.constData() <<
"'\n";
2179 smap[
"RunFrontendInWindow"] =
"1";
2180 else if (
toBool(
"notwindowed"))
2181 smap[
"RunFrontendInWindow"] =
"0";
2183 if (
toBool(
"mousecursor"))
2184 smap[
"HideMouseCursor"] =
"0";
2185 else if (
toBool(
"nomousecursor"))
2186 smap[
"HideMouseCursor"] =
"1";
2190 if (!smap.isEmpty())
2193 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2194 vmap[it.key()] = QVariant(it.value());
2196 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2202 std::cerr <<
"Option Overrides:\n";
2203 QMap<QString, QString>::const_iterator it;
2204 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2205 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2206 .toLocal8Bit().constData() <<
'\n';
2227 if (arg->
m_type == QMetaType::Bool)
2252 if (arg->
m_stored.canConvert<
int>())
2306 if (arg->
m_stored.canConvert<
long long>())
2311 if (arg->
m_default.canConvert<
long long>())
2333 if (arg->
m_stored.canConvert<
double>())
2338 if (arg->
m_default.canConvert<
double>())
2360 if (arg->
m_stored.canConvert<QSize>())
2390 if (arg->
m_stored.canConvert<QString>())
2395 if (arg->
m_default.canConvert<QString>())
2429 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2430 val = varval.toString().split(sep);
2431 else if (varval.canConvert<QStringList>())
2432 val = varval.toStringList();
2442 QMap<QString, QString> val;
2443 QMap<QString, QVariant> tmp;
2456 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2461 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2465 for (
auto i = tmp.cbegin(); i != tmp.cend(); ++i)
2466 val[i.key()] = i.value().toString();
2486 if (arg->
m_stored.canConvert<QDateTime>())
2491 if (arg->
m_default.canConvert<QDateTime>())
2513 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2532 QMap<QString,QVariant> vmap;
2533 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2554 QMetaType::QStringList, QStringList());
2562 add(QStringList{
"-h",
"--help",
"--usage"},
2563 "showhelp",
"",
"Display this help printout, or give detailed "
2564 "information of selected option.",
2565 "Displays a list of all commands available for use with "
2566 "this application. If another option is provided as an "
2567 "argument, it will provide detailed information on that "
2575 add(
"--version",
"showversion",
false,
"Display version information.",
2576 "Display informtion about build, including:\n"
2577 " version, branch, protocol, library API, Qt "
2578 "and compiled options.");
2585 add(QStringList{
"-nw",
"--no-windowed"},
2586 "notwindowed",
false,
2587 "Prevent application from running in a window.",
"")
2588 ->SetBlocks(
"windowed")
2591 add(QStringList{
"-w",
"--windowed"},
"windowed",
2592 false,
"Force application to run in a window.",
"")
2593 ->SetGroup(
"User Interface");
2600 add(
"--mouse-cursor",
"mousecursor",
false,
2601 "Force visibility of the mouse cursor.",
"")
2605 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2606 "Force the mouse cursor to be hidden.",
"")
2614 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2615 "Fork application into background after startup.",
2616 "Fork application into background, detatching from "
2617 "the local terminal.\nOften used with: "
2618 " --logpath --pidfile --user");
2626 add(QStringList{
"-O",
"--override-setting"},
2627 "overridesettings", QMetaType::QVariantMap,
2628 "Override a single setting defined by a key=value pair.",
2629 "Override a single setting from the database using "
2630 "options defined as one or more key=value pairs\n"
2631 "Multiple can be defined by multiple uses of the "
2633 add(
"--override-settings-file",
"overridesettingsfile",
"",
2634 "Define a file of key=value pairs to be "
2635 "loaded for setting overrides.",
"");
2642 add(
"--chanid",
"chanid", 0U,
2643 "Specify chanid of recording to operate on.",
"")
2646 add(
"--starttime",
"starttime", QDateTime(),
2647 "Specify start time of recording to operate on.",
"")
2655 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2656 "",
"Specify window size and position (WxH[+X+Y])",
"")
2657 ->SetGroup(
"User Interface");
2664 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2671 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2678 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2681 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2682 LOG_INFO : defaultLogLevel;
2686 add(QStringList{
"-v",
"--verbose"},
"verbose",
2688 "Specify log filtering. Use '-v help' for level info.",
"")
2689 ->SetGroup(
"Logging");
2690 add(
"-V",
"verboseint", 0LL,
"",
2691 "This option is intended for internal use only.\n"
2692 "This option takes an unsigned value corresponding "
2693 "to the bitwise log verbosity operator.")
2695 add(
"--logpath",
"logpath",
"",
2696 "Writes logging messages to a file in the directory logpath with "
2697 "filenames in the format: applicationName.date.pid.log.\n"
2698 "This is typically used in combination with --daemon, and if used "
2699 "in combination with --pidfile, this can be used with log "
2700 "rotators, using the HUP call to inform MythTV to reload the "
2703 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2704 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2705 ->SetGroup(
"Logging");
2706 add(
"--loglong",
"loglong", 0,
2707 "Use long log format for the console, i.e. show file, line number, etc. in the console log.",
"")
2709 add(
"--loglevel",
"loglevel", logLevelStr,
2711 "Set the logging level. All log messages at lower levels will be "
2713 "In descending order: emerg, alert, crit, err, warning, notice, "
2714 "info, debug, trace\ndefaults to ") + logLevelStr,
"")
2716 add(
"--syslog",
"syslog",
"none",
2717 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2718 "defaults to none.",
"")
2720#if CONFIG_SYSTEMD_JOURNAL
2721 add(
"--systemd-journal",
"systemd-journal",
"false",
2722 "Use systemd-journal instead of syslog.",
"")
2728 add(
"--nodblog",
"nodblog",
false,
"",
"")
2730 ->
SetRemoved(
"Database logging has been removed.",
"34");
2731 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2733 ->
SetRemoved(
"Database logging has been removed.",
"34");
2735 add(QStringList{
"-l",
"--logfile"},
2736 "logfile",
"",
"",
"")
2737 ->SetGroup(
"Logging")
2738 ->
SetRemoved(
"This option has been removed as part of "
2739 "rewrite of the logging interface. Please update your init "
2740 "scripts to use --syslog to interface with your system's "
2741 "existing system logging daemon, or --logpath to specify a "
2742 "dirctory for MythTV to write its logs to.",
"0.25");
2749 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2750 "Write PID of application to filename.",
2751 "Write the PID of the currently running process as a single "
2752 "line to this file. Used for init scripts to know what "
2753 "process to terminate, and with log rotators "
2754 "to send a HUP signal to process to have it re-open files.");
2761 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2762 "Intended for internal use only, specify the JobID to match "
2763 "up with in the database for additional information and the "
2764 "ability to update runtime status in the database.");
2771 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2773 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2781 add(QStringList{
"-display",
"--display"},
"display",
"",
2782 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2791 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2792 "Qt platform argument that is passed through to Qt")
2800 QString logfile =
toString(
"logpath");
2801 pid_t pid = getpid();
2803 if (logfile.isEmpty())
2806 QFileInfo finfo(logfile);
2809 LOG(VB_GENERAL, LOG_ERR,
2810 QString(
"%1 is not a directory, disabling logfiles")
2815 QString logdir = finfo.filePath();
2816 logfile = QCoreApplication::applicationName() +
"." +
2818 QString(
".%1").arg(pid) +
".log";
2822 SetValue(
"filepath", QFileInfo(QDir(logdir), logfile).filePath());
2831 QString setting =
toString(
"syslog").toLower();
2832 if (setting ==
"none")
2842 QString setting =
toString(
"loglevel");
2843 if (setting.isEmpty())
2847 if (level == LOG_UNKNOWN)
2848 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2864 const QVariant& val(value);
2865#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2866 auto type =
static_cast<QMetaType::Type
>(val.type());
2868 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2876#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2877 auto type =
static_cast<QMetaType::Type
>(value.type());
2879 auto type = value.typeId();
2904 else if (
toBool(
"verboseint"))
2911 int quiet =
toInt(
"quiet");
2912 if (std::max(quiet,
static_cast<int>(
progress)) > 1)
2918 bool loglong =
toBool(
"loglong");
2921#if CONFIG_SYSTEMD_JOURNAL
2922 bool journal =
toBool(
"systemd-journal");
2927 facility = SYSTEMD_JOURNAL_FACILITY;
2931 if (level == LOG_UNKNOWN)
2934 LOG(VB_GENERAL, LOG_CRIT,
2935 QString(
"%1 version: %2 [%3] www.mythtv.org")
2936 .arg(QCoreApplication::applicationName(),
2938 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2939 .arg(QT_VERSION_STR, qVersion()));
2940 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2941 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2942 LOG(VB_GENERAL, LOG_NOTICE,
2946 bool propagate = !logfile.isEmpty();
2949 quiet = std::max(quiet, 1);
2952 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2953 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2965 std::cerr <<
"Applying settings override\n";
2968 if (!
override.empty())
2970 QMap<QString, QString>::iterator it;
2971 for (it =
override.begin(); it !=
override.end(); ++it)
2973 LOG(VB_GENERAL, LOG_NOTICE,
2974 QString(
"Setting '%1' being forced to '%2'")
2975 .arg(it.key(), *it));
2983 if (!pidfile.isEmpty())
2985 pidfs.open(pidfile.toLatin1().constData());
2988 std::cerr <<
"Could not open pid file: " <<
ENO_STR <<
'\n';
2999 if (username.isEmpty())
3003 std::cerr <<
"--user option is not supported on Windows" << std::endl;
3009 int dumpability = prctl(PR_GET_DUMPABLE);
3011 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
3012 const uid_t user_id =
geteuid();
3016 std::cerr <<
"You must be running as root to use the --user switch.\n";
3021 LOG(VB_GENERAL, LOG_WARNING,
3022 QString(
"Already running as '%1'").arg(username));
3026 if (!qputenv(
"HOME",
user_info->pw_dir))
3028 std::cerr <<
"Error setting home directory.\n";
3033 std::cerr <<
"Error setting effective group.\n";
3038 std::cerr <<
"Error setting groups.\n";
3043 std::cerr <<
"Error setting effective user.\n";
3047 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3049 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3050 "creation. Run without the --user argument to use "
3051 "shell-specified limits.");
3057 std::cerr << QString(
"Invalid user '%1' specified with --user")
3058 .arg(username).toLocal8Bit().constData() <<
'\n';
3070 std::ofstream pidfs;
3074 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3075 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3080 std::cerr <<
"Daemonizing is unavailable in OSX\n";
3081 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3086 std::cerr <<
"Failed to daemonize: " <<
ENO_STR <<
'\n';
3091 QString username =
toString(
"username");
3092 if (!username.isEmpty() && !
setUser(username))
3097 pidfs << getpid() <<
'\n';
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")