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>
69 #include "mythconfig.h"
71 #include "mythversion.h"
83 #if defined(_WIN32) || defined(Q_OS_ANDROID)
88 if (ioctl(0, TIOCGWINSZ, &ws) != 0)
91 return static_cast<int>(ws.ws_col);
97 return ((array.startsWith(
'"') && array.endsWith(
'"') ) ||
98 (array.startsWith(
'\'') && array.endsWith(
'\''))
99 ) ? array.mid(1, array.size() - 2) : array;
106 width = std::max(width, 5);
108 for (
int i = 0; i < list.size(); i++)
110 QString
string = list.at(i);
112 if(
string.size() <= width )
115 QString left =
string.left(width);
116 bool inserted =
false;
118 while( !inserted && !left.endsWith(
" " ))
120 if(
string.mid(left.size(), 1) ==
" " )
122 list.replace(i, left);
123 list.insert(i+1,
string.mid(left.size()).trimmed());
129 if( !left.contains(
" ") )
132 list.replace(i, left +
"-");
133 list.insert(i+1,
string.mid(left.size()));
142 list.replace(i, left);
143 list.insert(i+1,
string.mid(left.size()).trimmed());
158 enum states : std::uint8_t {
167 states state =
START;
170 for (
int i = 0; i < line.size(); i++)
172 const QChar c = line.at(i);
177 if (c.isSpace())
break;
178 if (c ==
'\'') state = INSQUOTE;
179 else if (c ==
'\"') state = INDQUOTE;
180 else if (c ==
'\\') state = ESCTEXT;
185 fields += line.mid(tokenStart, i - tokenStart);
189 else if (c ==
'\'') {
191 }
else if (c ==
'\"') {
193 }
else if (c ==
'\\') {
198 if (c ==
'\'') state = INTEXT;
199 else if (c ==
'\\') state = ESCSQUOTE;
202 if (c ==
'\"') state = INTEXT;
203 else if (c ==
'\\') state = ESCDQUOTE;
205 case ESCTEXT: state = INTEXT;
break;
206 case ESCSQUOTE: state = INSQUOTE;
break;
207 case ESCDQUOTE: state = INDQUOTE;
break;
212 fields += line.mid(tokenStart);
236 return "kCombOptVal";
242 return "kPassthrough";
285 QVariant def, QString
help, QString longhelp) :
287 m_name(name), m_type(
type), m_default(std::move(def)),
288 m_help(std::move(
help)), m_longhelp(std::move(longhelp))
290 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
291 (
m_type != QMetaType::QVariantMap))
303 m_name(name), m_type(
type), m_default(std::move(def))
305 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
306 (
m_type != QMetaType::QVariantMap))
340 QList<CommandLineArg*>::const_iterator i1;
342 len = std::max(len, (*i1)->GetKeywordLength()+2);
365 QTextStream msg(&helpstr, QIODevice::WriteOnly);
410 QStringList hlist =
m_help.split(
'\n');
416 << hlist.takeFirst() << Qt::endl;
419 for (
const auto & line : std::as_const(hlist))
420 msg << pad << line << Qt::endl;
424 msg << arg->GetHelpString(off, group,
true);
440 QTextStream msg(&helpstr, QIODevice::WriteOnly);
458 msg <<
"Option: " << keyword << Qt::endl << Qt::endl;
463 for (
const auto & word : std::as_const(
m_keywords))
469 msg <<
"Aliases: " << word << Qt::endl;
474 msg <<
" " << word << Qt::endl;
480 msg <<
"Type: " << QMetaType(
m_type).name() << Qt::endl;
482 msg <<
"Default: " <<
m_default.toString() << Qt::endl;
492 msg <<
"Description: " <<
help.takeFirst() << Qt::endl;
493 for (
const auto & line : std::as_const(
help))
494 msg <<
" " << line << Qt::endl;
496 QList<CommandLineArg*>::const_iterator i2;
501 msg << Qt::endl <<
"Can be used in combination with:" << Qt::endl;
502 for (
auto * parent : std::as_const(
m_parents))
503 msg <<
" " << parent->GetPreferredKeyword()
504 .toLocal8Bit().constData();
510 msg << Qt::endl <<
"Allows the use of:" << Qt::endl;
512 msg <<
" " << (*i2)->GetPreferredKeyword()
513 .toLocal8Bit().constData();
519 msg << Qt::endl <<
"Requires the use of:" << Qt::endl;
521 msg <<
" " << (*i2)->GetPreferredKeyword()
522 .toLocal8Bit().constData();
528 msg << Qt::endl <<
"Prevents the use of:" << Qt::endl;
530 msg <<
" " << (*i2)->GetPreferredKeyword()
531 .toLocal8Bit().constData();
551 case QMetaType::Bool:
562 case QMetaType::QString:
567 std::cerr <<
"Command line option did not receive value:" << std::endl
568 <<
" " << opt.toLocal8Bit().constData() << std::endl;
581 QList<QByteArray> blist;
587 case QMetaType::Bool:
588 std::cerr <<
"Boolean type options do not accept values:" << std::endl
589 <<
" " << opt.toLocal8Bit().constData() << std::endl;
592 case QMetaType::QString:
600 case QMetaType::UInt:
604 case QMetaType::LongLong:
605 m_stored = QVariant(val.toLongLong());
608 case QMetaType::Double:
609 m_stored = QVariant(val.toDouble());
612 case QMetaType::QDateTime:
616 case QMetaType::QStringList:
623 case QMetaType::QVariantMap:
624 if (!val.contains(
'='))
626 std::cerr <<
"Command line option did not get expected "
627 <<
"key/value pair" << std::endl;
631 blist = val.split(
'=');
639 case QMetaType::QSize:
640 if (!val.contains(
'x'))
642 std::cerr <<
"Command line option did not get expected "
643 <<
"XxY pair" << std::endl;
647 blist = val.split(
'x');
648 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
671 for (
const auto& opt : std::as_const(
opts))
688 for (
const auto& opt : std::as_const(
opts))
705 for (
const auto& opt : std::as_const(
opts))
722 for (
const auto& opt : std::as_const(
opts))
740 for (
const auto& opt : std::as_const(
opts))
761 for (
const auto& opt : std::as_const(
opts))
781 for (
const auto& opt : std::as_const(
opts))
798 for (
const auto& opt : std::as_const(
opts))
807 if (depstr.isEmpty())
808 depstr =
"and will be removed in a future version.";
817 if (remstr.isEmpty())
818 remstr =
"and is no longer available in this version.";
831 bool replaced =
false;
859 bool replaced =
false;
862 for (
int i = 0; i <
m_parents.size(); i++)
887 bool replaced =
false;
916 bool replaced =
false;
919 for (
int i = 0; i <
m_blocks.size(); i++)
947 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
951 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
953 (*i1)->SetBlocks(*i2);
956 if ((*i1)->m_type == QMetaType::UnknownType)
969 if (!QCoreApplication::instance())
984 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
985 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
987 auto storedType =
m_stored.typeId();
989 if (
m_type == QMetaType::QString)
991 if (storedType == QMetaType::QByteArray)
999 else if (
m_type == QMetaType::QStringList)
1001 if (storedType == QMetaType::QVariantList)
1003 QVariantList vlist =
m_stored.toList();
1005 for (
const auto& item : std::as_const(vlist))
1006 slist << QString::fromLocal8Bit(item.toByteArray());
1010 else if (
m_type == QMetaType::QVariantMap)
1012 QVariantMap vmap =
m_stored.toMap();
1014 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1015 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1033 QStringList::const_iterator it;
1039 int len2 = (*it).size();
1058 QList<CommandLineArg*>::const_iterator i;
1060 bool passes =
false;
1072 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1073 <<
" requires at least one of the following arguments" << std::endl;
1076 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1077 std::cerr << std::endl << std::endl;
1088 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1089 <<
" requires all of the following be defined as well"
1094 << (*i)->GetPreferredKeyword().toLocal8Bit()
1097 std::cerr << std::endl << std::endl;
1107 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1108 <<
" requires that none of the following be defined" << std::endl;
1112 << (*i)->GetPreferredKeyword().toLocal8Bit()
1115 std::cerr << std::endl << std::endl;
1151 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1154 QMap<QString, QVariant> tmpmap;
1155 QMap<QString, QVariant>::const_iterator it;
1161 case QMetaType::Bool:
1162 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1165 case QMetaType::Int:
1166 std::cerr <<
m_stored.toInt() << std::endl;
1169 case QMetaType::UInt:
1170 std::cerr <<
m_stored.toUInt() << std::endl;
1173 case QMetaType::LongLong:
1174 std::cerr <<
m_stored.toLongLong() << std::endl;
1177 case QMetaType::Double:
1178 std::cerr <<
m_stored.toDouble() << std::endl;
1181 case QMetaType::QSize:
1183 std::cerr <<
"x=" << tmpsize.width()
1184 <<
" y=" << tmpsize.height()
1188 case QMetaType::QString:
1189 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1190 <<
'"' << std::endl;
1193 case QMetaType::QStringList:
1195 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1196 for (
const auto& str : std::as_const(vlist))
1202 std::cerr << std::endl;
1205 case QMetaType::QVariantMap:
1207 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1212 std::cerr << QString(
"").leftJustified(32)
1213 .toLocal8Bit().constData();
1215 std::cerr << it.key().toLocal8Bit().constData()
1217 << it->toByteArray().constData()
1223 case QMetaType::QDateTime:
1225 .toLocal8Bit().constData()
1230 std::cerr << std::endl;
1238 QString warn = QString(
"%1 has been removed").arg(keyword);
1242 std::cerr << QString(
"****************************************************\n"
1245 "****************************************************\n\n")
1247 .toLocal8Bit().constData();
1254 std::cerr << QString(
"****************************************************\n"
1255 " WARNING: %1 has been deprecated\n"
1257 "****************************************************\n\n")
1259 .toLocal8Bit().constData();
1276 : m_appname(std::move(appname))
1278 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1280 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1289 QString pidfile =
toString(
"pidfile");
1290 if (!pidfile.isEmpty())
1292 QFile::remove(pidfile);
1295 QMap<QString, CommandLineArg*>::iterator i;
1300 (*i)->CleanupLinks();
1347 const QString& name, QMetaType::Type
type, QVariant def,
1348 QString
help, QString longhelp)
1360 for (
const auto & str : std::as_const(arglist))
1367 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1368 <<
" as taking type '"
1369 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1370 << QVariant::typeToName(
static_cast<int>(
type))
1372 << QMetaType(
type).name()
1374 <<
"'" << std::endl;
1388 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1391 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1392 std::cout <<
"Library API : " << MYTH_BINARY_VERSION << std::endl;
1393 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1394 #ifdef MYTH_BUILD_CONFIG
1395 std::cout <<
"Options compiled in:" <<std::endl;
1396 std::cout << MYTH_BUILD_CONFIG << std::endl;
1405 std::cerr <<
help.toLocal8Bit().constData();
1416 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1418 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1420 msg << versionStr << Qt::endl;
1422 if (
toString(
"showhelp").isEmpty())
1427 if (descr.size() > 0)
1428 msg << Qt::endl << descr << Qt::endl << Qt::endl;
1431 QStringList groups(
"");
1435 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1436 if (!groups.contains(cmdarg->m_group))
1437 groups << cmdarg->m_group;
1443 for (
const auto & group : std::as_const(groups))
1445 if (group.isEmpty())
1446 msg <<
"Misc. Options:" << Qt::endl << Qt::endl;
1448 msg << group.toLocal8Bit().constData() <<
" Options:" << Qt::endl << Qt::endl;
1451 msg << cmdarg->GetHelpString(maxlen, group);
1458 QString optstr =
"-" +
toString(
"showhelp");
1461 optstr =
"-" + optstr;
1463 return QString(
"Could not find option matching '%1'\n")
1478 int &argpos, QString &opt, QByteArray &val)
1487 QByteArray
tmp(argv[argpos]);
1499 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1508 if (
tmp.contains(
'='))
1511 QList<QByteArray> blist =
tmp.split(
'=');
1513 if (blist.size() != 2)
1527 if (argpos+1 >= argc)
1531 tmp = QByteArray(argv[++argpos]);
1536 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1570 for (
int argpos = 1; argpos < argc; ++argpos)
1574 res =
getOpt(argc, argv, argpos, opt, val);
1579 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1580 <<
"val: " << val.constData() << std::endl << std::endl;
1586 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1603 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1604 << opt.toLocal8Bit().constData();
1621 std::cerr <<
"Received '"
1623 <<
"' but unassociated arguments have not been enabled"
1636 std::cerr <<
"Command line arguments received out of sequence"
1643 if (opt.startsWith(
"-psn_"))
1645 std::cerr <<
"Ignoring Process Serial Number from command line"
1658 QByteArray
tmp = opt.toLocal8Bit();
1667 std::cerr <<
"Unhandled option given on command line:" << std::endl
1668 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1691 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1697 if (!argdef->
Set(opt))
1706 if (!argdef->
Set(opt, val))
1727 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1733 std::cerr <<
"Processed option list:" << std::endl;
1735 cmdarg->PrintVerbose();
1739 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1741 for (
const auto& lopt : std::as_const(slist))
1742 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1747 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1748 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1751 std::cerr << std::endl;
1757 if (!cmdarg->TestLinks())
1759 QString keyword = cmdarg->m_usedKeyword;
1760 if (keyword.startsWith(
'-'))
1762 if (keyword.startsWith(
"--"))
1763 keyword.remove(0,2);
1765 keyword.remove(0,1);
1777 QString
help, QString longhelp)
1779 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1783 QString
help, QString longhelp)
1785 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1789 QString
help, QString longhelp)
1791 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1795 QString
help, QString longhelp)
1797 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1801 QString
help, QString longhelp)
1803 return add(QStringList(arg), name, QMetaType::Double, 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::QString, QVariant(def), std::move(
help), std::move(longhelp));
1819 QString
help, QString longhelp)
1821 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1825 QString
help, QString longhelp)
1827 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1831 QString
help, QString longhelp)
1833 return add(QStringList(arg), name,
type,
1834 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1835 QVariant(
static_cast<QVariant::Type
>(
type)),
1837 QVariant(QMetaType(
type)),
1839 std::move(
help), std::move(longhelp));
1843 QMetaType::Type
type,
1844 QVariant def, QString
help, QString longhelp)
1846 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1850 QString
help, QString longhelp)
1852 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1856 QString
help, QString longhelp)
1858 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1862 QString
help, QString longhelp)
1864 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1868 QString
help, QString longhelp)
1870 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1874 QString
help, QString longhelp)
1876 return add(std::move(arglist), name, QMetaType::Double, 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::QString, QVariant(def), std::move(
help), std::move(longhelp));
1892 QString
help, QString longhelp)
1894 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1898 QString
help, QString longhelp)
1900 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1904 QMetaType::Type
type,
1905 QString
help, QString longhelp)
1907 return add(std::move(arglist), name,
type,
1908 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1909 QVariant(
static_cast<QVariant::Type
>(
type)),
1911 QVariant(QMetaType(
type)),
1913 std::move(
help), std::move(longhelp));
1922 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1924 QMap<QString,CommandLineArg*>::iterator args_it;
1927 QList<CommandLineArg*> links = (*args_it)->m_parents;
1928 QList<CommandLineArg*>::iterator links_it;
1929 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1931 if ((*links_it)->m_type != QMetaType::UnknownType)
1937 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1938 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1939 <<
"' could not find '"
1940 << (*links_it)->m_name.toLocal8Bit().constData()
1941 <<
"'." << std::endl
1942 <<
" Please resolve dependency and recompile." << std::endl;
1949 std::cerr << QString(
" Setting %1 as child of %2")
1950 .arg((*args_it)->m_name, (*links_it)->m_name)
1951 .toLocal8Bit().constData()
1954 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1957 links = (*args_it)->m_children;
1958 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1960 if ((*links_it)->m_type != QMetaType::UnknownType)
1966 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1967 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1968 <<
"' could not find '"
1969 << (*links_it)->m_name.toLocal8Bit().constData()
1970 <<
"'." << std::endl
1971 <<
" Please resolve dependency and recompile." << std::endl;
1978 std::cerr << QString(
" Setting %1 as parent of %2")
1979 .arg((*args_it)->m_name, (*links_it)->m_name)
1980 .toLocal8Bit().constData()
1983 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1986 links = (*args_it)->m_requires;
1987 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1989 if ((*links_it)->m_type != QMetaType::UnknownType)
1995 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1996 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1997 <<
"' could not find '"
1998 << (*links_it)->m_name.toLocal8Bit().constData()
1999 <<
"'." << std::endl
2000 <<
" Please resolve dependency and recompile." << std::endl;
2007 std::cerr << QString(
" Setting %1 as requiring %2")
2008 .arg((*args_it)->m_name, (*links_it)->m_name)
2009 .toLocal8Bit().constData()
2012 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
2015 QList<CommandLineArg*>::iterator req_it =
2016 (*args_it)->m_requiredby.begin();
2017 while (req_it != (*args_it)->m_requiredby.end())
2019 if ((*req_it)->m_type == QMetaType::UnknownType)
2024 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2027 std::cerr << QString(
" Setting %1 as blocking %2")
2028 .arg((*args_it)->m_name,
2030 .toLocal8Bit().constData()
2036 (*req_it)->DecrRef();
2037 req_it = (*args_it)->m_requiredby.erase(req_it);
2040 QList<CommandLineArg*>::iterator block_it =
2041 (*args_it)->m_blocks.begin();
2042 while (block_it != (*args_it)->m_blocks.end())
2044 if ((*block_it)->m_type != QMetaType::UnknownType)
2052 (*block_it)->DecrRef();
2053 block_it = (*args_it)->m_blocks.erase(block_it);
2060 std::cerr << QString(
" Setting %1 as blocking %2")
2061 .arg((*args_it)->m_name, (*block_it)->m_name)
2062 .toLocal8Bit().constData()
2065 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2105 return toMap(
"_extra");
2124 QMap<QString,QString> smap =
toMap(
"overridesettings");
2128 if (
toBool(
"overridesettingsfile"))
2134 if (f.open(QIODevice::ReadOnly))
2137 while (!in.atEnd()) {
2138 QString line = in.readLine().trimmed();
2139 QStringList tokens = line.split(
"=",
2140 Qt::SkipEmptyParts);
2141 if (tokens.size() == 2)
2143 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2144 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2145 tokens[0].remove(kQuoteStartRE);
2146 tokens[0].remove(kQuoteEndRE);
2147 tokens[1].remove(kQuoteStartRE);
2148 tokens[1].remove(kQuoteEndRE);
2149 if (!tokens[0].isEmpty())
2150 smap[tokens[0]] = tokens[1];
2157 std::cerr <<
"Failed to open the override settings file: '"
2158 <<
tmp.constData() <<
"'" << std::endl;
2164 smap[
"RunFrontendInWindow"] =
"1";
2165 else if (
toBool(
"notwindowed"))
2166 smap[
"RunFrontendInWindow"] =
"0";
2168 if (
toBool(
"mousecursor"))
2169 smap[
"HideMouseCursor"] =
"0";
2170 else if (
toBool(
"nomousecursor"))
2171 smap[
"HideMouseCursor"] =
"1";
2175 if (!smap.isEmpty())
2178 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2179 vmap[it.key()] = QVariant(it.value());
2181 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2187 std::cerr <<
"Option Overrides:" << std::endl;
2188 QMap<QString, QString>::const_iterator it;
2189 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2190 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2191 .toLocal8Bit().constData() << std::endl;
2212 if (arg->
m_type == QMetaType::Bool)
2237 if (arg->
m_stored.canConvert<
int>())
2291 if (arg->
m_stored.canConvert<
long long>())
2296 if (arg->
m_default.canConvert<
long long>())
2318 if (arg->
m_stored.canConvert<
double>())
2323 if (arg->
m_default.canConvert<
double>())
2345 if (arg->
m_stored.canConvert<QSize>())
2375 if (arg->
m_stored.canConvert<QString>())
2380 if (arg->
m_default.canConvert<QString>())
2414 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2415 val = varval.toString().split(sep);
2416 else if (varval.canConvert<QStringList>())
2417 val = varval.toStringList();
2427 QMap<QString, QString> val;
2428 QMap<QString, QVariant>
tmp;
2441 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2446 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2450 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2451 val[i.key()] = i.value().toString();
2471 if (arg->
m_stored.canConvert<QDateTime>())
2476 if (arg->
m_default.canConvert<QDateTime>())
2498 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2517 QMap<QString,QVariant> vmap;
2518 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2539 QMetaType::QStringList, QStringList());
2547 add(QStringList{
"-h",
"--help",
"--usage"},
2548 "showhelp",
"",
"Display this help printout, or give detailed "
2549 "information of selected option.",
2550 "Displays a list of all commands available for use with "
2551 "this application. If another option is provided as an "
2552 "argument, it will provide detailed information on that "
2560 add(
"--version",
"showversion",
false,
"Display version information.",
2561 "Display informtion about build, including:\n"
2562 " version, branch, protocol, library API, Qt "
2563 "and compiled options.");
2570 add(QStringList{
"-nw",
"--no-windowed"},
2571 "notwindowed",
false,
2572 "Prevent application from running in a window.",
"")
2573 ->SetBlocks(
"windowed")
2576 add(QStringList{
"-w",
"--windowed"},
"windowed",
2577 false,
"Force application to run in a window.",
"")
2578 ->SetGroup(
"User Interface");
2585 add(
"--mouse-cursor",
"mousecursor",
false,
2586 "Force visibility of the mouse cursor.",
"")
2590 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2591 "Force the mouse cursor to be hidden.",
"")
2599 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2600 "Fork application into background after startup.",
2601 "Fork application into background, detatching from "
2602 "the local terminal.\nOften used with: "
2603 " --logpath --pidfile --user");
2611 add(QStringList{
"-O",
"--override-setting"},
2612 "overridesettings", QMetaType::QVariantMap,
2613 "Override a single setting defined by a key=value pair.",
2614 "Override a single setting from the database using "
2615 "options defined as one or more key=value pairs\n"
2616 "Multiple can be defined by multiple uses of the "
2618 add(
"--override-settings-file",
"overridesettingsfile",
"",
2619 "Define a file of key=value pairs to be "
2620 "loaded for setting overrides.",
"");
2627 add(
"--chanid",
"chanid", 0U,
2628 "Specify chanid of recording to operate on.",
"")
2631 add(
"--starttime",
"starttime", QDateTime(),
2632 "Specify start time of recording to operate on.",
"")
2640 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2641 "",
"Specify window size and position (WxH[+X+Y])",
"")
2642 ->SetGroup(
"User Interface");
2649 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2656 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2663 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2666 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2667 LOG_INFO : defaultLogLevel;
2671 add(QStringList{
"-v",
"--verbose"},
"verbose",
2673 "Specify log filtering. Use '-v help' for level info.",
"")
2674 ->SetGroup(
"Logging");
2675 add(
"-V",
"verboseint", 0LL,
"",
2676 "This option is intended for internal use only.\n"
2677 "This option takes an unsigned value corresponding "
2678 "to the bitwise log verbosity operator.")
2680 add(
"--logpath",
"logpath",
"",
2681 "Writes logging messages to a file in the directory logpath with "
2682 "filenames in the format: applicationName.date.pid.log.\n"
2683 "This is typically used in combination with --daemon, and if used "
2684 "in combination with --pidfile, this can be used with log "
2685 "rotators, using the HUP call to inform MythTV to reload the "
2688 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2689 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2690 ->SetGroup(
"Logging");
2691 add(
"--loglong",
"loglong", 0,
2692 "Use long log format for the console, i.e. show file, line number, etc. in the console log.",
"")
2694 add(
"--loglevel",
"loglevel", logLevelStr,
2696 "Set the logging level. All log messages at lower levels will be "
2698 "In descending order: emerg, alert, crit, err, warning, notice, "
2699 "info, debug, trace\ndefaults to ") + logLevelStr,
"")
2701 add(
"--syslog",
"syslog",
"none",
2702 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2703 "defaults to none.",
"")
2705 #if CONFIG_SYSTEMD_JOURNAL
2706 add(
"--systemd-journal",
"systemd-journal",
"false",
2707 "Use systemd-journal instead of syslog.",
"")
2713 add(
"--nodblog",
"nodblog",
false,
"",
"")
2715 ->
SetRemoved(
"Database logging has been removed.",
"34");
2716 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2718 ->
SetRemoved(
"Database logging has been removed.",
"34");
2720 add(QStringList{
"-l",
"--logfile"},
2721 "logfile",
"",
"",
"")
2722 ->SetGroup(
"Logging")
2723 ->
SetRemoved(
"This option has been removed as part of "
2724 "rewrite of the logging interface. Please update your init "
2725 "scripts to use --syslog to interface with your system's "
2726 "existing system logging daemon, or --logpath to specify a "
2727 "dirctory for MythTV to write its logs to.",
"0.25");
2734 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2735 "Write PID of application to filename.",
2736 "Write the PID of the currently running process as a single "
2737 "line to this file. Used for init scripts to know what "
2738 "process to terminate, and with log rotators "
2739 "to send a HUP signal to process to have it re-open files.");
2746 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2747 "Intended for internal use only, specify the JobID to match "
2748 "up with in the database for additional information and the "
2749 "ability to update runtime status in the database.");
2756 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2758 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2766 add(QStringList{
"-display",
"--display"},
"display",
"",
2767 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2776 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2777 "Qt platform argument that is passed through to Qt")
2785 QString logfile =
toString(
"logpath");
2786 pid_t pid = getpid();
2788 if (logfile.isEmpty())
2791 QFileInfo finfo(logfile);
2794 LOG(VB_GENERAL, LOG_ERR,
2795 QString(
"%1 is not a directory, disabling logfiles")
2800 QString logdir = finfo.filePath();
2801 logfile = QCoreApplication::applicationName() +
"." +
2803 QString(
".%1").arg(pid) +
".log";
2807 SetValue(
"filepath", QFileInfo(QDir(logdir), logfile).filePath());
2816 QString setting =
toString(
"syslog").toLower();
2817 if (setting ==
"none")
2827 QString setting =
toString(
"loglevel");
2828 if (setting.isEmpty())
2832 if (level == LOG_UNKNOWN)
2833 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2849 const QVariant& val(value);
2850 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2851 auto type =
static_cast<QMetaType::Type
>(val.type());
2853 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2861 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2862 auto type =
static_cast<QMetaType::Type
>(value.type());
2864 auto type = value.typeId();
2889 else if (
toBool(
"verboseint"))
2903 bool loglong =
toBool(
"loglong");
2906 #if CONFIG_SYSTEMD_JOURNAL
2907 bool journal =
toBool(
"systemd-journal");
2912 facility = SYSTEMD_JOURNAL_FACILITY;
2916 if (level == LOG_UNKNOWN)
2919 LOG(VB_GENERAL, LOG_CRIT,
2920 QString(
"%1 version: %2 [%3] www.mythtv.org")
2921 .arg(QCoreApplication::applicationName(),
2923 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2924 .arg(QT_VERSION_STR, qVersion()));
2925 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2926 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2927 LOG(VB_GENERAL, LOG_NOTICE,
2931 bool propagate = !logfile.isEmpty();
2937 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2938 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2950 std::cerr <<
"Applying settings override" << std::endl;
2953 if (!
override.empty())
2955 QMap<QString, QString>::iterator it;
2956 for (it =
override.begin(); it !=
override.end(); ++it)
2958 LOG(VB_GENERAL, LOG_NOTICE,
2959 QString(
"Setting '%1' being forced to '%2'")
2960 .arg(it.key(), *it));
2968 if (!pidfile.isEmpty())
2970 std::ofstream pidfs {pidfile.toLocal8Bit().constData()};
2973 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2976 pidfs << getpid() << std::endl;
2985 if (username.isEmpty())
2989 std::cerr <<
"--user option is not supported on Windows" << std::endl;
2992 #if defined(__linux__) || defined(__LINUX__)
2995 int dumpability = prctl(PR_GET_DUMPABLE);
2997 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
2998 const uid_t user_id =
geteuid();
3002 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
3007 LOG(VB_GENERAL, LOG_WARNING,
3008 QString(
"Already running as '%1'").arg(username));
3014 std::cerr <<
"Error setting home directory." << std::endl;
3019 std::cerr <<
"Error setting effective group." << std::endl;
3024 std::cerr <<
"Error setting groups." << std::endl;
3029 std::cerr <<
"Error setting effective user." << std::endl;
3032 #if defined(__linux__) || defined(__LINUX__)
3033 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3035 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3036 "creation. Run without the --user argument to use "
3037 "shell-specified limits.");
3043 std::cerr << QString(
"Invalid user '%1' specified with --user")
3044 .arg(username).toLocal8Bit().constData() << std::endl;
3059 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3060 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3065 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
3066 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3071 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
3076 QString username =
toString(
"username");
3077 if (!username.isEmpty() && !
setUser(username))