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
75 #include "mythconfig.h"
77 #include "mythversion.h"
89 #if defined(_WIN32) || defined(Q_OS_ANDROID)
94 if (ioctl(0, TIOCGWINSZ, &ws) != 0)
97 return static_cast<int>(ws.ws_col);
103 return ((array.startsWith(
'"') && array.endsWith(
'"') ) ||
104 (array.startsWith(
'\'') && array.endsWith(
'\''))
105 ) ? array.mid(1, array.size() - 2) : array;
112 width = std::max(width, 5);
114 for (
int i = 0; i < list.size(); i++)
116 QString
string = list.at(i);
118 if(
string.size() <= width )
121 QString left =
string.left(width);
122 bool inserted =
false;
124 while( !inserted && !left.endsWith(
" " ))
126 if(
string.mid(left.size(), 1) ==
" " )
128 list.replace(i, left);
129 list.insert(i+1,
string.mid(left.size()).trimmed());
135 if( !left.contains(
" ") )
138 list.replace(i, left +
"-");
139 list.insert(i+1,
string.mid(left.size()));
148 list.replace(i, left);
149 list.insert(i+1,
string.mid(left.size()).trimmed());
173 states state =
START;
176 for (
int i = 0; i < line.size(); i++)
178 const QChar c = line.at(i);
183 if (c.isSpace())
break;
184 if (c ==
'\'') state = INSQUOTE;
185 else if (c ==
'\"') state = INDQUOTE;
186 else if (c ==
'\\') state = ESCTEXT;
191 fields += line.mid(tokenStart, i - tokenStart);
195 else if (c ==
'\'') state = INSQUOTE;
196 else if (c ==
'\"') state = INDQUOTE;
197 else if (c ==
'\\') state = ESCTEXT;
200 if (c ==
'\'') state = INTEXT;
201 else if (c ==
'\\') state = ESCSQUOTE;
204 if (c ==
'\"') state = INTEXT;
205 else if (c ==
'\\') state = ESCDQUOTE;
207 case ESCTEXT: state = INTEXT;
break;
208 case ESCSQUOTE: state = INSQUOTE;
break;
209 case ESCDQUOTE: state = INDQUOTE;
break;
214 fields += line.mid(tokenStart);
238 return "kCombOptVal";
244 return "kPassthrough";
287 QVariant def, QString
help, QString longhelp) :
289 m_name(name), m_type(
type), m_default(
std::move(def)),
290 m_help(
std::move(
help)), m_longhelp(
std::move(longhelp))
292 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
293 (
m_type != QMetaType::QVariantMap))
305 m_name(name), m_type(
type), m_default(
std::move(def))
307 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
308 (
m_type != QMetaType::QVariantMap))
342 QList<CommandLineArg*>::const_iterator i1;
344 len = std::max(len, (*i1)->GetKeywordLength()+2);
367 QTextStream msg(&helpstr, QIODevice::WriteOnly);
412 QStringList hlist =
m_help.split(
'\n');
417 << hlist.takeFirst() <<
QT_ENDL;
420 for (
const auto & line : qAsConst(hlist))
425 msg << arg->GetHelpString(off, group,
true);
441 QTextStream msg(&helpstr, QIODevice::WriteOnly);
464 for (
const auto & word : qAsConst(
m_keywords))
470 msg <<
"Aliases: " << word <<
QT_ENDL;
479 #if QT_VERSION < QT_VERSION_CHECK(5,15,0)
495 msg <<
"Description: " <<
help.takeFirst() <<
QT_ENDL;
496 for (
const auto & line : qAsConst(
help))
499 QList<CommandLineArg*>::const_iterator i2;
505 for (
auto * parent : qAsConst(
m_parents))
506 msg <<
" " << parent->GetPreferredKeyword()
507 .toLocal8Bit().constData();
515 msg <<
" " << (*i2)->GetPreferredKeyword()
516 .toLocal8Bit().constData();
524 msg <<
" " << (*i2)->GetPreferredKeyword()
525 .toLocal8Bit().constData();
533 msg <<
" " << (*i2)->GetPreferredKeyword()
534 .toLocal8Bit().constData();
554 case QMetaType::Bool:
565 case QMetaType::QString:
570 std::cerr <<
"Command line option did not receive value:" << std::endl
571 <<
" " << opt.toLocal8Bit().constData() << std::endl;
584 QList<QByteArray> blist;
590 case QMetaType::Bool:
591 std::cerr <<
"Boolean type options do not accept values:" << std::endl
592 <<
" " << opt.toLocal8Bit().constData() << std::endl;
595 case QMetaType::QString:
603 case QMetaType::UInt:
607 case QMetaType::LongLong:
608 m_stored = QVariant(val.toLongLong());
611 case QMetaType::Double:
612 m_stored = QVariant(val.toDouble());
615 case QMetaType::QDateTime:
619 case QMetaType::QStringList:
626 case QMetaType::QVariantMap:
627 if (!val.contains(
'='))
629 std::cerr <<
"Command line option did not get expected "
630 <<
"key/value pair" << std::endl;
634 blist = val.split(
'=');
642 case QMetaType::QSize:
643 if (!val.contains(
'x'))
645 std::cerr <<
"Command line option did not get expected "
646 <<
"XxY pair" << std::endl;
650 blist = val.split(
'x');
651 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
674 for (
const auto& opt : qAsConst(
opts))
691 for (
const auto& opt : qAsConst(
opts))
708 for (
const auto& opt : qAsConst(
opts))
725 for (
const auto& opt : qAsConst(
opts))
743 for (
const auto& opt : qAsConst(
opts))
764 for (
const auto& opt : qAsConst(
opts))
784 for (
const auto& opt : qAsConst(
opts))
801 for (
const auto& opt : qAsConst(
opts))
810 if (depstr.isEmpty())
811 depstr =
"and will be removed in a future version.";
820 if (remstr.isEmpty())
821 remstr =
"and is no longer available in this version.";
834 bool replaced =
false;
862 bool replaced =
false;
865 for (
int i = 0; i <
m_parents.size(); i++)
890 bool replaced =
false;
919 bool replaced =
false;
922 for (
int i = 0; i <
m_blocks.size(); i++)
950 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
954 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
956 (*i1)->SetBlocks(*i2);
959 if ((*i1)->m_type == QMetaType::UnknownType)
972 if (!QCoreApplication::instance())
987 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
988 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
990 auto storedType =
m_stored.typeId();
992 if (
m_type == QMetaType::QString)
994 if (storedType == QMetaType::QByteArray)
1002 else if (
m_type == QMetaType::QStringList)
1004 if (storedType == QMetaType::QVariantList)
1006 QVariantList vlist =
m_stored.toList();
1008 for (
const auto& item : qAsConst(vlist))
1009 slist << QString::fromLocal8Bit(item.toByteArray());
1013 else if (
m_type == QMetaType::QVariantMap)
1015 QVariantMap vmap =
m_stored.toMap();
1017 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1018 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1034 QStringList::const_iterator it;
1040 int len2 = (*it).size();
1059 QList<CommandLineArg*>::const_iterator i;
1061 bool passes =
false;
1073 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1074 <<
" requires at least one of the following arguments" << std::endl;
1077 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1078 std::cerr << std::endl << std::endl;
1089 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1090 <<
" requires all of the following be defined as well"
1095 << (*i)->GetPreferredKeyword().toLocal8Bit()
1098 std::cerr << std::endl << std::endl;
1108 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1109 <<
" requires that none of the following be defined" << std::endl;
1113 << (*i)->GetPreferredKeyword().toLocal8Bit()
1116 std::cerr << std::endl << std::endl;
1152 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1155 QMap<QString, QVariant> tmpmap;
1156 QMap<QString, QVariant>::const_iterator it;
1162 case QMetaType::Bool:
1163 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1166 case QMetaType::Int:
1167 std::cerr <<
m_stored.toInt() << std::endl;
1170 case QMetaType::UInt:
1171 std::cerr <<
m_stored.toUInt() << std::endl;
1174 case QMetaType::LongLong:
1175 std::cerr <<
m_stored.toLongLong() << std::endl;
1178 case QMetaType::Double:
1179 std::cerr <<
m_stored.toDouble() << std::endl;
1182 case QMetaType::QSize:
1184 std::cerr <<
"x=" << tmpsize.width()
1185 <<
" y=" << tmpsize.height()
1189 case QMetaType::QString:
1190 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1191 <<
'"' << std::endl;
1194 case QMetaType::QStringList:
1196 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1197 for (
const auto& str : qAsConst(vlist))
1203 std::cerr << std::endl;
1206 case QMetaType::QVariantMap:
1208 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1213 std::cerr << QString(
"").leftJustified(32)
1214 .toLocal8Bit().constData();
1216 std::cerr << it.key().toLocal8Bit().constData()
1218 << it->toByteArray().constData()
1224 case QMetaType::QDateTime:
1226 .toLocal8Bit().constData()
1231 std::cerr << std::endl;
1239 QString warn = QString(
"%1 has been removed").arg(keyword);
1243 std::cerr << QString(
"****************************************************\n"
1246 "****************************************************\n\n")
1248 .toLocal8Bit().constData();
1255 std::cerr << QString(
"****************************************************\n"
1256 " WARNING: %1 has been deprecated\n"
1258 "****************************************************\n\n")
1260 .toLocal8Bit().constData();
1277 : m_appname(
std::move(appname))
1279 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1281 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1290 QMap<QString, CommandLineArg*>::iterator i;
1295 (*i)->CleanupLinks();
1342 const QString& name, QMetaType::Type
type, QVariant def,
1343 QString
help, QString longhelp)
1355 for (
const auto & str : qAsConst(arglist))
1362 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1363 <<
" as taking type '"
1364 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1365 << QVariant::typeToName(
static_cast<int>(
type))
1367 << QMetaType(
type).name()
1369 <<
"'" << std::endl;
1383 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1386 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1387 std::cout <<
"Library API : " << MYTH_BINARY_VERSION << std::endl;
1388 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1389 #ifdef MYTH_BUILD_CONFIG
1390 std::cout <<
"Options compiled in:" <<std::endl;
1391 std::cout << MYTH_BUILD_CONFIG << std::endl;
1400 std::cerr <<
help.toLocal8Bit().constData();
1411 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1413 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1417 if (
toString(
"showhelp").isEmpty())
1422 if (descr.size() > 0)
1426 QStringList groups(
"");
1430 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1431 if (!groups.contains(cmdarg->m_group))
1432 groups << cmdarg->m_group;
1438 for (
const auto & group : qAsConst(groups))
1440 if (group.isEmpty())
1441 msg <<
"Misc. Options:" <<
QT_ENDL;
1443 msg << group.toLocal8Bit().constData() <<
" Options:" <<
QT_ENDL;
1446 msg << cmdarg->GetHelpString(maxlen, group);
1453 QString optstr =
"-" +
toString(
"showhelp");
1456 optstr =
"-" + optstr;
1458 return QString(
"Could not find option matching '%1'\n")
1473 int &argpos, QString &opt, QByteArray &val)
1482 QByteArray
tmp(argv[argpos]);
1494 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1503 if (
tmp.contains(
'='))
1506 QList<QByteArray> blist =
tmp.split(
'=');
1508 if (blist.size() != 2)
1522 if (argpos+1 >= argc)
1526 tmp = QByteArray(argv[++argpos]);
1531 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1565 for (
int argpos = 1; argpos < argc; ++argpos)
1569 res =
getOpt(argc, argv, argpos, opt, val);
1574 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1575 <<
"val: " << val.constData() << std::endl << std::endl;
1581 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1598 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1599 << opt.toLocal8Bit().constData();
1616 std::cerr <<
"Received '"
1618 <<
"' but unassociated arguments have not been enabled"
1631 std::cerr <<
"Command line arguments received out of sequence"
1638 if (opt.startsWith(
"-psn_"))
1640 std::cerr <<
"Ignoring Process Serial Number from command line"
1653 QByteArray
tmp = opt.toLocal8Bit();
1662 std::cerr <<
"Unhandled option given on command line:" << std::endl
1663 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1684 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1690 if (!argdef->
Set(opt))
1699 if (!argdef->
Set(opt, val))
1720 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1726 std::cerr <<
"Processed option list:" << std::endl;
1728 cmdarg->PrintVerbose();
1732 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1734 for (
const auto& lopt : qAsConst(slist))
1735 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1740 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1741 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1744 std::cerr << std::endl;
1750 if (!cmdarg->TestLinks())
1752 QString keyword = cmdarg->m_usedKeyword;
1753 if (keyword.startsWith(
'-'))
1755 if (keyword.startsWith(
"--"))
1756 keyword.remove(0,2);
1758 keyword.remove(0,1);
1770 QString
help, QString longhelp)
1772 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1776 QString
help, QString longhelp)
1778 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1782 QString
help, QString longhelp)
1784 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1788 QString
help, QString longhelp)
1790 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1794 QString
help, QString longhelp)
1796 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1800 QString
help, QString longhelp)
1802 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1806 QString
help, QString longhelp)
1808 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1812 QString
help, QString longhelp)
1814 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1818 QString
help, QString longhelp)
1820 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1824 QString
help, QString longhelp)
1826 return add(QStringList(arg), name,
type,
1827 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1828 QVariant(
static_cast<QVariant::Type
>(
type)),
1830 QVariant(QMetaType(
type)),
1832 std::move(
help), std::move(longhelp));
1836 QMetaType::Type
type,
1837 QVariant def, QString
help, QString longhelp)
1839 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1843 QString
help, QString longhelp)
1845 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1849 QString
help, QString longhelp)
1851 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1855 QString
help, QString longhelp)
1857 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1861 QString
help, QString longhelp)
1863 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1867 QString
help, QString longhelp)
1869 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1873 QString
help, QString longhelp)
1875 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1879 QString
help, QString longhelp)
1881 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1885 QString
help, QString longhelp)
1887 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1891 QString
help, QString longhelp)
1893 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1897 QMetaType::Type
type,
1898 QString
help, QString longhelp)
1900 return add(std::move(arglist), name,
type,
1901 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1902 QVariant(
static_cast<QVariant::Type
>(
type)),
1904 QVariant(QMetaType(
type)),
1906 std::move(
help), std::move(longhelp));
1915 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1917 QMap<QString,CommandLineArg*>::iterator args_it;
1920 QList<CommandLineArg*> links = (*args_it)->m_parents;
1921 QList<CommandLineArg*>::iterator links_it;
1922 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1924 if ((*links_it)->m_type != QMetaType::UnknownType)
1930 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1931 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1932 <<
"' could not find '"
1933 << (*links_it)->m_name.toLocal8Bit().constData()
1934 <<
"'." << std::endl
1935 <<
" Please resolve dependency and recompile." << std::endl;
1942 std::cerr << QString(
" Setting %1 as child of %2")
1943 .arg((*args_it)->m_name, (*links_it)->m_name)
1944 .toLocal8Bit().constData()
1947 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1950 links = (*args_it)->m_children;
1951 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1953 if ((*links_it)->m_type != QMetaType::UnknownType)
1959 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1960 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1961 <<
"' could not find '"
1962 << (*links_it)->m_name.toLocal8Bit().constData()
1963 <<
"'." << std::endl
1964 <<
" Please resolve dependency and recompile." << std::endl;
1971 std::cerr << QString(
" Setting %1 as parent of %2")
1972 .arg((*args_it)->m_name, (*links_it)->m_name)
1973 .toLocal8Bit().constData()
1976 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1979 links = (*args_it)->m_requires;
1980 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1982 if ((*links_it)->m_type != QMetaType::UnknownType)
1988 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1989 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1990 <<
"' could not find '"
1991 << (*links_it)->m_name.toLocal8Bit().constData()
1992 <<
"'." << std::endl
1993 <<
" Please resolve dependency and recompile." << std::endl;
2000 std::cerr << QString(
" Setting %1 as requiring %2")
2001 .arg((*args_it)->m_name, (*links_it)->m_name)
2002 .toLocal8Bit().constData()
2005 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2008 QList<CommandLineArg*>::iterator req_it =
2009 (*args_it)->m_requiredby.begin();
2010 while (req_it != (*args_it)->m_requiredby.end())
2012 if ((*req_it)->m_type == QMetaType::UnknownType)
2017 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2020 std::cerr << QString(
" Setting %1 as blocking %2")
2021 .arg((*args_it)->m_name,
2023 .toLocal8Bit().constData()
2029 (*req_it)->DecrRef();
2030 req_it = (*args_it)->m_requiredby.erase(req_it);
2033 QList<CommandLineArg*>::iterator block_it =
2034 (*args_it)->m_blocks.begin();
2035 while (block_it != (*args_it)->m_blocks.end())
2037 if ((*block_it)->m_type != QMetaType::UnknownType)
2045 (*block_it)->DecrRef();
2046 block_it = (*args_it)->m_blocks.erase(block_it);
2053 std::cerr << QString(
" Setting %1 as blocking %2")
2054 .arg((*args_it)->m_name, (*block_it)->m_name)
2055 .toLocal8Bit().constData()
2058 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2098 return toMap(
"_extra");
2117 QMap<QString,QString> smap =
toMap(
"overridesettings");
2121 if (
toBool(
"overridesettingsfile"))
2127 if (f.open(QIODevice::ReadOnly))
2130 while (!in.atEnd()) {
2131 QString line = in.readLine().trimmed();
2132 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2133 QStringList tokens = line.split(
"=",
2134 QString::SkipEmptyParts);
2136 QStringList tokens = line.split(
"=",
2137 Qt::SkipEmptyParts);
2139 if (tokens.size() == 2)
2141 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2142 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2143 tokens[0].remove(kQuoteStartRE);
2144 tokens[0].remove(kQuoteEndRE);
2145 tokens[1].remove(kQuoteStartRE);
2146 tokens[1].remove(kQuoteEndRE);
2147 if (!tokens[0].isEmpty())
2148 smap[tokens[0]] = tokens[1];
2155 std::cerr <<
"Failed to open the override settings file: '"
2156 <<
tmp.constData() <<
"'" << std::endl;
2162 smap[
"RunFrontendInWindow"] =
"1";
2163 else if (
toBool(
"notwindowed"))
2164 smap[
"RunFrontendInWindow"] =
"0";
2166 if (
toBool(
"mousecursor"))
2167 smap[
"HideMouseCursor"] =
"0";
2168 else if (
toBool(
"nomousecursor"))
2169 smap[
"HideMouseCursor"] =
"1";
2173 if (!smap.isEmpty())
2176 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2177 vmap[it.key()] = QVariant(it.value());
2179 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2185 std::cerr <<
"Option Overrides:" << std::endl;
2186 QMap<QString, QString>::const_iterator it;
2187 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2188 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2189 .toLocal8Bit().constData() << std::endl;
2210 if (arg->
m_type == QMetaType::Bool)
2235 if (arg->
m_stored.canConvert<
int>())
2289 if (arg->
m_stored.canConvert<
long long>())
2294 if (arg->
m_default.canConvert<
long long>())
2316 if (arg->
m_stored.canConvert<
double>())
2321 if (arg->
m_default.canConvert<
double>())
2343 if (arg->
m_stored.canConvert<QSize>())
2373 if (arg->
m_stored.canConvert<QString>())
2378 if (arg->
m_default.canConvert<QString>())
2410 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2411 val = varval.toString().split(sep);
2412 else if (varval.canConvert<QStringList>())
2413 val = varval.toStringList();
2423 QMap<QString, QString> val;
2424 QMap<QString, QVariant>
tmp;
2437 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2442 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2446 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2447 val[i.key()] = i.value().toString();
2467 if (arg->
m_stored.canConvert<QDateTime>())
2472 if (arg->
m_default.canConvert<QDateTime>())
2492 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2509 QMap<QString,QVariant> vmap;
2510 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2529 QMetaType::QStringList, QStringList());
2537 add(QStringList{
"-h",
"--help",
"--usage"},
2538 "showhelp",
"",
"Display this help printout, or give detailed "
2539 "information of selected option.",
2540 "Displays a list of all commands available for use with "
2541 "this application. If another option is provided as an "
2542 "argument, it will provide detailed information on that "
2550 add(
"--version",
"showversion",
false,
"Display version information.",
2551 "Display informtion about build, including:\n"
2552 " version, branch, protocol, library API, Qt "
2553 "and compiled options.");
2560 add(QStringList{
"-nw",
"--no-windowed"},
2561 "notwindowed",
false,
2562 "Prevent application from running in a window.",
"")
2563 ->SetBlocks(
"windowed")
2566 add(QStringList{
"-w",
"--windowed"},
"windowed",
2567 false,
"Force application to run in a window.",
"")
2568 ->SetGroup(
"User Interface");
2575 add(
"--mouse-cursor",
"mousecursor",
false,
2576 "Force visibility of the mouse cursor.",
"")
2580 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2581 "Force the mouse cursor to be hidden.",
"")
2589 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2590 "Fork application into background after startup.",
2591 "Fork application into background, detatching from "
2592 "the local terminal.\nOften used with: "
2593 " --logpath --pidfile --user");
2601 add(QStringList{
"-O",
"--override-setting"},
2602 "overridesettings", QMetaType::QVariantMap,
2603 "Override a single setting defined by a key=value pair.",
2604 "Override a single setting from the database using "
2605 "options defined as one or more key=value pairs\n"
2606 "Multiple can be defined by multiple uses of the "
2608 add(
"--override-settings-file",
"overridesettingsfile",
"",
2609 "Define a file of key=value pairs to be "
2610 "loaded for setting overrides.",
"");
2617 add(
"--chanid",
"chanid", 0U,
2618 "Specify chanid of recording to operate on.",
"")
2621 add(
"--starttime",
"starttime", QDateTime(),
2622 "Specify start time of recording to operate on.",
"")
2630 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2631 "",
"Specify window size and position (WxH[+X+Y])",
"")
2632 ->SetGroup(
"User Interface");
2639 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2646 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2653 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2656 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2657 LOG_INFO : defaultLogLevel;
2661 add(QStringList{
"-v",
"--verbose"},
"verbose",
2663 "Specify log filtering. Use '-v help' for level info.",
"")
2664 ->SetGroup(
"Logging");
2665 add(
"-V",
"verboseint", 0LL,
"",
2666 "This option is intended for internal use only.\n"
2667 "This option takes an unsigned value corresponding "
2668 "to the bitwise log verbosity operator.")
2670 add(
"--logpath",
"logpath",
"",
2671 "Writes logging messages to a file in the directory logpath with "
2672 "filenames in the format: applicationName.date.pid.log.\n"
2673 "This is typically used in combination with --daemon, and if used "
2674 "in combination with --pidfile, this can be used with log "
2675 "rotators, using the HUP call to inform MythTV to reload the "
2678 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2679 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2680 ->SetGroup(
"Logging");
2681 add(
"--loglevel",
"loglevel", logLevelStr,
2683 "Set the logging level. All log messages at lower levels will be "
2685 "In descending order: emerg, alert, crit, err, warning, notice, "
2686 "info, debug\ndefaults to ") + logLevelStr,
"")
2688 add(
"--syslog",
"syslog",
"none",
2689 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2690 "defaults to none.",
"")
2692 #if CONFIG_SYSTEMD_JOURNAL
2693 add(
"--systemd-journal",
"systemd-journal",
"false",
2694 "Use systemd-journal instead of syslog.",
"")
2700 add(
"--nodblog",
"nodblog",
false,
"",
"")
2702 ->
SetRemoved(
"Database logging has been removed.",
"34");
2703 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2705 ->
SetRemoved(
"Database logging has been removed.",
"34");
2707 add(QStringList{
"-l",
"--logfile"},
2708 "logfile",
"",
"",
"")
2709 ->SetGroup(
"Logging")
2710 ->
SetRemoved(
"This option has been removed as part of "
2711 "rewrite of the logging interface. Please update your init "
2712 "scripts to use --syslog to interface with your system's "
2713 "existing system logging daemon, or --logpath to specify a "
2714 "dirctory for MythTV to write its logs to.",
"0.25");
2721 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2722 "Write PID of application to filename.",
2723 "Write the PID of the currently running process as a single "
2724 "line to this file. Used for init scripts to know what "
2725 "process to terminate, and with log rotators "
2726 "to send a HUP signal to process to have it re-open files.");
2733 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2734 "Intended for internal use only, specify the JobID to match "
2735 "up with in the database for additional information and the "
2736 "ability to update runtime status in the database.");
2743 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2745 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2753 add(QStringList{
"-display",
"--display"},
"display",
"",
2754 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2763 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2764 "Qt platform argument that is passed through to Qt")
2773 pid_t pid = getpid();
2781 LOG(VB_GENERAL, LOG_ERR,
2782 QString(
"%1 is not a directory, disabling logfiles")
2787 QString logdir = finfo.filePath();
2788 logfile = QCoreApplication::applicationName() +
"." +
2790 QString(
".%1").arg(pid) +
".log";
2803 QString setting =
toString(
"syslog").toLower();
2804 if (setting ==
"none")
2814 QString setting =
toString(
"loglevel");
2815 if (setting.isEmpty())
2819 if (level == LOG_UNKNOWN)
2820 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2836 const QVariant& val(value);
2837 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2838 auto type =
static_cast<QMetaType::Type
>(val.type());
2840 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2848 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2849 auto type =
static_cast<QMetaType::Type
>(value.type());
2851 auto type = value.typeId();
2877 else if (
toBool(
"verboseint"))
2890 #if CONFIG_SYSTEMD_JOURNAL
2891 bool journal =
toBool(
"systemd-journal");
2896 facility = SYSTEMD_JOURNAL_FACILITY;
2900 if (level == LOG_UNKNOWN)
2903 LOG(VB_GENERAL, LOG_CRIT,
2904 QString(
"%1 version: %2 [%3] www.mythtv.org")
2905 .arg(QCoreApplication::applicationName(),
2907 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2908 .arg(QT_VERSION_STR, qVersion()));
2909 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2910 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2911 LOG(VB_GENERAL, LOG_NOTICE,
2915 bool propagate = !
logfile.isEmpty();
2921 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2922 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2934 std::cerr <<
"Applying settings override" << std::endl;
2937 if (!
override.empty())
2939 QMap<QString, QString>::iterator it;
2940 for (it =
override.begin(); it !=
override.end(); ++it)
2942 LOG(VB_GENERAL, LOG_NOTICE,
2943 QString(
"Setting '%1' being forced to '%2'")
2944 .arg(it.key(), *it));
2954 pidfs.open(
pidfile.toLatin1().constData());
2957 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2968 if (username.isEmpty())
2972 std::cerr <<
"--user option is not supported on Windows" << std::endl;
2975 #if defined(__linux__) || defined(__LINUX__)
2978 int dumpability = prctl(PR_GET_DUMPABLE);
2980 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
2981 const uid_t user_id =
geteuid();
2985 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
2990 LOG(VB_GENERAL, LOG_WARNING,
2991 QString(
"Already running as '%1'").arg(username));
2997 std::cerr <<
"Error setting home directory." << std::endl;
3002 std::cerr <<
"Error setting effective group." << std::endl;
3007 std::cerr <<
"Error setting groups." << std::endl;
3012 std::cerr <<
"Error setting effective user." << std::endl;
3015 #if defined(__linux__) || defined(__LINUX__)
3016 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3018 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3019 "creation. Run without the --user argument to use "
3020 "shell-specified limits.");
3026 std::cerr << QString(
"Invalid user '%1' specified with --user")
3027 .arg(username).toLocal8Bit().constData() << std::endl;
3039 std::ofstream pidfs;
3043 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3044 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3049 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
3050 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3055 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
3060 QString username =
toString(
"username");
3061 if (!username.isEmpty() && !
setUser(username))
3066 pidfs << getpid() << std::endl;