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());
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 ==
'\'') state = INSQUOTE;
190 else if (c ==
'\"') state = INDQUOTE;
191 else if (c ==
'\\') state = ESCTEXT;
194 if (c ==
'\'') state = INTEXT;
195 else if (c ==
'\\') state = ESCSQUOTE;
198 if (c ==
'\"') state = INTEXT;
199 else if (c ==
'\\') state = ESCDQUOTE;
201 case ESCTEXT: state = INTEXT;
break;
202 case ESCSQUOTE: state = INSQUOTE;
break;
203 case ESCDQUOTE: state = INDQUOTE;
break;
208 fields += line.mid(tokenStart);
232 return "kCombOptVal";
238 return "kPassthrough";
281 QVariant def, QString
help, QString longhelp) :
283 m_name(name), m_type(
type), m_default(
std::move(def)),
284 m_help(
std::move(
help)), m_longhelp(
std::move(longhelp))
286 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
287 (
m_type != QMetaType::QVariantMap))
299 m_name(name), m_type(
type), m_default(
std::move(def))
301 if ((
m_type != QMetaType::QString) && (
m_type != QMetaType::QStringList) &&
302 (
m_type != QMetaType::QVariantMap))
336 QList<CommandLineArg*>::const_iterator i1;
338 len = std::max(len, (*i1)->GetKeywordLength()+2);
361 QTextStream msg(&helpstr, QIODevice::WriteOnly);
406 QStringList hlist =
m_help.split(
'\n');
412 << hlist.takeFirst() << Qt::endl;
415 for (
const auto & line : std::as_const(hlist))
416 msg << pad << line << Qt::endl;
420 msg << arg->GetHelpString(off, group,
true);
436 QTextStream msg(&helpstr, QIODevice::WriteOnly);
454 msg <<
"Option: " << keyword << Qt::endl << Qt::endl;
459 for (
const auto & word : std::as_const(
m_keywords))
465 msg <<
"Aliases: " << word << Qt::endl;
469 msg <<
" " << word << Qt::endl;
474 msg <<
"Type: " << QMetaType(
m_type).name() << Qt::endl;
476 msg <<
"Default: " <<
m_default.toString() << Qt::endl;
486 msg <<
"Description: " <<
help.takeFirst() << Qt::endl;
487 for (
const auto & line : std::as_const(
help))
488 msg <<
" " << line << Qt::endl;
490 QList<CommandLineArg*>::const_iterator i2;
495 msg << Qt::endl <<
"Can be used in combination with:" << Qt::endl;
496 for (
auto * parent : std::as_const(
m_parents))
497 msg <<
" " << parent->GetPreferredKeyword()
498 .toLocal8Bit().constData();
504 msg << Qt::endl <<
"Allows the use of:" << Qt::endl;
506 msg <<
" " << (*i2)->GetPreferredKeyword()
507 .toLocal8Bit().constData();
513 msg << Qt::endl <<
"Requires the use of:" << Qt::endl;
515 msg <<
" " << (*i2)->GetPreferredKeyword()
516 .toLocal8Bit().constData();
522 msg << Qt::endl <<
"Prevents the use of:" << Qt::endl;
524 msg <<
" " << (*i2)->GetPreferredKeyword()
525 .toLocal8Bit().constData();
545 case QMetaType::Bool:
556 case QMetaType::QString:
561 std::cerr <<
"Command line option did not receive value:" << std::endl
562 <<
" " << opt.toLocal8Bit().constData() << std::endl;
575 QList<QByteArray> blist;
581 case QMetaType::Bool:
582 std::cerr <<
"Boolean type options do not accept values:" << std::endl
583 <<
" " << opt.toLocal8Bit().constData() << std::endl;
586 case QMetaType::QString:
594 case QMetaType::UInt:
598 case QMetaType::LongLong:
599 m_stored = QVariant(val.toLongLong());
602 case QMetaType::Double:
603 m_stored = QVariant(val.toDouble());
606 case QMetaType::QDateTime:
610 case QMetaType::QStringList:
617 case QMetaType::QVariantMap:
618 if (!val.contains(
'='))
620 std::cerr <<
"Command line option did not get expected "
621 <<
"key/value pair" << std::endl;
625 blist = val.split(
'=');
633 case QMetaType::QSize:
634 if (!val.contains(
'x'))
636 std::cerr <<
"Command line option did not get expected "
637 <<
"XxY pair" << std::endl;
641 blist = val.split(
'x');
642 m_stored = QVariant(QSize(blist[0].toInt(), blist[1].toInt()));
665 for (
const auto& opt : std::as_const(
opts))
682 for (
const auto& opt : std::as_const(
opts))
699 for (
const auto& opt : std::as_const(
opts))
716 for (
const auto& opt : std::as_const(
opts))
734 for (
const auto& opt : std::as_const(
opts))
755 for (
const auto& opt : std::as_const(
opts))
775 for (
const auto& opt : std::as_const(
opts))
792 for (
const auto& opt : std::as_const(
opts))
801 if (depstr.isEmpty())
802 depstr =
"and will be removed in a future version.";
811 if (remstr.isEmpty())
812 remstr =
"and is no longer available in this version.";
825 bool replaced =
false;
853 bool replaced =
false;
856 for (
int i = 0; i <
m_parents.size(); i++)
881 bool replaced =
false;
910 bool replaced =
false;
913 for (
int i = 0; i <
m_blocks.size(); i++)
941 for (
auto i1 =
args.cbegin(); i1 !=
args.cend()-1; ++i1)
945 for (
auto i2 = i1+1; i2 !=
args.cend(); ++i2)
947 (*i1)->SetBlocks(*i2);
950 if ((*i1)->m_type == QMetaType::UnknownType)
963 if (!QCoreApplication::instance())
978 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
979 auto storedType =
static_cast<QMetaType::Type
>(
m_stored.type());
981 auto storedType =
m_stored.typeId();
983 if (
m_type == QMetaType::QString)
985 if (storedType == QMetaType::QByteArray)
993 else if (
m_type == QMetaType::QStringList)
995 if (storedType == QMetaType::QVariantList)
997 QVariantList vlist =
m_stored.toList();
999 for (
const auto& item : std::as_const(vlist))
1000 slist << QString::fromLocal8Bit(item.toByteArray());
1004 else if (
m_type == QMetaType::QVariantMap)
1006 QVariantMap vmap =
m_stored.toMap();
1008 for (
auto iter = vmap.begin(); iter != vmap.end(); ++iter)
1009 (*iter) = QString::fromLocal8Bit(iter->toByteArray());
1025 QStringList::const_iterator it;
1031 int len2 = (*it).size();
1050 QList<CommandLineArg*>::const_iterator i;
1052 bool passes =
false;
1064 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1065 <<
" requires at least one of the following arguments" << std::endl;
1068 << (*i)->GetPreferredKeyword().toLocal8Bit().constData();
1069 std::cerr << std::endl << std::endl;
1080 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1081 <<
" requires all of the following be defined as well"
1086 << (*i)->GetPreferredKeyword().toLocal8Bit()
1089 std::cerr << std::endl << std::endl;
1099 std::cerr <<
"ERROR: " <<
m_usedKeyword.toLocal8Bit().constData()
1100 <<
" requires that none of the following be defined" << std::endl;
1104 << (*i)->GetPreferredKeyword().toLocal8Bit()
1107 std::cerr << std::endl << std::endl;
1143 std::cerr <<
" " <<
m_name.leftJustified(30).toLocal8Bit().constData();
1146 QMap<QString, QVariant> tmpmap;
1147 QMap<QString, QVariant>::const_iterator it;
1153 case QMetaType::Bool:
1154 std::cerr << (
m_stored.toBool() ?
"True" :
"False") << std::endl;
1157 case QMetaType::Int:
1158 std::cerr <<
m_stored.toInt() << std::endl;
1161 case QMetaType::UInt:
1162 std::cerr <<
m_stored.toUInt() << std::endl;
1165 case QMetaType::LongLong:
1166 std::cerr <<
m_stored.toLongLong() << std::endl;
1169 case QMetaType::Double:
1170 std::cerr <<
m_stored.toDouble() << std::endl;
1173 case QMetaType::QSize:
1175 std::cerr <<
"x=" << tmpsize.width()
1176 <<
" y=" << tmpsize.height()
1180 case QMetaType::QString:
1181 std::cerr <<
'"' <<
m_stored.toByteArray().constData()
1182 <<
'"' << std::endl;
1185 case QMetaType::QStringList:
1187 std::cerr <<
'"' << vlist.takeFirst().toByteArray().constData() <<
'"';
1188 for (
const auto& str : std::as_const(vlist))
1194 std::cerr << std::endl;
1197 case QMetaType::QVariantMap:
1199 for (it = tmpmap.cbegin(); it != tmpmap.cend(); ++it)
1204 std::cerr << QString(
"").leftJustified(32)
1205 .toLocal8Bit().constData();
1207 std::cerr << it.key().toLocal8Bit().constData()
1209 << it->toByteArray().constData()
1215 case QMetaType::QDateTime:
1217 .toLocal8Bit().constData()
1222 std::cerr << std::endl;
1230 QString warn = QString(
"%1 has been removed").arg(keyword);
1234 std::cerr << QString(
"****************************************************\n"
1237 "****************************************************\n\n")
1239 .toLocal8Bit().constData();
1246 std::cerr << QString(
"****************************************************\n"
1247 " WARNING: %1 has been deprecated\n"
1249 "****************************************************\n\n")
1251 .toLocal8Bit().constData();
1268 : m_appname(
std::move(appname))
1270 if (qEnvironmentVariableIsSet(
"VERBOSE_PARSER"))
1272 std::cerr <<
"MythCommandLineParser is now operating verbosely." << std::endl;
1281 QMap<QString, CommandLineArg*>::iterator i;
1286 (*i)->CleanupLinks();
1333 const QString& name, QMetaType::Type
type, QVariant def,
1334 QString
help, QString longhelp)
1346 for (
const auto & str : std::as_const(arglist))
1353 std::cerr <<
"Adding " << str.toLocal8Bit().constData()
1354 <<
" as taking type '"
1355 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1356 << QVariant::typeToName(
static_cast<int>(
type))
1358 << QMetaType(
type).name()
1360 <<
"'" << std::endl;
1374 std::cout <<
"Please attach all output as a file in bug reports." << std::endl;
1377 std::cout <<
"Network Protocol : " << MYTH_PROTO_VERSION << std::endl;
1378 std::cout <<
"Library API : " << MYTH_BINARY_VERSION << std::endl;
1379 std::cout <<
"QT Version : " << QT_VERSION_STR << std::endl;
1380 #ifdef MYTH_BUILD_CONFIG
1381 std::cout <<
"Options compiled in:" <<std::endl;
1382 std::cout << MYTH_BUILD_CONFIG << std::endl;
1391 std::cerr <<
help.toLocal8Bit().constData();
1402 QTextStream msg(&helpstr, QIODevice::WriteOnly);
1404 QString versionStr = QString(
"%1 version: %2 [%3] www.mythtv.org")
1406 msg << versionStr << Qt::endl;
1408 if (
toString(
"showhelp").isEmpty())
1413 if (descr.size() > 0)
1414 msg << Qt::endl << descr << Qt::endl << Qt::endl;
1417 QStringList groups(
"");
1421 maxlen = std::max(cmdarg->GetKeywordLength(), maxlen);
1422 if (!groups.contains(cmdarg->m_group))
1423 groups << cmdarg->m_group;
1429 for (
const auto & group : std::as_const(groups))
1431 if (group.isEmpty())
1432 msg <<
"Misc. Options:" << Qt::endl << Qt::endl;
1434 msg << group.toLocal8Bit().constData() <<
" Options:" << Qt::endl << Qt::endl;
1437 msg << cmdarg->GetHelpString(maxlen, group);
1444 QString optstr =
"-" +
toString(
"showhelp");
1447 optstr =
"-" + optstr;
1449 return QString(
"Could not find option matching '%1'\n")
1464 int &argpos, QString &opt, QByteArray &val)
1473 QByteArray
tmp(argv[argpos]);
1485 if (
tmp.startsWith(
'-') &&
tmp.size() > 1)
1494 if (
tmp.contains(
'='))
1497 QList<QByteArray> blist =
tmp.split(
'=');
1499 if (blist.size() != 2)
1513 if (argpos+1 >= argc)
1517 tmp = QByteArray(argv[++argpos]);
1522 if (
tmp.startsWith(
"-") &&
tmp.size() > 1)
1556 for (
int argpos = 1; argpos < argc; ++argpos)
1560 res =
getOpt(argc, argv, argpos, opt, val);
1565 <<
"opt: " << opt.toLocal8Bit().constData() << std::endl
1566 <<
"val: " << val.constData() << std::endl << std::endl;
1572 std::cerr <<
"Received '--' but passthrough has not been enabled" << std::endl;
1589 std::cerr <<
"Invalid option received:" << std::endl <<
" "
1590 << opt.toLocal8Bit().constData();
1607 std::cerr <<
"Received '"
1609 <<
"' but unassociated arguments have not been enabled"
1622 std::cerr <<
"Command line arguments received out of sequence"
1629 if (opt.startsWith(
"-psn_"))
1631 std::cerr <<
"Ignoring Process Serial Number from command line"
1644 QByteArray
tmp = opt.toLocal8Bit();
1653 std::cerr <<
"Unhandled option given on command line:" << std::endl
1654 <<
" " << opt.toLocal8Bit().constData() << std::endl;
1675 std::cerr <<
"name: " << argdef->
GetName().toLocal8Bit().constData()
1681 if (!argdef->
Set(opt))
1690 if (!argdef->
Set(opt, val))
1711 std::cerr <<
"value: " << argdef->
m_stored.toString().toLocal8Bit().constData()
1717 std::cerr <<
"Processed option list:" << std::endl;
1719 cmdarg->PrintVerbose();
1723 std::cerr << std::endl <<
"Extra argument list:" << std::endl;
1725 for (
const auto& lopt : std::as_const(slist))
1726 std::cerr <<
" " << (lopt).toLocal8Bit().constData() << std::endl;
1731 std::cerr << std::endl <<
"Passthrough string:" << std::endl;
1732 std::cerr <<
" " <<
GetPassthrough().toLocal8Bit().constData() << std::endl;
1735 std::cerr << std::endl;
1741 if (!cmdarg->TestLinks())
1743 QString keyword = cmdarg->m_usedKeyword;
1744 if (keyword.startsWith(
'-'))
1746 if (keyword.startsWith(
"--"))
1747 keyword.remove(0,2);
1749 keyword.remove(0,1);
1761 QString
help, QString longhelp)
1763 return add(QStringList(arg), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1767 QString
help, QString longhelp)
1769 return add(QStringList(arg), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1773 QString
help, QString longhelp)
1775 return add(QStringList(arg), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1779 QString
help, QString longhelp)
1781 return add(QStringList(arg), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1785 QString
help, QString longhelp)
1787 return add(QStringList(arg), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1791 QString
help, QString longhelp)
1793 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1797 QString
help, QString longhelp)
1799 return add(QStringList(arg), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1803 QString
help, QString longhelp)
1805 return add(QStringList(arg), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1809 QString
help, QString longhelp)
1811 return add(QStringList(arg), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1815 QString
help, QString longhelp)
1817 return add(QStringList(arg), name,
type,
1818 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1819 QVariant(
static_cast<QVariant::Type
>(
type)),
1821 QVariant(QMetaType(
type)),
1823 std::move(
help), std::move(longhelp));
1827 QMetaType::Type
type,
1828 QVariant def, QString
help, QString longhelp)
1830 return add(QStringList(arg), name,
type, std::move(def), std::move(
help), std::move(longhelp));
1834 QString
help, QString longhelp)
1836 return add(std::move(arglist), name, QMetaType::Bool, QVariant(def), std::move(
help), std::move(longhelp));
1840 QString
help, QString longhelp)
1842 return add(std::move(arglist), name, QMetaType::Int, QVariant(def), std::move(
help), std::move(longhelp));
1846 QString
help, QString longhelp)
1848 return add(std::move(arglist), name, QMetaType::UInt, QVariant(def), std::move(
help), std::move(longhelp));
1852 QString
help, QString longhelp)
1854 return add(std::move(arglist), name, QMetaType::LongLong, QVariant(def), std::move(
help), std::move(longhelp));
1858 QString
help, QString longhelp)
1860 return add(std::move(arglist), name, QMetaType::Double, QVariant(def), std::move(
help), std::move(longhelp));
1864 QString
help, QString longhelp)
1866 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1870 QString
help, QString longhelp)
1872 return add(std::move(arglist), name, QMetaType::QString, QVariant(def), std::move(
help), std::move(longhelp));
1876 QString
help, QString longhelp)
1878 return add(std::move(arglist), name, QMetaType::QSize, QVariant(def), std::move(
help), std::move(longhelp));
1882 QString
help, QString longhelp)
1884 return add(std::move(arglist), name, QMetaType::QDateTime, QVariant(def), std::move(
help), std::move(longhelp));
1888 QMetaType::Type
type,
1889 QString
help, QString longhelp)
1891 return add(std::move(arglist), name,
type,
1892 #
if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1893 QVariant(
static_cast<QVariant::Type
>(
type)),
1895 QVariant(QMetaType(
type)),
1897 std::move(
help), std::move(longhelp));
1906 std::cerr <<
"Reconciling links for option interdependencies." << std::endl;
1908 QMap<QString,CommandLineArg*>::iterator args_it;
1911 QList<CommandLineArg*> links = (*args_it)->m_parents;
1912 QList<CommandLineArg*>::iterator links_it;
1913 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1915 if ((*links_it)->m_type != QMetaType::UnknownType)
1921 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1922 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1923 <<
"' could not find '"
1924 << (*links_it)->m_name.toLocal8Bit().constData()
1925 <<
"'." << std::endl
1926 <<
" Please resolve dependency and recompile." << std::endl;
1933 std::cerr << QString(
" Setting %1 as child of %2")
1934 .arg((*args_it)->m_name, (*links_it)->m_name)
1935 .toLocal8Bit().constData()
1938 (*args_it)->SetChildOf(
m_namedArgs[(*links_it)->m_name]);
1941 links = (*args_it)->m_children;
1942 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1944 if ((*links_it)->m_type != QMetaType::UnknownType)
1950 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1951 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1952 <<
"' could not find '"
1953 << (*links_it)->m_name.toLocal8Bit().constData()
1954 <<
"'." << std::endl
1955 <<
" Please resolve dependency and recompile." << std::endl;
1962 std::cerr << QString(
" Setting %1 as parent of %2")
1963 .arg((*args_it)->m_name, (*links_it)->m_name)
1964 .toLocal8Bit().constData()
1967 (*args_it)->SetParentOf(
m_namedArgs[(*links_it)->m_name]);
1970 links = (*args_it)->m_requires;
1971 for (links_it = links.begin(); links_it != links.end(); ++links_it)
1973 if ((*links_it)->m_type != QMetaType::UnknownType)
1979 std::cerr <<
"ERROR: could not reconcile linked argument." << std::endl
1980 <<
" '" << (*args_it)->m_name.toLocal8Bit().constData()
1981 <<
"' could not find '"
1982 << (*links_it)->m_name.toLocal8Bit().constData()
1983 <<
"'." << std::endl
1984 <<
" Please resolve dependency and recompile." << std::endl;
1991 std::cerr << QString(
" Setting %1 as requiring %2")
1992 .arg((*args_it)->m_name, (*links_it)->m_name)
1993 .toLocal8Bit().constData()
1996 (*args_it)->SetRequires(
m_namedArgs[(*links_it)->m_name]);
1999 QList<CommandLineArg*>::iterator req_it =
2000 (*args_it)->m_requiredby.begin();
2001 while (req_it != (*args_it)->m_requiredby.end())
2003 if ((*req_it)->m_type == QMetaType::UnknownType)
2008 m_namedArgs[(*req_it)->m_name]->SetRequires(*args_it);
2011 std::cerr << QString(
" Setting %1 as blocking %2")
2012 .arg((*args_it)->m_name,
2014 .toLocal8Bit().constData()
2020 (*req_it)->DecrRef();
2021 req_it = (*args_it)->m_requiredby.erase(req_it);
2024 QList<CommandLineArg*>::iterator block_it =
2025 (*args_it)->m_blocks.begin();
2026 while (block_it != (*args_it)->m_blocks.end())
2028 if ((*block_it)->m_type != QMetaType::UnknownType)
2036 (*block_it)->DecrRef();
2037 block_it = (*args_it)->m_blocks.erase(block_it);
2044 std::cerr << QString(
" Setting %1 as blocking %2")
2045 .arg((*args_it)->m_name, (*block_it)->m_name)
2046 .toLocal8Bit().constData()
2049 (*args_it)->SetBlocks(
m_namedArgs[(*block_it)->m_name]);
2089 return toMap(
"_extra");
2108 QMap<QString,QString> smap =
toMap(
"overridesettings");
2112 if (
toBool(
"overridesettingsfile"))
2118 if (f.open(QIODevice::ReadOnly))
2121 while (!in.atEnd()) {
2122 QString line = in.readLine().trimmed();
2123 QStringList tokens = line.split(
"=",
2124 Qt::SkipEmptyParts);
2125 if (tokens.size() == 2)
2127 static const QRegularExpression kQuoteStartRE {
"^[\"']" };
2128 static const QRegularExpression kQuoteEndRE {
"[\"']$" };
2129 tokens[0].remove(kQuoteStartRE);
2130 tokens[0].remove(kQuoteEndRE);
2131 tokens[1].remove(kQuoteStartRE);
2132 tokens[1].remove(kQuoteEndRE);
2133 if (!tokens[0].isEmpty())
2134 smap[tokens[0]] = tokens[1];
2141 std::cerr <<
"Failed to open the override settings file: '"
2142 <<
tmp.constData() <<
"'" << std::endl;
2148 smap[
"RunFrontendInWindow"] =
"1";
2149 else if (
toBool(
"notwindowed"))
2150 smap[
"RunFrontendInWindow"] =
"0";
2152 if (
toBool(
"mousecursor"))
2153 smap[
"HideMouseCursor"] =
"0";
2154 else if (
toBool(
"nomousecursor"))
2155 smap[
"HideMouseCursor"] =
"1";
2159 if (!smap.isEmpty())
2162 for (
auto it = smap.cbegin(); it != smap.cend(); ++it)
2163 vmap[it.key()] = QVariant(it.value());
2165 m_namedArgs[
"overridesettings"]->Set(QVariant(vmap));
2171 std::cerr <<
"Option Overrides:" << std::endl;
2172 QMap<QString, QString>::const_iterator it;
2173 for (it = smap.constBegin(); it != smap.constEnd(); ++it)
2174 std::cerr << QString(
" %1 - %2").arg(it.key(), 30).arg(*it)
2175 .toLocal8Bit().constData() << std::endl;
2196 if (arg->
m_type == QMetaType::Bool)
2221 if (arg->
m_stored.canConvert<
int>())
2275 if (arg->
m_stored.canConvert<
long long>())
2280 if (arg->
m_default.canConvert<
long long>())
2302 if (arg->
m_stored.canConvert<
double>())
2307 if (arg->
m_default.canConvert<
double>())
2329 if (arg->
m_stored.canConvert<QSize>())
2359 if (arg->
m_stored.canConvert<QString>())
2364 if (arg->
m_default.canConvert<QString>())
2396 if (arg->
m_type == QMetaType::QString && !sep.isEmpty())
2397 val = varval.toString().split(sep);
2398 else if (varval.canConvert<QStringList>())
2399 val = varval.toStringList();
2409 QMap<QString, QString> val;
2410 QMap<QString, QVariant>
tmp;
2423 if (arg->
m_stored.canConvert<QMap<QString, QVariant>>())
2428 if (arg->
m_default.canConvert<QMap<QString, QVariant>>())
2432 for (
auto i =
tmp.cbegin(); i !=
tmp.cend(); ++i)
2433 val[i.key()] = i.value().toString();
2453 if (arg->
m_stored.canConvert<QDateTime>())
2458 if (arg->
m_default.canConvert<QDateTime>())
2478 auto *arg =
new CommandLineArg(
"_args", QMetaType::QStringList, QStringList());
2495 QMap<QString,QVariant> vmap;
2496 auto *arg =
new CommandLineArg(
"_extra", QMetaType::QVariantMap, vmap);
2515 QMetaType::QStringList, QStringList());
2523 add(QStringList{
"-h",
"--help",
"--usage"},
2524 "showhelp",
"",
"Display this help printout, or give detailed "
2525 "information of selected option.",
2526 "Displays a list of all commands available for use with "
2527 "this application. If another option is provided as an "
2528 "argument, it will provide detailed information on that "
2536 add(
"--version",
"showversion",
false,
"Display version information.",
2537 "Display informtion about build, including:\n"
2538 " version, branch, protocol, library API, Qt "
2539 "and compiled options.");
2546 add(QStringList{
"-nw",
"--no-windowed"},
2547 "notwindowed",
false,
2548 "Prevent application from running in a window.",
"")
2549 ->SetBlocks(
"windowed")
2552 add(QStringList{
"-w",
"--windowed"},
"windowed",
2553 false,
"Force application to run in a window.",
"")
2554 ->SetGroup(
"User Interface");
2561 add(
"--mouse-cursor",
"mousecursor",
false,
2562 "Force visibility of the mouse cursor.",
"")
2566 add(
"--no-mouse-cursor",
"nomousecursor",
false,
2567 "Force the mouse cursor to be hidden.",
"")
2575 add(QStringList{
"-d",
"--daemon"},
"daemon",
false,
2576 "Fork application into background after startup.",
2577 "Fork application into background, detatching from "
2578 "the local terminal.\nOften used with: "
2579 " --logpath --pidfile --user");
2587 add(QStringList{
"-O",
"--override-setting"},
2588 "overridesettings", QMetaType::QVariantMap,
2589 "Override a single setting defined by a key=value pair.",
2590 "Override a single setting from the database using "
2591 "options defined as one or more key=value pairs\n"
2592 "Multiple can be defined by multiple uses of the "
2594 add(
"--override-settings-file",
"overridesettingsfile",
"",
2595 "Define a file of key=value pairs to be "
2596 "loaded for setting overrides.",
"");
2603 add(
"--chanid",
"chanid", 0U,
2604 "Specify chanid of recording to operate on.",
"")
2607 add(
"--starttime",
"starttime", QDateTime(),
2608 "Specify start time of recording to operate on.",
"")
2616 add(QStringList{
"-geometry",
"--geometry"},
"geometry",
2617 "",
"Specify window size and position (WxH[+X+Y])",
"")
2618 ->SetGroup(
"User Interface");
2625 add(
"--noupnp",
"noupnp",
false,
"Disable use of UPnP.",
"");
2632 add(
"--dvbv3",
"dvbv3",
false,
"Use legacy DVBv3 API.",
"");
2639 const QString &defaultVerbosity, LogLevel_t defaultLogLevel)
2642 ((defaultLogLevel >= LOG_UNKNOWN) || (defaultLogLevel <= LOG_ANY)) ?
2643 LOG_INFO : defaultLogLevel;
2647 add(QStringList{
"-v",
"--verbose"},
"verbose",
2649 "Specify log filtering. Use '-v help' for level info.",
"")
2650 ->SetGroup(
"Logging");
2651 add(
"-V",
"verboseint", 0LL,
"",
2652 "This option is intended for internal use only.\n"
2653 "This option takes an unsigned value corresponding "
2654 "to the bitwise log verbosity operator.")
2656 add(
"--logpath",
"logpath",
"",
2657 "Writes logging messages to a file in the directory logpath with "
2658 "filenames in the format: applicationName.date.pid.log.\n"
2659 "This is typically used in combination with --daemon, and if used "
2660 "in combination with --pidfile, this can be used with log "
2661 "rotators, using the HUP call to inform MythTV to reload the "
2664 add(QStringList{
"-q",
"--quiet"},
"quiet", 0,
2665 "Don't log to the console (-q). Don't log anywhere (-q -q)",
"")
2666 ->SetGroup(
"Logging");
2667 add(
"--loglevel",
"loglevel", logLevelStr,
2669 "Set the logging level. All log messages at lower levels will be "
2671 "In descending order: emerg, alert, crit, err, warning, notice, "
2672 "info, debug\ndefaults to ") + logLevelStr,
"")
2674 add(
"--syslog",
"syslog",
"none",
2675 "Set the syslog logging facility.\nSet to \"none\" to disable, "
2676 "defaults to none.",
"")
2678 #if CONFIG_SYSTEMD_JOURNAL
2679 add(
"--systemd-journal",
"systemd-journal",
"false",
2680 "Use systemd-journal instead of syslog.",
"")
2686 add(
"--nodblog",
"nodblog",
false,
"",
"")
2688 ->
SetRemoved(
"Database logging has been removed.",
"34");
2689 add(
"--enable-dblog",
"enabledblog",
false,
"",
"")
2691 ->
SetRemoved(
"Database logging has been removed.",
"34");
2693 add(QStringList{
"-l",
"--logfile"},
2694 "logfile",
"",
"",
"")
2695 ->SetGroup(
"Logging")
2696 ->
SetRemoved(
"This option has been removed as part of "
2697 "rewrite of the logging interface. Please update your init "
2698 "scripts to use --syslog to interface with your system's "
2699 "existing system logging daemon, or --logpath to specify a "
2700 "dirctory for MythTV to write its logs to.",
"0.25");
2707 add(QStringList{
"-p",
"--pidfile"},
"pidfile",
"",
2708 "Write PID of application to filename.",
2709 "Write the PID of the currently running process as a single "
2710 "line to this file. Used for init scripts to know what "
2711 "process to terminate, and with log rotators "
2712 "to send a HUP signal to process to have it re-open files.");
2719 add(QStringList{
"-j",
"--jobid"},
"jobid", 0,
"",
2720 "Intended for internal use only, specify the JobID to match "
2721 "up with in the database for additional information and the "
2722 "ability to update runtime status in the database.");
2729 add(
"--infile",
"infile",
"",
"Input file URI",
"");
2731 add(
"--outfile",
"outfile",
"",
"Output file URI",
"");
2739 add(QStringList{
"-display",
"--display"},
"display",
"",
2740 "Qt (QPA) X11 connection name when using xcb (X11) platform plugin",
"")
2749 add(QStringList{
"-platform",
"--platform"},
"platform",
"",
"Qt (QPA) platform argument",
2750 "Qt platform argument that is passed through to Qt")
2759 pid_t pid = getpid();
2767 LOG(VB_GENERAL, LOG_ERR,
2768 QString(
"%1 is not a directory, disabling logfiles")
2773 QString logdir = finfo.filePath();
2774 logfile = QCoreApplication::applicationName() +
"." +
2776 QString(
".%1").arg(pid) +
".log";
2789 QString setting =
toString(
"syslog").toLower();
2790 if (setting ==
"none")
2800 QString setting =
toString(
"loglevel");
2801 if (setting.isEmpty())
2805 if (level == LOG_UNKNOWN)
2806 std::cerr <<
"Unknown log level: " << setting.toLocal8Bit().constData()
2822 const QVariant& val(value);
2823 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2824 auto type =
static_cast<QMetaType::Type
>(val.type());
2826 auto type =
static_cast<QMetaType::Type
>(val.typeId());
2834 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2835 auto type =
static_cast<QMetaType::Type
>(value.type());
2837 auto type = value.typeId();
2862 else if (
toBool(
"verboseint"))
2875 #if CONFIG_SYSTEMD_JOURNAL
2876 bool journal =
toBool(
"systemd-journal");
2881 facility = SYSTEMD_JOURNAL_FACILITY;
2885 if (level == LOG_UNKNOWN)
2888 LOG(VB_GENERAL, LOG_CRIT,
2889 QString(
"%1 version: %2 [%3] www.mythtv.org")
2890 .arg(QCoreApplication::applicationName(),
2892 LOG(VB_GENERAL, LOG_CRIT, QString(
"Qt version: compile: %1, runtime: %2")
2893 .arg(QT_VERSION_STR, qVersion()));
2894 LOG(VB_GENERAL, LOG_INFO, QString(
"%1 (%2)")
2895 .arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture()));
2896 LOG(VB_GENERAL, LOG_NOTICE,
2900 bool propagate = !
logfile.isEmpty();
2906 qInstallMessageHandler([](QtMsgType ,
const QMessageLogContext& ,
const QString &Msg)
2907 {
LOG(VB_GENERAL, LOG_INFO,
"Qt: " + Msg); });
2919 std::cerr <<
"Applying settings override" << std::endl;
2922 if (!
override.empty())
2924 QMap<QString, QString>::iterator it;
2925 for (it =
override.begin(); it !=
override.end(); ++it)
2927 LOG(VB_GENERAL, LOG_NOTICE,
2928 QString(
"Setting '%1' being forced to '%2'")
2929 .arg(it.key(), *it));
2939 pidfs.open(
pidfile.toLatin1().constData());
2942 std::cerr <<
"Could not open pid file: " <<
ENO_STR << std::endl;
2953 if (username.isEmpty())
2957 std::cerr <<
"--user option is not supported on Windows" << std::endl;
2960 #if defined(__linux__) || defined(__LINUX__)
2963 int dumpability = prctl(PR_GET_DUMPABLE);
2965 struct passwd *
user_info = getpwnam(username.toLocal8Bit().constData());
2966 const uid_t user_id =
geteuid();
2970 std::cerr <<
"You must be running as root to use the --user switch." << std::endl;
2975 LOG(VB_GENERAL, LOG_WARNING,
2976 QString(
"Already running as '%1'").arg(username));
2982 std::cerr <<
"Error setting home directory." << std::endl;
2987 std::cerr <<
"Error setting effective group." << std::endl;
2992 std::cerr <<
"Error setting groups." << std::endl;
2997 std::cerr <<
"Error setting effective user." << std::endl;
3000 #if defined(__linux__) || defined(__LINUX__)
3001 if (dumpability && (prctl(PR_SET_DUMPABLE, dumpability) == -1))
3003 LOG(VB_GENERAL, LOG_WARNING,
"Unable to re-enable core file "
3004 "creation. Run without the --user argument to use "
3005 "shell-specified limits.");
3011 std::cerr << QString(
"Invalid user '%1' specified with --user")
3012 .arg(username).toLocal8Bit().constData() << std::endl;
3024 std::ofstream pidfs;
3028 if (signal(
SIGPIPE, SIG_IGN) == SIG_ERR)
3029 LOG(VB_GENERAL, LOG_WARNING,
"Unable to ignore SIGPIPE");
3034 std::cerr <<
"Daemonizing is unavailable in OSX" << std::endl;
3035 LOG(VB_GENERAL, LOG_WARNING,
"Unable to daemonize");
3040 std::cerr <<
"Failed to daemonize: " <<
ENO_STR << std::endl;
3045 QString username =
toString(
"username");
3046 if (!username.isEmpty() && !
setUser(username))
3051 pidfs << getpid() << std::endl;