23 #if defined ANDROID && __ANDROID_API__ < 24
39 #include <sys/types.h>
41 #include <sys/ioctl.h>
44 #if defined(__linux__) || defined(__LINUX__)
45 #include <sys/prctl.h>
51 #include <QCoreApplication>
56 #include <QRegularExpression>
59 #include <QTextStream>
61 #include <QVariantList>
62 #include <QVariantMap>
65 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
68 #define QT_ENDL Qt::endl
74 #include "mythconfig.h"
84 bool setUser(
const QString &username);
93 #if defined(_WIN32) || defined(Q_OS_ANDROID)
98 if (ioctl(0, TIOCGWINSZ, &ws) != 0)
101 return static_cast<int>(ws.ws_col);
107 if (val.startsWith(
'"') && val.endsWith(
'"'))
108 return val.mid(1,val.size()-2);
109 if (val.startsWith(
'\'') && val.endsWith(
'\''))
110 return val.mid(1,val.size()-2);
134 return "kCombOptVal";
140 return "kPassthrough";
183 QVariant def, QString
help, QString longhelp) :
185 m_name(name), m_type(
type), m_default(std::move(def)),
186 m_help(std::move(
help)), m_longhelp(std::move(longhelp))
188 if ((
m_type != QVariant::String) && (
m_type != QVariant::StringList) &&
189 (
m_type != QVariant::Map))
201 m_name(name), m_type(
type), m_default(std::move(def))
203 if ((
m_type != QVariant::String) && (
m_type != QVariant::StringList) &&
204 (
m_type != QVariant::Map))
238 QList<CommandLineArg*>::const_iterator i1;
240 len = std::max(len, (*i1)->GetKeywordLength()+2);
263 QTextStream msg(&helpstr, QIODevice::WriteOnly);
308 QStringList hlist =
m_help.split(
'\n');
313 << hlist.takeFirst() <<
QT_ENDL;
316 for (
const auto & line : qAsConst(hlist))
321 msg <<
arg->GetHelpString(off, group,
true);
337 QTextStream msg(&helpstr, QIODevice::WriteOnly);
360 for (
const auto & word : qAsConst(
m_keywords))
366 msg <<
"Aliases: " << word <<
QT_ENDL;
375 msg <<
"Type: " << QVariant::typeToName(
static_cast<int>(
m_type)) <<
QT_ENDL;
376 if (
m_default.canConvert(QVariant::String))
387 msg <<
"Description: " <<
help.takeFirst() <<
QT_ENDL;
388 for (
const auto & line : qAsConst(
help))
391 QList<CommandLineArg*>::const_iterator i2;
397 for (
auto * parent : qAsConst(
m_parents))
398 msg <<
" " << parent->GetPreferredKeyword()
399 .toLocal8Bit().constData();
407 msg <<
" " << (*i2)->GetPreferredKeyword()
408 .toLocal8Bit().constData();
416 msg <<
" " << (*i2)->GetPreferredKeyword()
417 .toLocal8Bit().constData();
425 msg <<
" " << (*i2)->GetPreferredKeyword()
426 .toLocal8Bit().constData();
457 case QVariant::String:
462 std::cerr <<
"Command line option did not receive value:" << std::endl
463 <<
" " << opt.toLocal8Bit().constData() << std::endl;
476 QList<QByteArray> blist;
483 std::cerr <<
"Boolean type options do not accept values:" << std::endl
484 <<
" " << opt.toLocal8Bit().constData() << std::endl;
487 case QVariant::String:
499 case QVariant::LongLong:
500 m_stored = QVariant(val.toLongLong());
503 case QVariant::Double:
504 m_stored = QVariant(val.toDouble());
507 case QVariant::DateTime:
511 case QVariant::StringList:
519 if (!val.contains(
'='))
521 std::cerr <<
"Command line option did not get expected "
522 <<
"key/value pair" << std::endl;
526 blist = val.split(
'=');
535 if (!val.contains(
'x'))
537 std::cerr <<
"Command line option did not get expected "
538 <<
"XxY pair" << std::endl;
542 blist = val.split(
'x');
543 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
566 for (
const auto& opt : qAsConst(
opts))
583 for (
const auto& opt : qAsConst(
opts))
600 for (
const auto& opt : qAsConst(
opts))
617 for (
const auto& opt : qAsConst(
opts))
635 for (
const auto& opt : qAsConst(
opts))
656 for (
const auto& opt : qAsConst(
opts))
676 for (
const auto& opt : qAsConst(
opts))
693 for (
const auto& opt : qAsConst(
opts))
702 if (depstr.isEmpty())
703 depstr =
"and will be removed in a future version.";
712 if (remstr.isEmpty())
713 remstr =
"and is no longer available in this version.";
726 bool replaced =
false;
754 bool replaced =
false;
757 for (
int i = 0; i <
m_parents.size(); i++)
782 bool replaced =
false;
811 bool replaced =
false;
814 for (
int i = 0; i <
m_blocks.size(); i++)
842 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
846 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
848 (*i1)->SetBlocks(*i2);
851 if ((*i1)->m_type == QVariant::Invalid)
864 if (!QCoreApplication::instance())
879 if (
m_type == QVariant::String)
881 if (
m_stored.type() == QVariant::ByteArray)
889 else if (
m_type == QVariant::StringList)
891 if (
m_stored.type() == QVariant::List)
893 QVariantList vlist =
m_stored.toList();
895 for (
const auto& item : qAsConst(vlist))
896 slist << QString::fromLocal8Bit(item.toByteArray());
900 else if (
m_type == QVariant::Map)
902 QVariantMap vmap =
m_stored.toMap();
904 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
905 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
921 QStringList::const_iterator it;
927 int len2 = (*it).size();
946 QList<CommandLineArg*>::const_iterator i;
960 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
961 <<
" requires at least one of the following arguments" << std::endl;
964 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
965 std::cerr << std::endl << std::endl;
976 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
977 <<
" requires all of the following be defined as well"
982 << (*i)->GetPreferredKeyword().toLocal8Bit()
985 std::cerr << std::endl << std::endl;
995 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
996 <<
" requires that none of the following be defined" << std::endl;
1000 << (*i)->GetPreferredKeyword().toLocal8Bit()
1003 std::cerr << std::endl << std::endl;
1039 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1042 QMap<QString, QVariant> tmpmap;
1043 QMap<QString, QVariant>::const_iterator it;
1049 case QVariant::Bool:
1050 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1054 std::cerr <<
m_stored.toInt() << std::endl;
1057 case QVariant::UInt:
1058 std::cerr <<
m_stored.toUInt() << std::endl;
1061 case QVariant::LongLong:
1062 std::cerr <<
m_stored.toLongLong() << std::endl;
1065 case QVariant::Double:
1066 std::cerr <<
m_stored.toDouble() << std::endl;
1069 case QVariant::Size:
1071 std::cerr <<
"x=" << tmpsize.width()
1072 <<
" y=" << tmpsize.height()
1076 case QVariant::String:
1077 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1078 <<
'"' << std::endl;
1081 case QVariant::StringList:
1083 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1084 for (
const auto& str : qAsConst(vlist))
1090 std::cerr << std::endl;
1095 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1100 std::cerr << QString(
"").leftJustified(32)
1101 .toLocal8Bit().constData();
1103 std::cerr << it.key().toLocal8Bit().constData()
1105 << it->toByteArray().constData()
1111 case QVariant::DateTime:
1113 .toLocal8Bit().constData()
1118 std::cerr << std::endl;
1126 QString warn = QString(
"%1 has been removed").arg(keyword);
1130 std::cerr << QString(
"****************************************************\n"
1133 "****************************************************\n\n")
1135 .toLocal8Bit().constData();
1142 std::cerr << QString(
"****************************************************\n"
1143 " WARNING: %1 has been deprecated\n"
1145 "****************************************************\n\n")
1147 .toLocal8Bit().constData();
1164 : m_appname(std::move(appname))
1166 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1168 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1177 QMap<QString, CommandLineArg*>::iterator i;
1182 (*i)->CleanupLinks();
1229 const QString& name, QVariant::Type
type, QVariant def,
1230 QString
help, QString longhelp)
1242 for (
const auto & str : qAsConst(arglist))
1246 arg->AddKeyword(str);
1249 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1250 <<
" as taking type '" << QVariant::typeToName(
static_cast<int>(
type))
1251 <<
"'" << std::endl;
1265 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1270 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1271 #ifdef MYTH_BUILD_CONFIG
1272 std::cout <<
"Options compiled in:" <<std::endl;
1273 std::cout << MYTH_BUILD_CONFIG << std::endl;
1282 std::cerr <<
help.toLocal8Bit().constData();
1293 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1295 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1299 if (
toString(
"showhelp").isEmpty())
1304 if (descr.size() > 0)
1308 QStringList groups(
"");
1312 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1313 if (!groups.contains(cmdarg->m_group))
1314 groups << cmdarg->m_group;
1320 for (
const auto & group : qAsConst(groups))
1322 if (group.isEmpty())
1323 msg <<
"Misc. Options:" <<
QT_ENDL;
1325 msg << group.toLocal8Bit().constData() <<
" Options:" <<
QT_ENDL;
1328 msg << cmdarg->GetHelpString(maxlen, group);
1335 QString optstr =
"-" +
toString(
"showhelp");
1338 optstr =
"-" + optstr;
1340 return QString(
"Could not find option matching '%1'\n")
1355 int &argpos, QString &opt, QByteArray &val)
1364 QByteArray
tmp(argv[argpos]);
1376 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1385 if (
tmp.contains(
'='))
1388 QList<QByteArray> blist =
tmp.split(
'=');
1390 if (blist.size() != 2)
1404 if (argpos+1 >= argc)
1408 tmp = QByteArray(argv[++argpos]);
1413 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1447 for (
int argpos = 1; argpos < argc; ++argpos)
1451 res =
getOpt(argc, argv, argpos, opt, val);
1456 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1457 <<
"val: " << val.constData() << std::endl << std::endl;
1463 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1480 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1481 << opt.toLocal8Bit().constData();
1498 std::cerr <<
"Received '"
1500 <<
"' but unassociated arguments have not been enabled"
1513 std::cerr <<
"Command line arguments received out of sequence"
1520 if (opt.startsWith(
"-psn_"))
1522 std::cerr <<
"Ignoring Process Serial Number from command line"
1535 QByteArray
tmp = opt.toLocal8Bit();
1544 std::cerr <<
"Unhandled option given on command line:" << std::endl
1545 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1566 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1572 if (!argdef->
Set(opt))
1581 if (!argdef->
Set(opt, val))
1602 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1608 std::cerr <<
"Processed option list:" << std::endl;
1610 cmdarg->PrintVerbose();
1614 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1616 for (
const auto& lopt : qAsConst(slist))
1617 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1622 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1623 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1626 std::cerr << std::endl;
1632 if (!cmdarg->TestLinks())
1634 QString keyword = cmdarg->m_usedKeyword;
1635 if (keyword.startsWith(
'-'))
1637 if (keyword.startsWith(
"--"))
1638 keyword.remove(0,2);
1640 keyword.remove(0,1);
1652 QString
help, QString longhelp)
1654 return add(QStringList(
arg), name, QVariant::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1658 QString
help, QString longhelp)
1660 return add(QStringList(
arg), name, QVariant::Int, QVariant(def), std::move(
help), std::move(longhelp));
1664 QString
help, QString longhelp)
1666 return add(QStringList(
arg), name, QVariant::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1670 QString
help, QString longhelp)
1672 return add(QStringList(
arg), name, QVariant::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1676 QString
help, QString longhelp)
1678 return add(QStringList(
arg), name, QVariant::Double, QVariant(def), std::move(
help), std::move(longhelp));
1682 QString
help, QString longhelp)
1684 return add(QStringList(
arg), name, QVariant::String, QVariant(def), std::move(
help), std::move(longhelp));
1688 QString
help, QString longhelp)
1690 return add(QStringList(
arg), name, QVariant::String, QVariant(def), std::move(
help), std::move(longhelp));
1694 QString
help, QString longhelp)
1696 return add(QStringList(
arg), name, QVariant::Size, QVariant(def), std::move(
help), std::move(longhelp));
1700 QString
help, QString longhelp)
1702 return add(QStringList(
arg), name, QVariant::DateTime, QVariant(def), std::move(
help), std::move(longhelp));
1706 QString
help, QString longhelp)
1708 return add(QStringList(
arg), name,
type, QVariant(
type), std::move(
help), std::move(longhelp));
1712 QVariant def, QString
help, QString longhelp)
1714 return add(QStringList(
arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1718 QString
help, QString longhelp)
1720 return add(std::move(arglist), name, QVariant::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1724 QString
help, QString longhelp)
1726 return add(std::move(arglist), name, QVariant::Int, QVariant(def), std::move(
help), std::move(longhelp));
1730 QString
help, QString longhelp)
1732 return add(std::move(arglist), name, QVariant::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1736 QString
help, QString longhelp)
1738 return add(std::move(arglist), name, QVariant::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1742 QString
help, QString longhelp)
1744 return add(std::move(arglist), name, QVariant::Double, QVariant(def), std::move(
help), std::move(longhelp));
1748 QString
help, QString longhelp)
1750 return add(std::move(arglist), name, QVariant::String, QVariant(def), std::move(
help), std::move(longhelp));
1754 QString
help, QString longhelp)
1756 return add(std::move(arglist), name, QVariant::String, QVariant(def), std::move(
help), std::move(longhelp));
1760 QString
help, QString longhelp)
1762 return add(std::move(arglist), name, QVariant::Size, QVariant(def), std::move(
help), std::move(longhelp));
1766 QString
help, QString longhelp)
1768 return add(std::move(arglist), name, QVariant::DateTime, QVariant(def), std::move(
help), std::move(longhelp));
1772 QString
help, QString longhelp)
1774 return add(std::move(arglist), name,
type, QVariant(
type), std::move(
help), std::move(longhelp));
1783 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1785 QMap<QString,CommandLineArg*>::iterator args_it;
1788 QList<CommandLineArg*> links = (*args_it)->m_parents;
1789 QList<CommandLineArg*>::iterator links_it;
1790 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1792 if ((*links_it)->m_type != QVariant::Invalid)
1798 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1799 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1800 <<
"' could not find '"
1801 << (*links_it)->m_name.toLocal8Bit().constData()
1802 <<
"'." << std::endl
1803 <<
" Please resolve dependency and recompile." << std::endl;
1810 std::cerr << QString(
" Setting %1 as child of %2")
1811 .arg((*args_it)->m_name).arg((*links_it)->m_name)
1812 .toLocal8Bit().constData()
1815 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1818 links = (*args_it)->m_children;
1819 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1821 if ((*links_it)->m_type != QVariant::Invalid)
1827 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1828 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1829 <<
"' could not find '"
1830 << (*links_it)->m_name.toLocal8Bit().constData()
1831 <<
"'." << std::endl
1832 <<
" Please resolve dependency and recompile." << std::endl;
1839 std::cerr << QString(
" Setting %1 as parent of %2")
1840 .arg((*args_it)->m_name).arg((*links_it)->m_name)
1841 .toLocal8Bit().constData()
1844 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1847 links = (*args_it)->m_requires;
1848 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1850 if ((*links_it)->m_type != QVariant::Invalid)
1856 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1857 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1858 <<
"' could not find '"
1859 << (*links_it)->m_name.toLocal8Bit().constData()
1860 <<
"'." << std::endl
1861 <<
" Please resolve dependency and recompile." << std::endl;
1868 std::cerr << QString(
" Setting %1 as requiring %2")
1869 .arg((*args_it)->m_name).arg((*links_it)->m_name)
1870 .toLocal8Bit().constData()
1873 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
1876 QList<CommandLineArg*>::iterator req_it =
1877 (*args_it)->m_requiredby.begin();
1878 while (req_it != (*args_it)->m_requiredby.end())
1880 if ((*req_it)->m_type == QVariant::Invalid)
1885 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
1888 std::cerr << QString(
" Setting %1 as blocking %2")
1889 .arg((*args_it)->m_name)
1890 .arg((*req_it)->m_name)
1891 .toLocal8Bit().constData()
1897 (*req_it)->DecrRef();
1898 req_it = (*args_it)->m_requiredby.erase(req_it);
1901 QList<CommandLineArg*>::iterator block_it =
1902 (*args_it)->m_blocks.begin();
1903 while (block_it != (*args_it)->m_blocks.end())
1905 if ((*block_it)->m_type != QVariant::Invalid)
1913 (*block_it)->DecrRef();
1914 block_it = (*args_it)->m_blocks.erase(block_it);
1921 std::cerr << QString(
" Setting %1 as blocking %2")
1922 .arg((*args_it)->m_name).arg((*block_it)->m_name)
1923 .toLocal8Bit().constData()
1926 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
1946 var =
arg->m_stored;
1948 var =
arg->m_default;
1966 return toMap(
"_extra");
1985 QMap<QString,QString> smap =
toMap(
"overridesettings");
1989 if (
toBool(
"overridesettingsfile"))
1995 if (
f.open(QIODevice::ReadOnly))
1998 while (!in.atEnd()) {
1999 QString line = in.readLine().trimmed();
2000 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2001 QStringList tokens = line.split(
"=",
2002 QString::SkipEmptyParts);
2004 QStringList tokens = line.split(
"=",
2005 Qt::SkipEmptyParts);
2007 if (tokens.size() == 2)
2009 tokens[0].remove(QRegularExpression(
"^[\"']"));
2010 tokens[0].remove(QRegularExpression(
"[\"']$"));
2011 tokens[1].remove(QRegularExpression(
"^[\"']"));
2012 tokens[1].remove(QRegularExpression(
"[\"']$"));
2013 if (!tokens[0].isEmpty())
2014 smap[tokens[0]] = tokens[1];
2021 std::cerr <<
"Failed to open the override settings file: '"
2022 <<
tmp.constData() <<
"'" << std::endl;
2028 smap[
"RunFrontendInWindow"] =
"1";
2029 else if (
toBool(
"notwindowed"))
2030 smap[
"RunFrontendInWindow"] =
"0";
2032 if (
toBool(
"mousecursor"))
2033 smap[
"HideMouseCursor"] =
"0";
2034 else if (
toBool(
"nomousecursor"))
2035 smap[
"HideMouseCursor"] =
"1";
2039 if (!smap.isEmpty())
2042 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2043 vmap[it.key()] = QVariant(it.value());
2045 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2051 std::cerr <<
"Option Overrides:" << std::endl;
2052 QMap<QString, QString>::const_iterator it;
2053 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2054 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2055 .toLocal8Bit().constData() << std::endl;
2076 if (
arg->m_type == QVariant::Bool)
2079 return arg->m_stored.toBool();
2080 return arg->m_default.toBool();
2083 return arg->m_given;
2101 if (
arg->m_stored.canConvert(QVariant::Int))
2102 val =
arg->m_stored.toInt();
2106 if (
arg->m_default.canConvert(QVariant::Int))
2107 val =
arg->m_default.toInt();
2128 if (
arg->m_stored.canConvert(QVariant::UInt))
2129 val =
arg->m_stored.toUInt();
2133 if (
arg->m_default.canConvert(QVariant::UInt))
2134 val =
arg->m_default.toUInt();
2155 if (
arg->m_stored.canConvert(QVariant::LongLong))
2156 val =
arg->m_stored.toLongLong();
2160 if (
arg->m_default.canConvert(QVariant::LongLong))
2161 val =
arg->m_default.toLongLong();
2182 if (
arg->m_stored.canConvert(QVariant::Double))
2183 val =
arg->m_stored.toDouble();
2187 if (
arg->m_default.canConvert(QVariant::Double))
2188 val =
arg->m_default.toDouble();
2209 if (
arg->m_stored.canConvert(QVariant::Size))
2210 val =
arg->m_stored.toSize();
2214 if (
arg->m_default.canConvert(QVariant::Size))
2215 val =
arg->m_default.toSize();
2236 if (!
arg->m_converted)
2239 if (
arg->m_stored.canConvert(QVariant::String))
2240 val =
arg->m_stored.toString();
2244 if (
arg->m_default.canConvert(QVariant::String))
2245 val =
arg->m_default.toString();
2268 if (!
arg->m_converted)
2271 varval =
arg->m_stored;
2274 varval =
arg->m_default;
2276 if (
arg->m_type == QVariant::String && !sep.isEmpty())
2277 val = varval.toString().split(sep);
2278 else if (varval.canConvert(QVariant::StringList))
2279 val = varval.toStringList();
2289 QMap<QString, QString> val;
2290 QMap<QString, QVariant>
tmp;
2300 if (!
arg->m_converted)
2303 if (
arg->m_stored.canConvert(QVariant::Map))
2304 tmp =
arg->m_stored.toMap();
2308 if (
arg->m_default.canConvert(QVariant::Map))
2309 tmp =
arg->m_default.toMap();
2312 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2313 val[i.key()] = i.value().toString();
2333 if (
arg->m_stored.canConvert(QVariant::DateTime))
2334 val =
arg->m_stored.toDateTime();
2338 if (
arg->m_default.canConvert(QVariant::DateTime))
2339 val =
arg->m_default.toDateTime();
2375 QMap<QString,QVariant> vmap;
2395 QVariant::StringList, QStringList());
2403 add(QStringList{
"-h",
"--help",
"--usage"},
2404 "showhelp",
"",
"Display this help printout, or give detailed "
2405 "information of selected option.",
2406 "Displays a list of all commands available for use with "
2407 "this application. If another option is provided as an "
2408 "argument, it will provide detailed information on that "
2416 add(
"--version",
"showversion",
false,
"Display version information.",
2417 "Display informtion about build, including:\n"
2418 " version, branch, protocol, library API, Qt "
2419 "and compiled options.");
2426 add(QStringList{
"-nw",
"--no-windowed"},
2427 "notwindowed",
false,
2428 "Prevent application from running in a window.",
"")
2429 ->SetBlocks(
"windowed")
2432 add(QStringList{
"-w",
"--windowed"},
"windowed",
2433 false,
"Force application to run in a window.",
"")
2434 ->SetGroup(
"User Interface");
2441 add(
"--mouse-cursor",
"mousecursor",
false,
2442 "Force visibility of the mouse cursor.",
"")
2446 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2447 "Force the mouse cursor to be hidden.",
"")
2455 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2456 "Fork application into background after startup.",
2457 "Fork application into background, detatching from "
2458 "the local terminal.\nOften used with: "
2459 " --logpath --pidfile --user");
2467 add(QStringList{
"-O",
"--override-setting"},
2468 "overridesettings", QVariant::Map,
2469 "Override a single setting defined by a key=value pair.",
2470 "Override a single setting from the database using "
2471 "options defined as one or more key=value pairs\n"
2472 "Multiple can be defined by multiple uses of the "
2474 add(
"--override-settings-file",
"overridesettingsfile",
"",
2475 "Define a file of key=value pairs to be "
2476 "loaded for setting overrides.",
"");
2483 add(
"--chanid",
"chanid", 0U,
2484 "Specify chanid of recording to operate on.",
"")
2487 add(
"--starttime",
"starttime", QDateTime(),
2488 "Specify start time of recording to operate on.",
"")
2496 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2497 "",
"Specify window size and position (WxH[+X+Y])",
"")
2498 ->SetGroup(
"User Interface");
2505 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2512 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2519 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2522 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2523 LOG_INFO : defaultLogLevel;
2527 add(QStringList{
"-v",
"--verbose"},
"verbose",
2529 "Specify log filtering. Use '-v help' for level info.",
"")
2530 ->SetGroup(
"Logging");
2531 add(
"-V",
"verboseint", 0LL,
"",
2532 "This option is intended for internal use only.\n"
2533 "This option takes an unsigned value corresponding "
2534 "to the bitwise log verbosity operator.")
2536 add(
"--logpath",
"logpath",
"",
2537 "Writes logging messages to a file in the directory logpath with "
2538 "filenames in the format: applicationName.date.pid.log.\n"
2539 "This is typically used in combination with --daemon, and if used "
2540 "in combination with --pidfile, this can be used with log "
2541 "rotators, using the HUP call to inform MythTV to reload the "
2544 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2545 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2546 ->SetGroup(
"Logging");
2547 add(
"--loglevel",
"loglevel", logLevelStr,
2549 "Set the logging level. All log messages at lower levels will be "
2551 "In descending order: emerg, alert, crit, err, warning, notice, "
2552 "info, debug\ndefaults to ") + logLevelStr,
"")
2554 add(
"--syslog",
"syslog",
"none",
2555 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2556 "defaults to none.",
"")
2558 #if CONFIG_SYSTEMD_JOURNAL
2559 add(
"--systemd-journal",
"systemd-journal",
"false",
2560 "Use systemd-journal instead of syslog.",
"")
2566 add(
"--nodblog",
"nodblog",
false,
"Disable database logging.",
"")
2568 ->
SetDeprecated(
"this is now the default, see --enable-dblog");
2569 add(
"--enable-dblog",
"enabledblog",
false,
"Enable logging to database.",
"")
2572 add(QStringList{
"-l",
"--logfile"},
2573 "logfile",
"",
"",
"")
2574 ->SetGroup(
"Logging")
2575 ->
SetRemoved(
"This option has been removed as part of "
2576 "rewrite of the logging interface. Please update your init "
2577 "scripts to use --syslog to interface with your system's "
2578 "existing system logging daemon, or --logpath to specify a "
2579 "dirctory for MythTV to write its logs to.",
"0.25");
2586 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2587 "Write PID of application to filename.",
2588 "Write the PID of the currently running process as a single "
2589 "line to this file. Used for init scripts to know what "
2590 "process to terminate, and with log rotators "
2591 "to send a HUP signal to process to have it re-open files.");
2598 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2599 "Intended for internal use only, specify the JobID to match "
2600 "up with in the database for additional information and the "
2601 "ability to update runtime status in the database.");
2608 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2610 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2618 add(QStringList{
"-display",
"--display"},
"display",
"",
2619 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2628 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2629 "Qt platform argument that is passed through to Qt")
2638 pid_t pid = getpid();
2646 LOG(VB_GENERAL, LOG_ERR,
2647 QString(
"%1 is not a directory, disabling logfiles")
2652 QString logdir = finfo.filePath();
2653 logfile = QCoreApplication::applicationName() +
"." +
2655 QString(
".%1").arg(pid) +
".log";
2668 QString setting =
toString(
"syslog").toLower();
2669 if (setting ==
"none")
2679 QString setting =
toString(
"loglevel");
2680 if (setting.isEmpty())
2684 if (level == LOG_UNKNOWN)
2685 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2701 const QVariant& val(value);
2708 if (
arg->m_type != value.type())
2732 else if (
toBool(
"verboseint"))
2745 #if CONFIG_SYSTEMD_JOURNAL
2746 bool journal =
toBool(
"systemd-journal");
2751 facility = SYSTEMD_JOURNAL_FACILITY;
2754 bool dblog =
toBool(
"enabledblog");
2756 if (level == LOG_UNKNOWN)
2759 LOG(VB_GENERAL, LOG_CRIT,
2760 QString(
"%1 version: %2 [%3] www.mythtv.org")
2761 .
arg(QCoreApplication::applicationName())
2763 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2764 .
arg(QT_VERSION_STR).
arg(qVersion()));
2765 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2766 .
arg(QSysInfo::prettyProductName()).
arg(QSysInfo::currentCpuArchitecture()));
2767 LOG(VB_GENERAL, LOG_NOTICE,
2771 bool propagate = !
logfile.isEmpty();
2777 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2778 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2790 std::cerr <<
"Applying settings override" << std::endl;
2793 if (!
override.empty())
2795 QMap<QString, QString>::iterator it;
2796 for (it =
override.begin(); it !=
override.end(); ++it)
2798 LOG(VB_GENERAL, LOG_NOTICE,
2799 QString(
"Setting '%1' being forced to '%2'")
2800 .
arg(it.key()).arg(*it));
2810 pidfs.open(
pidfile.toLatin1().constData());
2813 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2824 if (username.isEmpty())
2828 cerr <<
"--user option is not supported on Windows" << endl;
2831 #if defined(__linux__) || defined(__LINUX__)
2834 int dumpability = prctl(PR_GET_DUMPABLE);
2836 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
2837 const uid_t user_id =
geteuid();
2841 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
2846 LOG(VB_GENERAL, LOG_WARNING,
2847 QString(
"Already running as '%1'").
arg(username));
2853 std::cerr <<
"Error setting home directory." << std::endl;
2858 std::cerr <<
"Error setting effective group." << std::endl;
2863 std::cerr <<
"Error setting groups." << std::endl;
2868 std::cerr <<
"Error setting effective user." << std::endl;
2871 #if defined(__linux__) || defined(__LINUX__)
2872 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
2874 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
2875 "creation. Run without the --user argument to use "
2876 "shell-specified limits.");
2882 std::cerr << QString(
"Invalid user '%1' specified with --user")
2883 .arg(username).toLocal8Bit().constData() << std::endl;
2895 std::ofstream pidfs;
2899 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
2900 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
2905 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
2906 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
2911 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
2916 QString username =
toString(
"username");
2917 if (!username.isEmpty() && !
setUser(username))
2922 pidfs << getpid() << std::endl;