24#if QT_VERSION >= QT_VERSION_CHECK(6,5,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#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
370 QTextStream msg(&helpstr, QIODevice::WriteOnly);
372 QTextStream msg(&helpstr, QIODeviceBase::WriteOnly);
418 QStringList hlist =
m_help.split(
'\n');
424 << hlist.takeFirst() << Qt::endl;
427 for (
const auto & line : std::as_const(hlist))
428 msg << pad << line << Qt::endl;
432 msg << arg->GetHelpString(off, group,
true);
448#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
449 QTextStream msg(&helpstr, QIODevice::WriteOnly);
451 QTextStream msg(&helpstr, QIODeviceBase::WriteOnly);
470 msg <<
"Option: " << keyword << Qt::endl << Qt::endl;
475 for (
const auto & word : std::as_const(
m_keywords))
481 msg <<
"Aliases: " << word << Qt::endl;
486 msg <<
" " << word << Qt::endl;
492 msg <<
"Type: " << QMetaType(
m_type).name() << Qt::endl;
494 msg <<
"Default: " <<
m_default.toString() << Qt::endl;
504 msg <<
"Description: " <<
help.takeFirst() << Qt::endl;
505 for (
const auto & line : std::as_const(
help))
506 msg <<
" " << line << Qt::endl;
508 QList<CommandLineArg*>::const_iterator i2;
513 msg << Qt::endl <<
"Can be used in combination with:" << Qt::endl;
514 for (
auto * parent : std::as_const(
m_parents))
515 msg <<
" " << parent->GetPreferredKeyword()
516 .toLocal8Bit().constData();
522 msg << Qt::endl <<
"Allows the use of:" << Qt::endl;
524 msg <<
" " << (*i2)->GetPreferredKeyword()
525 .toLocal8Bit().constData();
531 msg << Qt::endl <<
"Requires the use of:" << Qt::endl;
533 msg <<
" " << (*i2)->GetPreferredKeyword()
534 .toLocal8Bit().constData();
540 msg << Qt::endl <<
"Prevents the use of:" << Qt::endl;
542 msg <<
" " << (*i2)->GetPreferredKeyword()
543 .toLocal8Bit().constData();
563 case QMetaType::Bool:
574 case QMetaType::QString:
579 std::cerr <<
"Command line option did not receive value:\n"
580 <<
" " << opt.toLocal8Bit().constData() <<
'\n';
593 QList<QByteArray> blist;
599 case QMetaType::Bool:
600 std::cerr <<
"Boolean type options do not accept values:\n"
601 <<
" " << opt.toLocal8Bit().constData() <<
'\n';
604 case QMetaType::QString:
612 case QMetaType::UInt:
616 case QMetaType::LongLong:
617 m_stored = QVariant(val.toLongLong());
620 case QMetaType::Double:
621 m_stored = QVariant(val.toDouble());
624 case QMetaType::QDateTime:
628 case QMetaType::QStringList:
635 case QMetaType::QVariantMap:
636 if (!val.contains(
'='))
638 std::cerr <<
"Command line option did not get expected "
639 <<
"key/value pair\n";
643 blist = val.split(
'=');
651 case QMetaType::QSize:
652 if (!val.contains(
'x'))
654 std::cerr <<
"Command line option did not get expected "
659 blist = val.split(
'x');
660 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
683 for (
const auto& opt : std::as_const(
opts))
700 for (
const auto& opt : std::as_const(
opts))
717 for (
const auto& opt : std::as_const(
opts))
734 for (
const auto& opt : std::as_const(
opts))
752 for (
const auto& opt : std::as_const(
opts))
773 for (
const auto& opt : std::as_const(
opts))
793 for (
const auto& opt : std::as_const(
opts))
810 for (
const auto& opt : std::as_const(
opts))
819 if (depstr.isEmpty())
820 depstr =
"and will be removed in a future version.";
829 if (remstr.isEmpty())
830 remstr =
"and is no longer available in this version.";
843 bool replaced =
false;
871 bool replaced =
false;
874 for (
int i = 0; i <
m_parents.size(); i++)
899 bool replaced =
false;
928 bool replaced =
false;
931 for (
int i = 0; i <
m_blocks.size(); i++)
959 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
963 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
965 (*i1)->SetBlocks(*i2);
968 if ((*i1)->m_type == QMetaType::UnknownType)
981 if (!QCoreApplication::instance())
996#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
997 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
999 auto storedType =
m_stored.typeId();
1001 if (
m_type == QMetaType::QString)
1003 if (storedType == QMetaType::QByteArray)
1011 else if (
m_type == QMetaType::QStringList)
1013 if (storedType == QMetaType::QVariantList)
1015 QVariantList vlist =
m_stored.toList();
1017 for (
const auto& item : std::as_const(vlist))
1018 slist << QString::fromLocal8Bit(item.toByteArray());
1022 else if (
m_type == QMetaType::QVariantMap)
1024 QVariantMap vmap =
m_stored.toMap();
1026 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1027 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1045 QStringList::const_iterator it;
1051 int len2 = (*it).size();
1070 QList<CommandLineArg*>::const_iterator i;
1072 bool passes =
false;
1084 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1085 <<
" requires at least one of the following arguments\n";
1088 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1089 std::cerr <<
"\n\n";
1100 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1101 <<
" requires all of the following be defined as well\n";
1105 << (*i)->GetPreferredKeyword().toLocal8Bit()
1108 std::cerr <<
"\n\n";
1118 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1119 <<
" requires that none of the following be defined\n";
1123 << (*i)->GetPreferredKeyword().toLocal8Bit()
1126 std::cerr <<
"\n\n";
1162 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1165 QMap<QString, QVariant> tmpmap;
1166 QMap<QString, QVariant>::const_iterator it;
1172 case QMetaType::Bool:
1173 std::cerr << (
m_stored.toBool() ?
"True" :
"False") <<
'\n';
1176 case QMetaType::Int:
1177 std::cerr <<
m_stored.toInt() <<
'\n';
1180 case QMetaType::UInt:
1181 std::cerr <<
m_stored.toUInt() <<
'\n';
1184 case QMetaType::LongLong:
1185 std::cerr <<
m_stored.toLongLong() <<
'\n';
1188 case QMetaType::Double:
1189 std::cerr <<
m_stored.toDouble() <<
'\n';
1192 case QMetaType::QSize:
1194 std::cerr <<
"x=" << tmpsize.width()
1195 <<
" y=" << tmpsize.height()
1199 case QMetaType::QString:
1200 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1204 case QMetaType::QStringList:
1206 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1207 for (
const auto& str : std::as_const(vlist))
1216 case QMetaType::QVariantMap:
1218 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1223 std::cerr << QString(
"").leftJustified(32)
1224 .toLocal8Bit().constData();
1226 std::cerr << it.key().toLocal8Bit().constData()
1228 << it->toByteArray().constData()
1234 case QMetaType::QDateTime:
1236 .toLocal8Bit().constData()
1249 QString warn = QString(
"%1 has been removed").arg(keyword);
1253 std::cerr << QString(
"****************************************************\n"
1256 "****************************************************\n\n")
1258 .toLocal8Bit().constData();
1265 std::cerr << QString(
"****************************************************\n"
1266 " WARNING: %1 has been deprecated\n"
1268 "****************************************************\n\n")
1270 .toLocal8Bit().constData();
1287 : m_appname(std::move(appname))
1289 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1291 std::cerr <<
"MythCommandLineParser is now operating verbosely.\n";
1300 QString pidfile =
toString(
"pidfile");
1301 if (!pidfile.isEmpty())
1303 QFile::remove(pidfile);
1306 QMap<QString, CommandLineArg*>::iterator i;
1311 (*i)->CleanupLinks();
1358 const QString& name, QMetaType::Type
type, QVariant def,
1359 QString
help, QString longhelp)
1373 for (
const auto & str : std::as_const(arglist))
1380 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1381 <<
" as taking type '"
1382#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1383 << QVariant::typeToName(
static_cast<int>(
type))
1385 << QMetaType(
type).name()
1401 std::cout <<
"Please attach all output as a file in bug reports.\n";
1404 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION <<
'\n';
1405 std::cout <<
"Library API : " << MYTH_BINARY_VERSION <<
'\n';
1406 std::cout <<
"QT Version : " << QT_VERSION_STR <<
'\n';
1407#ifdef MYTH_BUILD_CONFIG
1408 std::cout <<
"Options compiled in:\n";
1409 std::cout << MYTH_BUILD_CONFIG <<
'\n';
1418 std::cerr <<
help.toLocal8Bit().constData();
1429#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1430 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1432 QTextStream msg(&helpstr, QIODeviceBase::WriteOnly);
1435 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1437 msg << versionStr << Qt::endl;
1439 if (
toString(
"showhelp").isEmpty())
1444 if (descr.size() > 0)
1445 msg << Qt::endl << descr << Qt::endl << Qt::endl;
1448 QStringList groups(
"");
1452 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1453 if (!groups.contains(cmdarg->m_group))
1454 groups << cmdarg->m_group;
1460 for (
const auto & group : std::as_const(groups))
1462 if (group.isEmpty())
1463 msg <<
"Misc. Options:" << Qt::endl << Qt::endl;
1465 msg << group.toLocal8Bit().constData() <<
" Options:" << Qt::endl << Qt::endl;
1468 msg << cmdarg->GetHelpString(maxlen, group);
1475 QString optstr =
"-" +
toString(
"showhelp");
1478 optstr =
"-" + optstr;
1480 return QString(
"Could not find option matching '%1'\n")
1495 int &argpos, QString &opt, QByteArray &val)
1504 QByteArray tmp(argv[argpos]);
1516 if (tmp.startsWith(
'-') && tmp.size() > 1)
1525 if (tmp.contains(
'='))
1528 QList<QByteArray> blist = tmp.split(
'=');
1530 if (blist.size() != 2)
1544 if (argpos+1 >= argc)
1548 tmp = QByteArray(argv[++argpos]);
1553 if (tmp.startsWith(
"-") && tmp.size() > 1)
1587 for (
int argpos = 1; argpos < argc; ++argpos)
1591 res =
getOpt(argc, argv, argpos, opt, val);
1596 <<
"opt: " << opt.toLocal8Bit().constData() <<
'\n'
1597 <<
"val: " << val.constData() <<
"\n\n";
1603 std::cerr <<
"Received '--' but passthrough has not been enabled\n";
1620 std::cerr <<
"Invalid option received:\n "
1621 << opt.toLocal8Bit().constData();
1638 std::cerr <<
"Received '"
1640 <<
"' but unassociated arguments have not been enabled\n";
1652 std::cerr <<
"Command line arguments received out of sequence\n";
1658 if (opt.startsWith(
"-psn_"))
1660 std::cerr <<
"Ignoring Process Serial Number from command line\n";
1672 QByteArray tmp = opt.toLocal8Bit();
1681 std::cerr <<
"Unhandled option given on command line:\n"
1682 <<
" " << opt.toLocal8Bit().constData() <<
'\n';
1705 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1711 if (!argdef->
Set(opt))
1720 if (!argdef->
Set(opt, val))
1741 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1747 std::cerr <<
"Processed option list:\n";
1749 cmdarg->PrintVerbose();
1753 std::cerr <<
"\nExtra argument list:\n";
1755 for (
const auto& lopt : std::as_const(slist))
1756 std::cerr <<
" " << lopt.toLocal8Bit().constData() <<
'\n';
1761 std::cerr <<
"\nPassthrough string:\n";
1762 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() <<
'\n';
1771 if (!cmdarg->TestLinks())
1773 QString keyword = cmdarg->m_usedKeyword;
1774 if (keyword.startsWith(
'-'))
1776 if (keyword.startsWith(
"--"))
1777 keyword.remove(0,2);
1779 keyword.remove(0,1);
1791 QString
help, QString longhelp)
1793 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1797 QString
help, QString longhelp)
1799 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1803 QString
help, QString longhelp)
1805 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1809 QString
help, QString longhelp)
1811 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1815 QString
help, QString longhelp)
1817 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1821 QString
help, QString longhelp)
1823 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1827 QString
help, QString longhelp)
1829 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1833 QString
help, QString longhelp)
1835 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1839 QString
help, QString longhelp)
1841 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1845 QString
help, QString longhelp)
1847 return add(QStringList(arg), name,
type,
1848#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1849 QVariant(
static_cast<QVariant::Type
>(
type)),
1851 QVariant(QMetaType(
type)),
1853 std::move(
help), std::move(longhelp));
1857 QMetaType::Type
type,
1858 QVariant def, QString
help, QString longhelp)
1860 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1864 QString
help, QString longhelp)
1866 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1870 QString
help, QString longhelp)
1872 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1876 QString
help, QString longhelp)
1878 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1882 QString
help, QString longhelp)
1884 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1888 QString
help, QString longhelp)
1890 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1894 QString
help, QString longhelp)
1896 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1900 QString
help, QString longhelp)
1902 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1906 QString
help, QString longhelp)
1908 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1912 QString
help, QString longhelp)
1914 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1918 QMetaType::Type
type,
1919 QString
help, QString longhelp)
1921 return add(std::move(arglist), name,
type,
1922#
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1923 QVariant(
static_cast<QVariant::Type
>(
type)),
1925 QVariant(QMetaType(
type)),
1927 std::move(
help), std::move(longhelp));
1936 std::cerr <<
"Reconciling links for option interdependencies.\n";
1938 QMap<QString,CommandLineArg*>::iterator args_it;
1941 QList<CommandLineArg*> links = (*args_it)->m_parents;
1942 QList<CommandLineArg*>::iterator links_it;
1943 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1945 if ((*links_it)->m_type != QMetaType::UnknownType)
1951 std::cerr <<
"ERROR: could not reconcile linked argument.\n"
1952 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1953 <<
"' could not find '"
1954 << (*links_it)->m_name.toLocal8Bit().constData()
1956 <<
" Please resolve dependency and recompile.\n";
1963 std::cerr << QString(
" Setting %1 as child of %2")
1964 .arg((*args_it)->m_name, (*links_it)->m_name)
1965 .toLocal8Bit().constData()
1968 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1971 links = (*args_it)->m_children;
1972 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1974 if ((*links_it)->m_type != QMetaType::UnknownType)
1980 std::cerr <<
"ERROR: could not reconcile linked argument.\n"
1981 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1982 <<
"' could not find '"
1983 << (*links_it)->m_name.toLocal8Bit().constData()
1985 <<
" Please resolve dependency and recompile.\n";
1992 std::cerr << QString(
" Setting %1 as parent of %2")
1993 .arg((*args_it)->m_name, (*links_it)->m_name)
1994 .toLocal8Bit().constData()
1997 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
2000 links = (*args_it)->m_requires;
2001 for (links_it = links.begin(); links_it != links.end(); ++links_it)
2003 if ((*links_it)->m_type != QMetaType::UnknownType)
2009 std::cerr <<
"ERROR: could not reconcile linked argument.\n"
2010 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
2011 <<
"' could not find '"
2012 << (*links_it)->m_name.toLocal8Bit().constData()
2014 <<
" Please resolve dependency and recompile.\n";
2021 std::cerr << QString(
" Setting %1 as requiring %2")
2022 .arg((*args_it)->m_name, (*links_it)->m_name)
2023 .toLocal8Bit().constData()
2026 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2029 QList<CommandLineArg*>::iterator req_it =
2030 (*args_it)->m_requiredby.begin();
2031 while (req_it != (*args_it)->m_requiredby.end())
2033 if ((*req_it)->m_type == QMetaType::UnknownType)
2038 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2041 std::cerr << QString(
" Setting %1 as blocking %2")
2042 .arg((*args_it)->m_name,
2044 .toLocal8Bit().constData()
2050 (*req_it)->DecrRef();
2051 req_it = (*args_it)->m_requiredby.erase(req_it);
2054 QList<CommandLineArg*>::iterator block_it =
2055 (*args_it)->m_blocks.begin();
2056 while (block_it != (*args_it)->m_blocks.end())
2058 if ((*block_it)->m_type != QMetaType::UnknownType)
2066 (*block_it)->DecrRef();
2067 block_it = (*args_it)->m_blocks.erase(block_it);
2074 std::cerr << QString(
" Setting %1 as blocking %2")
2075 .arg((*args_it)->m_name, (*block_it)->m_name)
2076 .toLocal8Bit().constData()
2079 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2119 return toMap(
"_extra");
2138 QMap<QString,QString> smap =
toMap(
"overridesettings");
2142 if (
toBool(
"overridesettingsfile"))
2148 if (f.open(QIODevice::ReadOnly))
2151 while (!in.atEnd()) {
2152 QString line = in.readLine().trimmed();
2153 QStringList tokens = line.split(
"=",
2154 Qt::SkipEmptyParts);
2155 if (tokens.size() == 2)
2157 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2158 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2159 tokens[0].remove(kQuoteStartRE);
2160 tokens[0].remove(kQuoteEndRE);
2161 tokens[1].remove(kQuoteStartRE);
2162 tokens[1].remove(kQuoteEndRE);
2163 if (!tokens[0].isEmpty())
2164 smap[tokens[0]] = tokens[1];
2170 QByteArray tmp =
filename.toLatin1();
2171 std::cerr <<
"Failed to open the override settings file: '"
2172 << tmp.constData() <<
"'\n";
2178 smap[
"RunFrontendInWindow"] =
"1";
2179 else if (
toBool(
"notwindowed"))
2180 smap[
"RunFrontendInWindow"] =
"0";
2182 if (
toBool(
"mousecursor"))
2183 smap[
"HideMouseCursor"] =
"0";
2184 else if (
toBool(
"nomousecursor"))
2185 smap[
"HideMouseCursor"] =
"1";
2189 if (!smap.isEmpty())
2192 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2193 vmap[it.key()] = QVariant(it.value());
2195 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2201 std::cerr <<
"Option Overrides:\n";
2202 QMap<QString, QString>::const_iterator it;
2203 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2204 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2205 .toLocal8Bit().constData() <<
'\n';
2226 if (arg->
m_type == QMetaType::Bool)
2251 if (arg->
m_stored.canConvert<
int>())
2305 if (arg->
m_stored.canConvert<
long long>())
2310 if (arg->
m_default.canConvert<
long long>())
2332 if (arg->
m_stored.canConvert<
double>())
2337 if (arg->
m_default.canConvert<
double>())
2359 if (arg->
m_stored.canConvert<QSize>())
2389 if (arg->
m_stored.canConvert<QString>())
2394 if (arg->
m_default.canConvert<QString>())
2428 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2429 val = varval.toString().split(sep);
2430 else if (varval.canConvert<QStringList>())
2431 val = varval.toStringList();
2441 QMap<QString, QString> val;
2442 QMap<QString, QVariant> tmp;
2455 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2460 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2464 for (
auto i = tmp.cbegin(); i != tmp.cend(); ++i)
2465 val[i.key()] = i.value().toString();
2485 if (arg->
m_stored.canConvert<QDateTime>())
2490 if (arg->
m_default.canConvert<QDateTime>())
2512 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2531 QMap<QString,QVariant> vmap;
2532 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2553 QMetaType::QStringList, QStringList());
2561 add(QStringList{
"-h",
"--help",
"--usage"},
2562 "showhelp",
"",
"Display this help printout, or give detailed "
2563 "information of selected option.",
2564 "Displays a list of all commands available for use with "
2565 "this application. If another option is provided as an "
2566 "argument, it will provide detailed information on that "
2574 add(
"--version",
"showversion",
false,
"Display version information.",
2575 "Display informtion about build, including:\n"
2576 " version, branch, protocol, library API, Qt "
2577 "and compiled options.");
2584 add(QStringList{
"-nw",
"--no-windowed"},
2585 "notwindowed",
false,
2586 "Prevent application from running in a window.",
"")
2587 ->SetBlocks(
"windowed")
2590 add(QStringList{
"-w",
"--windowed"},
"windowed",
2591 false,
"Force application to run in a window.",
"")
2592 ->SetGroup(
"User Interface");
2599 add(
"--mouse-cursor",
"mousecursor",
false,
2600 "Force visibility of the mouse cursor.",
"")
2604 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2605 "Force the mouse cursor to be hidden.",
"")
2613 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2614 "Fork application into background after startup.",
2615 "Fork application into background, detatching from "
2616 "the local terminal.\nOften used with: "
2617 " --logpath --pidfile --user");
2625 add(QStringList{
"-O",
"--override-setting"},
2626 "overridesettings", QMetaType::QVariantMap,
2627 "Override a single setting defined by a key=value pair.",
2628 "Override a single setting from the database using "
2629 "options defined as one or more key=value pairs\n"
2630 "Multiple can be defined by multiple uses of the "
2632 add(
"--override-settings-file",
"overridesettingsfile",
"",
2633 "Define a file of key=value pairs to be "
2634 "loaded for setting overrides.",
"");
2641 add(
"--chanid",
"chanid", 0U,
2642 "Specify chanid of recording to operate on.",
"")
2645 add(
"--starttime",
"starttime", QDateTime(),
2646 "Specify start time of recording to operate on.",
"")
2654 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2655 "",
"Specify window size and position (WxH[+X+Y])",
"")
2656 ->SetGroup(
"User Interface");
2663 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2670 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2677 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2680 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2681 LOG_INFO : defaultLogLevel;
2685 add(QStringList{
"-v",
"--verbose"},
"verbose",
2687 "Specify log filtering. Use '-v help' for level info.",
"")
2688 ->SetGroup(
"Logging");
2689 add(
"-V",
"verboseint", 0LL,
"",
2690 "This option is intended for internal use only.\n"
2691 "This option takes an unsigned value corresponding "
2692 "to the bitwise log verbosity operator.")
2694 add(
"--logpath",
"logpath",
"",
2695 "Writes logging messages to a file in the directory logpath with "
2696 "filenames in the format: applicationName.date.pid.log.\n"
2697 "This is typically used in combination with --daemon, and if used "
2698 "in combination with --pidfile, this can be used with log "
2699 "rotators, using the HUP call to inform MythTV to reload the "
2702 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2703 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2704 ->SetGroup(
"Logging");
2705 add(
"--loglong",
"loglong", 0,
2706 "Use long log format for the console, i.e. show file, line number, etc. in the console log.",
"")
2708 add(
"--loglevel",
"loglevel", logLevelStr,
2710 "Set the logging level. All log messages at lower levels will be "
2712 "In descending order: emerg, alert, crit, err, warning, notice, "
2713 "info, debug, trace\ndefaults to ") + logLevelStr,
"")
2715 add(
"--syslog",
"syslog",
"none",
2716 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2717 "defaults to none.",
"")
2719#if CONFIG_SYSTEMD_JOURNAL
2720 add(
"--systemd-journal",
"systemd-journal",
"false",
2721 "Use systemd-journal instead of syslog.",
"")
2727 add(
"--nodblog",
"nodblog",
false,
"",
"")
2729 ->
SetRemoved(
"Database logging has been removed.",
"34");
2730 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2732 ->
SetRemoved(
"Database logging has been removed.",
"34");
2734 add(QStringList{
"-l",
"--logfile"},
2735 "logfile",
"",
"",
"")
2736 ->SetGroup(
"Logging")
2737 ->
SetRemoved(
"This option has been removed as part of "
2738 "rewrite of the logging interface. Please update your init "
2739 "scripts to use --syslog to interface with your system's "
2740 "existing system logging daemon, or --logpath to specify a "
2741 "dirctory for MythTV to write its logs to.",
"0.25");
2748 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2749 "Write PID of application to filename.",
2750 "Write the PID of the currently running process as a single "
2751 "line to this file. Used for init scripts to know what "
2752 "process to terminate, and with log rotators "
2753 "to send a HUP signal to process to have it re-open files.");
2760 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2761 "Intended for internal use only, specify the JobID to match "
2762 "up with in the database for additional information and the "
2763 "ability to update runtime status in the database.");
2770 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2772 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2780 add(QStringList{
"-display",
"--display"},
"display",
"",
2781 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2790 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2791 "Qt platform argument that is passed through to Qt")
2799 QString logfile =
toString(
"logpath");
2800 pid_t pid = getpid();
2802 if (logfile.isEmpty())
2805 QFileInfo finfo(logfile);
2808 LOG(VB_GENERAL, LOG_ERR,
2809 QString(
"%1 is not a directory, disabling logfiles")
2814 QString logdir = finfo.filePath();
2815 logfile = QCoreApplication::applicationName() +
"." +
2817 QString(
".%1").arg(pid) +
".log";
2821 SetValue(
"filepath", QFileInfo(QDir(logdir), logfile).filePath());
2830 QString setting =
toString(
"syslog").toLower();
2831 if (setting ==
"none")
2841 QString setting =
toString(
"loglevel");
2842 if (setting.isEmpty())
2846 if (level == LOG_UNKNOWN)
2847 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2863 const QVariant& val(value);
2864#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2865 auto type =
static_cast<QMetaType::Type
>(val.type());
2867 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2875#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2876 auto type =
static_cast<QMetaType::Type
>(value.type());
2878 auto type = value.typeId();
2903 else if (
toBool(
"verboseint"))
2910 int quiet =
toInt(
"quiet");
2911 if (std::max(quiet,
static_cast<int>(
progress)) > 1)
2917 bool loglong =
toBool(
"loglong");
2920#if CONFIG_SYSTEMD_JOURNAL
2921 bool journal =
toBool(
"systemd-journal");
2926 facility = SYSTEMD_JOURNAL_FACILITY;
2930 if (level == LOG_UNKNOWN)
2933 LOG(VB_GENERAL, LOG_CRIT,
2934 QString(
"%1 version: %2 [%3] www.mythtv.org")
2935 .arg(QCoreApplication::applicationName(),
2937 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2938 .arg(QT_VERSION_STR, qVersion()));
2939 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2940 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2941 LOG(VB_GENERAL, LOG_NOTICE,
2945 bool propagate = !logfile.isEmpty();
2948 quiet = std::max(quiet, 1);
2951 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2952 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2964 std::cerr <<
"Applying settings override\n";
2967 if (!
override.empty())
2969 QMap<QString, QString>::iterator it;
2970 for (it =
override.begin(); it !=
override.end(); ++it)
2972 LOG(VB_GENERAL, LOG_NOTICE,
2973 QString(
"Setting '%1' being forced to '%2'")
2974 .arg(it.key(), *it));
2982 if (!pidfile.isEmpty())
2984 pidfs.open(pidfile.toLatin1().constData());
2987 std::cerr <<
"Could not open pid file: " <<
ENO_STR <<
'\n';
2998 if (username.isEmpty())
3002 std::cerr <<
"--user option is not supported on Windows" << std::endl;
3008 int dumpability = prctl(PR_GET_DUMPABLE);
3010 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
3011 const uid_t user_id =
geteuid();
3015 std::cerr <<
"You must be running as root to use the --user switch.\n";
3020 LOG(VB_GENERAL, LOG_WARNING,
3021 QString(
"Already running as '%1'").arg(username));
3027 std::cerr <<
"Error setting home directory.\n";
3032 std::cerr <<
"Error setting effective group.\n";
3037 std::cerr <<
"Error setting groups.\n";
3042 std::cerr <<
"Error setting effective user.\n";
3046 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3048 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3049 "creation. Run without the --user argument to use "
3050 "shell-specified limits.");
3056 std::cerr << QString(
"Invalid user '%1' specified with --user")
3057 .arg(username).toLocal8Bit().constData() <<
'\n';
3069 std::ofstream pidfs;
3073 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3074 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3079 std::cerr <<
"Daemonizing is unavailable in OSX\n";
3080 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3085 std::cerr <<
"Failed to daemonize: " <<
ENO_STR <<
'\n';
3090 QString username =
toString(
"username");
3091 if (!username.isEmpty() && !
setUser(username))
3096 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")