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');
418 << hlist.takeFirst() <<
QT_ENDL;
421 for (
const auto & line : qAsConst(hlist))
426 msg << arg->GetHelpString(off, group,
true);
442 QTextStream msg(&helpstr, QIODevice::WriteOnly);
465 for (
const auto & word : qAsConst(
m_keywords))
471 msg <<
"Aliases: " << word <<
QT_ENDL;
480 #if QT_VERSION < QT_VERSION_CHECK(5,15,0)
496 msg <<
"Description: " <<
help.takeFirst() <<
QT_ENDL;
497 for (
const auto & line : qAsConst(
help))
500 QList<CommandLineArg*>::const_iterator i2;
506 for (
auto * parent : qAsConst(
m_parents))
507 msg <<
" " << parent->GetPreferredKeyword()
508 .toLocal8Bit().constData();
516 msg <<
" " << (*i2)->GetPreferredKeyword()
517 .toLocal8Bit().constData();
525 msg <<
" " << (*i2)->GetPreferredKeyword()
526 .toLocal8Bit().constData();
534 msg <<
" " << (*i2)->GetPreferredKeyword()
535 .toLocal8Bit().constData();
555 case QMetaType::Bool:
566 case QMetaType::QString:
571 std::cerr <<
"Command line option did not receive value:" << std::endl
572 <<
" " << opt.toLocal8Bit().constData() << std::endl;
585 QList<QByteArray> blist;
591 case QMetaType::Bool:
592 std::cerr <<
"Boolean type options do not accept values:" << std::endl
593 <<
" " << opt.toLocal8Bit().constData() << std::endl;
596 case QMetaType::QString:
604 case QMetaType::UInt:
608 case QMetaType::LongLong:
609 m_stored = QVariant(val.toLongLong());
612 case QMetaType::Double:
613 m_stored = QVariant(val.toDouble());
616 case QMetaType::QDateTime:
620 case QMetaType::QStringList:
627 case QMetaType::QVariantMap:
628 if (!val.contains(
'='))
630 std::cerr <<
"Command line option did not get expected "
631 <<
"key/value pair" << std::endl;
635 blist = val.split(
'=');
643 case QMetaType::QSize:
644 if (!val.contains(
'x'))
646 std::cerr <<
"Command line option did not get expected "
647 <<
"XxY pair" << std::endl;
651 blist = val.split(
'x');
652 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
675 for (
const auto& opt : qAsConst(
opts))
692 for (
const auto& opt : qAsConst(
opts))
709 for (
const auto& opt : qAsConst(
opts))
726 for (
const auto& opt : qAsConst(
opts))
744 for (
const auto& opt : qAsConst(
opts))
765 for (
const auto& opt : qAsConst(
opts))
785 for (
const auto& opt : qAsConst(
opts))
802 for (
const auto& opt : qAsConst(
opts))
811 if (depstr.isEmpty())
812 depstr =
"and will be removed in a future version.";
821 if (remstr.isEmpty())
822 remstr =
"and is no longer available in this version.";
835 bool replaced =
false;
863 bool replaced =
false;
866 for (
int i = 0; i <
m_parents.size(); i++)
891 bool replaced =
false;
920 bool replaced =
false;
923 for (
int i = 0; i <
m_blocks.size(); i++)
951 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
955 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
957 (*i1)->SetBlocks(*i2);
960 if ((*i1)->m_type == QMetaType::UnknownType)
973 if (!QCoreApplication::instance())
988 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
989 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
991 auto storedType =
m_stored.typeId();
993 if (
m_type == QMetaType::QString)
995 if (storedType == QMetaType::QByteArray)
1003 else if (
m_type == QMetaType::QStringList)
1005 if (storedType == QMetaType::QVariantList)
1007 QVariantList vlist =
m_stored.toList();
1009 for (
const auto& item : qAsConst(vlist))
1010 slist << QString::fromLocal8Bit(item.toByteArray());
1014 else if (
m_type == QMetaType::QVariantMap)
1016 QVariantMap vmap =
m_stored.toMap();
1018 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1019 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1035 QStringList::const_iterator it;
1041 int len2 = (*it).size();
1060 QList<CommandLineArg*>::const_iterator i;
1062 bool passes =
false;
1074 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1075 <<
" requires at least one of the following arguments" << std::endl;
1078 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1079 std::cerr << std::endl << std::endl;
1090 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1091 <<
" requires all of the following be defined as well"
1096 << (*i)->GetPreferredKeyword().toLocal8Bit()
1099 std::cerr << std::endl << std::endl;
1109 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1110 <<
" requires that none of the following be defined" << std::endl;
1114 << (*i)->GetPreferredKeyword().toLocal8Bit()
1117 std::cerr << std::endl << std::endl;
1153 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1156 QMap<QString, QVariant> tmpmap;
1157 QMap<QString, QVariant>::const_iterator it;
1163 case QMetaType::Bool:
1164 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1167 case QMetaType::Int:
1168 std::cerr <<
m_stored.toInt() << std::endl;
1171 case QMetaType::UInt:
1172 std::cerr <<
m_stored.toUInt() << std::endl;
1175 case QMetaType::LongLong:
1176 std::cerr <<
m_stored.toLongLong() << std::endl;
1179 case QMetaType::Double:
1180 std::cerr <<
m_stored.toDouble() << std::endl;
1183 case QMetaType::QSize:
1185 std::cerr <<
"x=" << tmpsize.width()
1186 <<
" y=" << tmpsize.height()
1190 case QMetaType::QString:
1191 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1192 <<
'"' << std::endl;
1195 case QMetaType::QStringList:
1197 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1198 for (
const auto& str : qAsConst(vlist))
1204 std::cerr << std::endl;
1207 case QMetaType::QVariantMap:
1209 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1214 std::cerr << QString(
"").leftJustified(32)
1215 .toLocal8Bit().constData();
1217 std::cerr << it.key().toLocal8Bit().constData()
1219 << it->toByteArray().constData()
1225 case QMetaType::QDateTime:
1227 .toLocal8Bit().constData()
1232 std::cerr << std::endl;
1240 QString warn = QString(
"%1 has been removed").arg(keyword);
1244 std::cerr << QString(
"****************************************************\n"
1247 "****************************************************\n\n")
1249 .toLocal8Bit().constData();
1256 std::cerr << QString(
"****************************************************\n"
1257 " WARNING: %1 has been deprecated\n"
1259 "****************************************************\n\n")
1261 .toLocal8Bit().constData();
1278 : m_appname(
std::move(appname))
1280 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1282 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1291 QMap<QString, CommandLineArg*>::iterator i;
1296 (*i)->CleanupLinks();
1343 const QString& name, QMetaType::Type
type, QVariant def,
1344 QString
help, QString longhelp)
1356 for (
const auto & str : qAsConst(arglist))
1363 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1364 <<
" as taking type '"
1365 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1366 << QVariant::typeToName(
static_cast<int>(
type))
1368 << QMetaType(
type).name()
1370 <<
"'" << std::endl;
1384 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1387 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1388 std::cout <<
"Library API : " << MYTH_BINARY_VERSION << std::endl;
1389 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1390 #ifdef MYTH_BUILD_CONFIG
1391 std::cout <<
"Options compiled in:" <<std::endl;
1392 std::cout << MYTH_BUILD_CONFIG << std::endl;
1401 std::cerr <<
help.toLocal8Bit().constData();
1412 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1414 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1418 if (
toString(
"showhelp").isEmpty())
1423 if (descr.size() > 0)
1427 QStringList groups(
"");
1431 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1432 if (!groups.contains(cmdarg->m_group))
1433 groups << cmdarg->m_group;
1439 for (
const auto & group : qAsConst(groups))
1441 if (group.isEmpty())
1444 msg << group.toLocal8Bit().constData() <<
" Options:" <<
QT_ENDL <<
QT_ENDL;
1447 msg << cmdarg->GetHelpString(maxlen, group);
1454 QString optstr =
"-" +
toString(
"showhelp");
1457 optstr =
"-" + optstr;
1459 return QString(
"Could not find option matching '%1'\n")
1474 int &argpos, QString &opt, QByteArray &val)
1483 QByteArray
tmp(argv[argpos]);
1495 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1504 if (
tmp.contains(
'='))
1507 QList<QByteArray> blist =
tmp.split(
'=');
1509 if (blist.size() != 2)
1523 if (argpos+1 >= argc)
1527 tmp = QByteArray(argv[++argpos]);
1532 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1566 for (
int argpos = 1; argpos < argc; ++argpos)
1570 res =
getOpt(argc, argv, argpos, opt, val);
1575 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1576 <<
"val: " << val.constData() << std::endl << std::endl;
1582 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1599 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1600 << opt.toLocal8Bit().constData();
1617 std::cerr <<
"Received '"
1619 <<
"' but unassociated arguments have not been enabled"
1632 std::cerr <<
"Command line arguments received out of sequence"
1639 if (opt.startsWith(
"-psn_"))
1641 std::cerr <<
"Ignoring Process Serial Number from command line"
1654 QByteArray
tmp = opt.toLocal8Bit();
1663 std::cerr <<
"Unhandled option given on command line:" << std::endl
1664 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1685 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1691 if (!argdef->
Set(opt))
1700 if (!argdef->
Set(opt, val))
1721 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1727 std::cerr <<
"Processed option list:" << std::endl;
1729 cmdarg->PrintVerbose();
1733 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1735 for (
const auto& lopt : qAsConst(slist))
1736 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1741 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1742 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1745 std::cerr << std::endl;
1751 if (!cmdarg->TestLinks())
1753 QString keyword = cmdarg->m_usedKeyword;
1754 if (keyword.startsWith(
'-'))
1756 if (keyword.startsWith(
"--"))
1757 keyword.remove(0,2);
1759 keyword.remove(0,1);
1771 QString
help, QString longhelp)
1773 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1777 QString
help, QString longhelp)
1779 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1783 QString
help, QString longhelp)
1785 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1789 QString
help, QString longhelp)
1791 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1795 QString
help, QString longhelp)
1797 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1801 QString
help, QString longhelp)
1803 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1807 QString
help, QString longhelp)
1809 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1813 QString
help, QString longhelp)
1815 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1819 QString
help, QString longhelp)
1821 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1825 QString
help, QString longhelp)
1827 return add(QStringList(arg), name,
type,
1828 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1829 QVariant(
static_cast<QVariant::Type
>(
type)),
1831 QVariant(QMetaType(
type)),
1833 std::move(
help), std::move(longhelp));
1837 QMetaType::Type
type,
1838 QVariant def, QString
help, QString longhelp)
1840 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1844 QString
help, QString longhelp)
1846 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1850 QString
help, QString longhelp)
1852 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1856 QString
help, QString longhelp)
1858 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1862 QString
help, QString longhelp)
1864 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1868 QString
help, QString longhelp)
1870 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1874 QString
help, QString longhelp)
1876 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1880 QString
help, QString longhelp)
1882 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1886 QString
help, QString longhelp)
1888 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1892 QString
help, QString longhelp)
1894 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1898 QMetaType::Type
type,
1899 QString
help, QString longhelp)
1901 return add(std::move(arglist), name,
type,
1902 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1903 QVariant(
static_cast<QVariant::Type
>(
type)),
1905 QVariant(QMetaType(
type)),
1907 std::move(
help), std::move(longhelp));
1916 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1918 QMap<QString,CommandLineArg*>::iterator args_it;
1921 QList<CommandLineArg*> links = (*args_it)->m_parents;
1922 QList<CommandLineArg*>::iterator links_it;
1923 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1925 if ((*links_it)->m_type != QMetaType::UnknownType)
1931 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1932 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1933 <<
"' could not find '"
1934 << (*links_it)->m_name.toLocal8Bit().constData()
1935 <<
"'." << std::endl
1936 <<
" Please resolve dependency and recompile." << std::endl;
1943 std::cerr << QString(
" Setting %1 as child of %2")
1944 .arg((*args_it)->m_name, (*links_it)->m_name)
1945 .toLocal8Bit().constData()
1948 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1951 links = (*args_it)->m_children;
1952 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1954 if ((*links_it)->m_type != QMetaType::UnknownType)
1960 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1961 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1962 <<
"' could not find '"
1963 << (*links_it)->m_name.toLocal8Bit().constData()
1964 <<
"'." << std::endl
1965 <<
" Please resolve dependency and recompile." << std::endl;
1972 std::cerr << QString(
" Setting %1 as parent of %2")
1973 .arg((*args_it)->m_name, (*links_it)->m_name)
1974 .toLocal8Bit().constData()
1977 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1980 links = (*args_it)->m_requires;
1981 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1983 if ((*links_it)->m_type != QMetaType::UnknownType)
1989 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1990 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1991 <<
"' could not find '"
1992 << (*links_it)->m_name.toLocal8Bit().constData()
1993 <<
"'." << std::endl
1994 <<
" Please resolve dependency and recompile." << std::endl;
2001 std::cerr << QString(
" Setting %1 as requiring %2")
2002 .arg((*args_it)->m_name, (*links_it)->m_name)
2003 .toLocal8Bit().constData()
2006 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2009 QList<CommandLineArg*>::iterator req_it =
2010 (*args_it)->m_requiredby.begin();
2011 while (req_it != (*args_it)->m_requiredby.end())
2013 if ((*req_it)->m_type == QMetaType::UnknownType)
2018 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2021 std::cerr << QString(
" Setting %1 as blocking %2")
2022 .arg((*args_it)->m_name,
2024 .toLocal8Bit().constData()
2030 (*req_it)->DecrRef();
2031 req_it = (*args_it)->m_requiredby.erase(req_it);
2034 QList<CommandLineArg*>::iterator block_it =
2035 (*args_it)->m_blocks.begin();
2036 while (block_it != (*args_it)->m_blocks.end())
2038 if ((*block_it)->m_type != QMetaType::UnknownType)
2046 (*block_it)->DecrRef();
2047 block_it = (*args_it)->m_blocks.erase(block_it);
2054 std::cerr << QString(
" Setting %1 as blocking %2")
2055 .arg((*args_it)->m_name, (*block_it)->m_name)
2056 .toLocal8Bit().constData()
2059 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2099 return toMap(
"_extra");
2118 QMap<QString,QString> smap =
toMap(
"overridesettings");
2122 if (
toBool(
"overridesettingsfile"))
2128 if (f.open(QIODevice::ReadOnly))
2131 while (!in.atEnd()) {
2132 QString line = in.readLine().trimmed();
2133 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
2134 QStringList tokens = line.split(
"=",
2135 QString::SkipEmptyParts);
2137 QStringList tokens = line.split(
"=",
2138 Qt::SkipEmptyParts);
2140 if (tokens.size() == 2)
2142 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2143 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2144 tokens[0].remove(kQuoteStartRE);
2145 tokens[0].remove(kQuoteEndRE);
2146 tokens[1].remove(kQuoteStartRE);
2147 tokens[1].remove(kQuoteEndRE);
2148 if (!tokens[0].isEmpty())
2149 smap[tokens[0]] = tokens[1];
2156 std::cerr <<
"Failed to open the override settings file: '"
2157 <<
tmp.constData() <<
"'" << std::endl;
2163 smap[
"RunFrontendInWindow"] =
"1";
2164 else if (
toBool(
"notwindowed"))
2165 smap[
"RunFrontendInWindow"] =
"0";
2167 if (
toBool(
"mousecursor"))
2168 smap[
"HideMouseCursor"] =
"0";
2169 else if (
toBool(
"nomousecursor"))
2170 smap[
"HideMouseCursor"] =
"1";
2174 if (!smap.isEmpty())
2177 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2178 vmap[it.key()] = QVariant(it.value());
2180 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2186 std::cerr <<
"Option Overrides:" << std::endl;
2187 QMap<QString, QString>::const_iterator it;
2188 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2189 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2190 .toLocal8Bit().constData() << std::endl;
2211 if (arg->
m_type == QMetaType::Bool)
2236 if (arg->
m_stored.canConvert<
int>())
2290 if (arg->
m_stored.canConvert<
long long>())
2295 if (arg->
m_default.canConvert<
long long>())
2317 if (arg->
m_stored.canConvert<
double>())
2322 if (arg->
m_default.canConvert<
double>())
2344 if (arg->
m_stored.canConvert<QSize>())
2374 if (arg->
m_stored.canConvert<QString>())
2379 if (arg->
m_default.canConvert<QString>())
2411 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2412 val = varval.toString().split(sep);
2413 else if (varval.canConvert<QStringList>())
2414 val = varval.toStringList();
2424 QMap<QString, QString> val;
2425 QMap<QString, QVariant>
tmp;
2438 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2443 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2447 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2448 val[i.key()] = i.value().toString();
2468 if (arg->
m_stored.canConvert<QDateTime>())
2473 if (arg->
m_default.canConvert<QDateTime>())
2493 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2510 QMap<QString,QVariant> vmap;
2511 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2530 QMetaType::QStringList, QStringList());
2538 add(QStringList{
"-h",
"--help",
"--usage"},
2539 "showhelp",
"",
"Display this help printout, or give detailed "
2540 "information of selected option.",
2541 "Displays a list of all commands available for use with "
2542 "this application. If another option is provided as an "
2543 "argument, it will provide detailed information on that "
2551 add(
"--version",
"showversion",
false,
"Display version information.",
2552 "Display informtion about build, including:\n"
2553 " version, branch, protocol, library API, Qt "
2554 "and compiled options.");
2561 add(QStringList{
"-nw",
"--no-windowed"},
2562 "notwindowed",
false,
2563 "Prevent application from running in a window.",
"")
2564 ->SetBlocks(
"windowed")
2567 add(QStringList{
"-w",
"--windowed"},
"windowed",
2568 false,
"Force application to run in a window.",
"")
2569 ->SetGroup(
"User Interface");
2576 add(
"--mouse-cursor",
"mousecursor",
false,
2577 "Force visibility of the mouse cursor.",
"")
2581 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2582 "Force the mouse cursor to be hidden.",
"")
2590 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2591 "Fork application into background after startup.",
2592 "Fork application into background, detatching from "
2593 "the local terminal.\nOften used with: "
2594 " --logpath --pidfile --user");
2602 add(QStringList{
"-O",
"--override-setting"},
2603 "overridesettings", QMetaType::QVariantMap,
2604 "Override a single setting defined by a key=value pair.",
2605 "Override a single setting from the database using "
2606 "options defined as one or more key=value pairs\n"
2607 "Multiple can be defined by multiple uses of the "
2609 add(
"--override-settings-file",
"overridesettingsfile",
"",
2610 "Define a file of key=value pairs to be "
2611 "loaded for setting overrides.",
"");
2618 add(
"--chanid",
"chanid", 0U,
2619 "Specify chanid of recording to operate on.",
"")
2622 add(
"--starttime",
"starttime", QDateTime(),
2623 "Specify start time of recording to operate on.",
"")
2631 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2632 "",
"Specify window size and position (WxH[+X+Y])",
"")
2633 ->SetGroup(
"User Interface");
2640 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2647 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2654 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2657 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2658 LOG_INFO : defaultLogLevel;
2662 add(QStringList{
"-v",
"--verbose"},
"verbose",
2664 "Specify log filtering. Use '-v help' for level info.",
"")
2665 ->SetGroup(
"Logging");
2666 add(
"-V",
"verboseint", 0LL,
"",
2667 "This option is intended for internal use only.\n"
2668 "This option takes an unsigned value corresponding "
2669 "to the bitwise log verbosity operator.")
2671 add(
"--logpath",
"logpath",
"",
2672 "Writes logging messages to a file in the directory logpath with "
2673 "filenames in the format: applicationName.date.pid.log.\n"
2674 "This is typically used in combination with --daemon, and if used "
2675 "in combination with --pidfile, this can be used with log "
2676 "rotators, using the HUP call to inform MythTV to reload the "
2679 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2680 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2681 ->SetGroup(
"Logging");
2682 add(
"--loglevel",
"loglevel", logLevelStr,
2684 "Set the logging level. All log messages at lower levels will be "
2686 "In descending order: emerg, alert, crit, err, warning, notice, "
2687 "info, debug\ndefaults to ") + logLevelStr,
"")
2689 add(
"--syslog",
"syslog",
"none",
2690 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2691 "defaults to none.",
"")
2693 #if CONFIG_SYSTEMD_JOURNAL
2694 add(
"--systemd-journal",
"systemd-journal",
"false",
2695 "Use systemd-journal instead of syslog.",
"")
2701 add(
"--nodblog",
"nodblog",
false,
"",
"")
2703 ->
SetRemoved(
"Database logging has been removed.",
"34");
2704 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2706 ->
SetRemoved(
"Database logging has been removed.",
"34");
2708 add(QStringList{
"-l",
"--logfile"},
2709 "logfile",
"",
"",
"")
2710 ->SetGroup(
"Logging")
2711 ->
SetRemoved(
"This option has been removed as part of "
2712 "rewrite of the logging interface. Please update your init "
2713 "scripts to use --syslog to interface with your system's "
2714 "existing system logging daemon, or --logpath to specify a "
2715 "dirctory for MythTV to write its logs to.",
"0.25");
2722 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2723 "Write PID of application to filename.",
2724 "Write the PID of the currently running process as a single "
2725 "line to this file. Used for init scripts to know what "
2726 "process to terminate, and with log rotators "
2727 "to send a HUP signal to process to have it re-open files.");
2734 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2735 "Intended for internal use only, specify the JobID to match "
2736 "up with in the database for additional information and the "
2737 "ability to update runtime status in the database.");
2744 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2746 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2754 add(QStringList{
"-display",
"--display"},
"display",
"",
2755 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2764 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2765 "Qt platform argument that is passed through to Qt")
2774 pid_t pid = getpid();
2782 LOG(VB_GENERAL, LOG_ERR,
2783 QString(
"%1 is not a directory, disabling logfiles")
2788 QString logdir = finfo.filePath();
2789 logfile = QCoreApplication::applicationName() +
"." +
2791 QString(
".%1").arg(pid) +
".log";
2804 QString setting =
toString(
"syslog").toLower();
2805 if (setting ==
"none")
2815 QString setting =
toString(
"loglevel");
2816 if (setting.isEmpty())
2820 if (level == LOG_UNKNOWN)
2821 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2837 const QVariant& val(value);
2838 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2839 auto type =
static_cast<QMetaType::Type
>(val.type());
2841 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2849 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2850 auto type =
static_cast<QMetaType::Type
>(value.type());
2852 auto type = value.typeId();
2878 else if (
toBool(
"verboseint"))
2891 #if CONFIG_SYSTEMD_JOURNAL
2892 bool journal =
toBool(
"systemd-journal");
2897 facility = SYSTEMD_JOURNAL_FACILITY;
2901 if (level == LOG_UNKNOWN)
2904 LOG(VB_GENERAL, LOG_CRIT,
2905 QString(
"%1 version: %2 [%3] www.mythtv.org")
2906 .arg(QCoreApplication::applicationName(),
2908 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2909 .arg(QT_VERSION_STR, qVersion()));
2910 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2911 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2912 LOG(VB_GENERAL, LOG_NOTICE,
2916 bool propagate = !
logfile.isEmpty();
2922 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2923 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2935 std::cerr <<
"Applying settings override" << std::endl;
2938 if (!
override.empty())
2940 QMap<QString, QString>::iterator it;
2941 for (it =
override.begin(); it !=
override.end(); ++it)
2943 LOG(VB_GENERAL, LOG_NOTICE,
2944 QString(
"Setting '%1' being forced to '%2'")
2945 .arg(it.key(), *it));
2955 pidfs.open(
pidfile.toLatin1().constData());
2958 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2969 if (username.isEmpty())
2973 std::cerr <<
"--user option is not supported on Windows" << std::endl;
2976 #if defined(__linux__) || defined(__LINUX__)
2979 int dumpability = prctl(PR_GET_DUMPABLE);
2981 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
2982 const uid_t user_id =
geteuid();
2986 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
2991 LOG(VB_GENERAL, LOG_WARNING,
2992 QString(
"Already running as '%1'").arg(username));
2998 std::cerr <<
"Error setting home directory." << std::endl;
3003 std::cerr <<
"Error setting effective group." << std::endl;
3008 std::cerr <<
"Error setting groups." << std::endl;
3013 std::cerr <<
"Error setting effective user." << std::endl;
3016 #if defined(__linux__) || defined(__LINUX__)
3017 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3019 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3020 "creation. Run without the --user argument to use "
3021 "shell-specified limits.");
3027 std::cerr << QString(
"Invalid user '%1' specified with --user")
3028 .arg(username).toLocal8Bit().constData() << std::endl;
3040 std::ofstream pidfs;
3044 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3045 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3050 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
3051 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3056 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
3061 QString username =
toString(
"username");
3062 if (!username.isEmpty() && !
setUser(username))
3067 pidfs << getpid() << std::endl;