2018-09-29 15:56:04 +03:00
|
|
|
/*
|
2024-12-30 22:39:49 +01:00
|
|
|
* Copyright (C) 2018-2025 QuasarApp.
|
2018-09-29 15:56:04 +03:00
|
|
|
* Distributed under the lgplv3 software license, see the accompanying
|
|
|
|
* Everyone is permitted to copy and distribute verbatim copies
|
|
|
|
* of this license document, but changing it is not allowed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "params.h"
|
|
|
|
#include <QVariantMap>
|
|
|
|
#include <QDebug>
|
2019-01-16 22:17:05 +03:00
|
|
|
#include <QFileInfo>
|
2019-08-23 21:14:32 +03:00
|
|
|
#include <QDateTime>
|
2020-04-04 15:42:56 +03:00
|
|
|
#include <QCoreApplication>
|
2022-05-25 18:05:36 +03:00
|
|
|
#include "qaglobalutils.h"
|
2024-06-24 13:23:40 +02:00
|
|
|
#include <QtLogging>
|
2024-08-02 15:06:04 +03:00
|
|
|
|
|
|
|
#ifdef Q_OS_DARWIN
|
2024-08-02 12:37:38 +03:00
|
|
|
#include <mach-o/dyld.h>
|
2024-08-02 15:06:04 +03:00
|
|
|
#endif
|
2019-08-23 21:14:32 +03:00
|
|
|
|
2019-01-27 19:45:30 +03:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
#include "windows.h"
|
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2018-09-29 15:56:04 +03:00
|
|
|
|
|
|
|
using namespace QuasarAppUtils;
|
2021-04-26 11:46:52 +03:00
|
|
|
QMap<QString, QString> Params::params = QMap<QString, QString>();
|
|
|
|
QString Params::appPath = "";
|
|
|
|
QString Params::appName = "";
|
2021-07-26 13:17:06 +03:00
|
|
|
Help::Section Params::userHelp = {};
|
2021-07-28 12:38:44 +03:00
|
|
|
OptionsDataList Params::inputOptions = {};
|
2018-09-29 15:56:04 +03:00
|
|
|
|
2020-04-18 21:28:35 +03:00
|
|
|
|
2018-09-29 15:56:04 +03:00
|
|
|
bool Params::isEndable(const QString& key) {
|
|
|
|
return params.contains(key);
|
|
|
|
}
|
|
|
|
|
2020-04-04 15:42:56 +03:00
|
|
|
void Params::log(const QString &log, VerboseLvl vLvl) {
|
2019-08-22 14:21:43 +03:00
|
|
|
|
2020-04-14 17:57:54 +03:00
|
|
|
auto lvl = getVerboseLvl();
|
2020-04-04 15:42:56 +03:00
|
|
|
if (vLvl <= lvl) {
|
2019-03-28 18:58:36 +03:00
|
|
|
|
2020-04-04 15:42:56 +03:00
|
|
|
switch (vLvl) {
|
2019-03-28 18:58:36 +03:00
|
|
|
|
2020-04-04 15:42:56 +03:00
|
|
|
case VerboseLvl::Error:
|
2024-06-24 13:23:40 +02:00
|
|
|
qCritical().noquote() << log;
|
2022-02-13 18:44:02 +03:00
|
|
|
break;
|
|
|
|
|
2020-04-04 15:42:56 +03:00
|
|
|
case VerboseLvl::Warning: {
|
2024-06-24 13:23:40 +02:00
|
|
|
qWarning().noquote() << log;
|
2022-01-08 12:23:46 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VerboseLvl::Debug: {
|
2024-06-24 13:23:40 +02:00
|
|
|
qDebug().noquote() << log;
|
2022-01-08 12:23:46 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-08-28 19:21:19 +03:00
|
|
|
case VerboseLvl::Info:
|
2020-04-04 15:42:56 +03:00
|
|
|
default: {
|
2024-06-24 13:23:40 +02:00
|
|
|
qInfo().noquote() << log;
|
2020-04-04 15:42:56 +03:00
|
|
|
break;
|
2019-03-28 18:58:36 +03:00
|
|
|
}
|
2022-08-28 19:21:19 +03:00
|
|
|
|
2020-04-04 15:42:56 +03:00
|
|
|
}
|
|
|
|
|
2019-01-02 13:42:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-22 14:21:43 +03:00
|
|
|
|
2020-04-14 17:57:54 +03:00
|
|
|
VerboseLvl Params::getVerboseLvl() {
|
|
|
|
return static_cast<VerboseLvl>(getArg("verbose", DEFAULT_VERBOSE_LVL).toInt());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Params::isDebug() {
|
|
|
|
return getVerboseLvl() >= VerboseLvl::Debug;
|
|
|
|
}
|
|
|
|
|
2021-01-24 14:04:31 +03:00
|
|
|
bool Params::isDebugBuild() {
|
|
|
|
#ifdef QT_DEBUG
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-07-28 13:17:26 +03:00
|
|
|
void Params::showHelp() {
|
|
|
|
|
|
|
|
if (inputOptions.size() > 1) {
|
|
|
|
showHelpForInputOptions();
|
|
|
|
} else {
|
2021-07-28 12:38:44 +03:00
|
|
|
Help::print(userHelp);
|
2021-07-28 13:17:26 +03:00
|
|
|
}
|
2021-07-28 12:38:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void Params::showHelpForInputOptions() {
|
|
|
|
Help::print(getHelpOfInputOptions());
|
|
|
|
}
|
|
|
|
|
|
|
|
Help::Section Params::getHelpOfInputOptions() {
|
|
|
|
|
|
|
|
if (inputOptions.size() <= 1 ) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Help::Options help;
|
2023-10-28 21:31:17 +02:00
|
|
|
for (const auto &optionData: std::as_const(inputOptions) ) {
|
2021-07-28 12:38:44 +03:00
|
|
|
help.unite(optionData.toHelp());
|
|
|
|
}
|
|
|
|
|
|
|
|
return Help::Section{{"Information about using options", help}};
|
|
|
|
}
|
|
|
|
|
|
|
|
const Help::Section &Params::getHelp() {
|
|
|
|
return userHelp;
|
2020-02-18 22:28:17 +03:00
|
|
|
}
|
|
|
|
|
2021-04-26 11:27:19 +03:00
|
|
|
const QMap<QString, QString>& Params::getUserParamsMap() {
|
|
|
|
return params;
|
2020-04-18 21:28:35 +03:00
|
|
|
}
|
|
|
|
|
2020-05-17 23:21:12 +03:00
|
|
|
void Params::clearParsedData() {
|
|
|
|
params.clear();
|
2021-04-26 11:27:19 +03:00
|
|
|
appPath = "";
|
|
|
|
appName = "";
|
2020-05-17 23:21:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Params::getCurrentExecutable() {
|
2021-04-26 11:27:19 +03:00
|
|
|
return getCurrentExecutableDir() + "/" + appName;
|
2020-09-28 23:42:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
QString Params::getCurrentExecutableDir() {
|
2021-04-26 11:27:19 +03:00
|
|
|
return appPath;
|
2020-05-17 23:21:12 +03:00
|
|
|
}
|
|
|
|
|
2021-07-27 17:24:43 +03:00
|
|
|
OptionsDataList Params::availableArguments() {
|
|
|
|
return OptionsDataList{
|
|
|
|
{
|
|
|
|
"Base Options",
|
|
|
|
OptionData{
|
|
|
|
{"-verbose"}, "(level 1 - 3)", "Shows debug log"
|
|
|
|
}
|
2021-07-28 12:38:44 +03:00
|
|
|
|
2021-07-27 17:24:43 +03:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"Base Options",
|
|
|
|
OptionData{
|
|
|
|
{"-fileLog"}, "(path to file)", "Sets path of log file. Default it is path to executable file with suffix '.log'"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-09-16 12:38:10 +03:00
|
|
|
int Params::size() {
|
|
|
|
return params.size();
|
|
|
|
}
|
|
|
|
|
2022-05-25 18:05:36 +03:00
|
|
|
bool Params::optionsForEach(const QStringList ¶msArray,
|
|
|
|
const OptionsDataList& availableOptions) {
|
|
|
|
|
|
|
|
for (int i = 0 ; i < paramsArray.size(); ++i) {
|
|
|
|
|
|
|
|
QStringList virtualOptionsList = paramsArray[i].split('=');
|
|
|
|
|
|
|
|
if (virtualOptionsList.size() > 1) {
|
|
|
|
return optionsForEach(virtualOptionsList, availableOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto optionData = availableOptions.value(paramsArray[i], {{}});
|
|
|
|
if (!checkOption(optionData, paramsArray[i])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
inputOptions.insert(paramsArray[i], optionData);
|
|
|
|
|
|
|
|
if (paramsArray[i][0] == '-') {
|
|
|
|
|
|
|
|
if (i < (paramsArray.size() - 1) && paramsArray[i + 1][0] != '-') {
|
|
|
|
params[paramsArray[i].mid(1)] = paramsArray[i + 1];
|
|
|
|
i++;
|
|
|
|
} else {
|
2024-06-24 13:23:40 +02:00
|
|
|
qCritical() << "Missing argument for " + paramsArray[i];
|
2022-05-25 18:05:36 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
params[paramsArray[i]] = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-07-26 13:17:06 +03:00
|
|
|
bool Params::parseParams(const int argc, const char *argv[], const OptionsDataList& options) {
|
2019-09-10 18:22:13 +03:00
|
|
|
|
|
|
|
QStringList params;
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
params.push_back(argv[i]);
|
|
|
|
}
|
|
|
|
|
2021-07-26 13:17:06 +03:00
|
|
|
return parseParams(params, options);
|
2019-09-10 18:22:13 +03:00
|
|
|
}
|
|
|
|
|
2021-07-26 13:17:06 +03:00
|
|
|
bool Params::parseParams(int argc, char *argv[], const OptionsDataList& options) {
|
|
|
|
return parseParams(argc, const_cast<const char**>(argv), options);
|
2019-11-21 18:03:13 +03:00
|
|
|
}
|
|
|
|
|
2021-07-26 13:17:06 +03:00
|
|
|
bool Params::parseParams(const QStringList ¶msArray, const OptionsDataList &options) {
|
2018-09-29 15:56:04 +03:00
|
|
|
params.clear();
|
2021-07-26 13:17:06 +03:00
|
|
|
OptionsDataList availableOptions;
|
|
|
|
|
2021-07-27 17:24:43 +03:00
|
|
|
parseAvailableOptions(OptionsDataList{}.unite(options).unite(availableArguments()),
|
|
|
|
&availableOptions,
|
|
|
|
&userHelp);
|
2019-01-27 19:45:30 +03:00
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
char buffer[MAX_PATH];
|
2019-11-01 20:39:44 +03:00
|
|
|
memset(buffer, 0, sizeof buffer);
|
2019-11-01 20:28:17 +03:00
|
|
|
|
2019-01-27 19:45:30 +03:00
|
|
|
GetModuleFileNameA(nullptr, buffer, MAX_PATH);
|
2021-04-26 11:27:19 +03:00
|
|
|
appPath = QFileInfo(buffer).absolutePath();
|
|
|
|
appName = QFileInfo(buffer).fileName();
|
2022-02-09 09:57:01 +03:00
|
|
|
#endif
|
2019-08-22 14:21:43 +03:00
|
|
|
|
2022-02-09 09:57:01 +03:00
|
|
|
#ifdef Q_OS_LINUX
|
2019-01-27 20:14:06 +03:00
|
|
|
char path[2048];
|
2019-11-01 20:28:17 +03:00
|
|
|
memset(path, 0, sizeof path);
|
|
|
|
|
2019-05-10 09:56:07 +03:00
|
|
|
if (readlink("/proc/self/exe", path, 2048) < 0) {
|
2024-06-24 13:23:40 +02:00
|
|
|
qCritical() << "parseParams can't get self path!";
|
2019-05-10 09:56:07 +03:00
|
|
|
return false;
|
|
|
|
}
|
2021-04-26 11:27:19 +03:00
|
|
|
appPath = QFileInfo(path).absolutePath();
|
|
|
|
appName = QFileInfo(path).fileName();
|
2019-08-22 14:21:43 +03:00
|
|
|
|
2022-02-09 09:57:01 +03:00
|
|
|
#endif
|
|
|
|
#ifdef Q_OS_DARWIN
|
2024-08-02 12:37:38 +03:00
|
|
|
uint32_t size = 0;
|
|
|
|
_NSGetExecutablePath(nullptr, &size); // request to buffer size
|
|
|
|
std::vector<char> buffer(size);
|
|
|
|
if (_NSGetExecutablePath(buffer.data(), &size) == 0) {
|
|
|
|
appPath = QString::fromUtf8(buffer.data());
|
|
|
|
} else {
|
|
|
|
appPath = QString();
|
|
|
|
}
|
|
|
|
|
2022-02-09 09:57:01 +03:00
|
|
|
appName = QCoreApplication::applicationName();
|
2019-01-27 19:45:30 +03:00
|
|
|
#endif
|
|
|
|
|
2021-04-26 11:27:19 +03:00
|
|
|
if (!appPath.size()) {
|
2019-01-27 19:45:30 +03:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-29 15:56:04 +03:00
|
|
|
|
2022-05-25 18:05:36 +03:00
|
|
|
if (!optionsForEach(paramsArray, availableOptions)) {
|
|
|
|
return false;
|
2018-09-29 15:56:04 +03:00
|
|
|
}
|
|
|
|
|
2021-02-22 10:05:52 +08:00
|
|
|
printWorkingOptions();
|
|
|
|
|
2018-09-29 15:56:04 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-22 10:05:52 +08:00
|
|
|
void Params::printWorkingOptions() {
|
2024-06-24 13:23:40 +02:00
|
|
|
qDebug() << "--- Working options table start ---";
|
2021-02-22 10:05:52 +08:00
|
|
|
|
2021-03-26 17:18:29 +03:00
|
|
|
QMap<QString, QString>::const_iterator iter = params.constBegin();
|
2021-02-22 10:05:52 +08:00
|
|
|
while (iter != params.constEnd()) {
|
|
|
|
|
|
|
|
QString row = QString{"Option[%0]"}.arg(iter.key());
|
|
|
|
|
2021-03-26 17:18:29 +03:00
|
|
|
QString value = iter.value();
|
2021-02-22 10:05:52 +08:00
|
|
|
if (!value.isEmpty()) {
|
|
|
|
row += QString{": %1"}.arg(value);
|
|
|
|
}
|
|
|
|
|
2024-06-24 13:23:40 +02:00
|
|
|
qDebug() << row;
|
2021-02-22 10:05:52 +08:00
|
|
|
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
2024-06-24 13:23:40 +02:00
|
|
|
qDebug() << "--- Working options table end ---";
|
2021-02-22 10:05:52 +08:00
|
|
|
}
|
|
|
|
|
2021-07-28 12:38:44 +03:00
|
|
|
bool Params::checkOption(const OptionData& optionData, const QString& rawOptionName) {
|
|
|
|
|
2022-05-25 18:05:36 +03:00
|
|
|
#ifndef QA_ALLOW_NOT_SUPPORTED_OPTIONS
|
2021-07-28 12:38:44 +03:00
|
|
|
if (!optionData.isValid()) {
|
2024-06-24 13:23:40 +02:00
|
|
|
|
|
|
|
qCritical() << QString("The '%0' option not exists!"
|
|
|
|
" You use wrong option name,"
|
|
|
|
" please check the help before run your commnad.").
|
|
|
|
arg(rawOptionName);
|
|
|
|
|
2021-07-28 12:38:44 +03:00
|
|
|
return false;
|
|
|
|
}
|
2022-05-25 18:05:36 +03:00
|
|
|
#else
|
|
|
|
Q_UNUSED(rawOptionName);
|
|
|
|
#endif
|
2021-07-28 12:38:44 +03:00
|
|
|
|
|
|
|
if (optionData.isDepricated()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (optionData.isRemoved()) {
|
2024-06-24 13:23:40 +02:00
|
|
|
qCritical() << optionData.depricatedMsg();
|
|
|
|
|
2021-07-28 12:38:44 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-06-24 13:23:40 +02:00
|
|
|
qWarning() << QString("The %0 option(s) marked as deprecated! "
|
|
|
|
"And most likely will be removed in next release.").
|
|
|
|
arg(optionData.names().join("/"));
|
2022-11-05 15:15:57 +03:00
|
|
|
|
2024-06-24 13:23:40 +02:00
|
|
|
qWarning() << QString("Option message: %0").arg(optionData.depricatedMsg());
|
2022-11-05 15:15:57 +03:00
|
|
|
|
2021-07-28 12:38:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-07-26 13:17:06 +03:00
|
|
|
void Params::parseAvailableOptions(const OptionsDataList &availableOptionsListIn,
|
|
|
|
OptionsDataList *availableOptionsListOut,
|
|
|
|
Help::Section *helpOut) {
|
|
|
|
|
|
|
|
if (!(availableOptionsListOut && helpOut))
|
|
|
|
return;
|
|
|
|
|
2021-07-28 12:38:44 +03:00
|
|
|
helpOut->clear();
|
|
|
|
|
2021-07-27 17:24:43 +03:00
|
|
|
QHash<QString, Help::Options> options;
|
2021-07-26 13:17:06 +03:00
|
|
|
for (auto it = availableOptionsListIn.begin(); it != availableOptionsListIn.end(); ++it) {
|
|
|
|
|
|
|
|
if (availableOptionsListOut) {
|
2023-10-28 21:31:17 +02:00
|
|
|
for (const auto &name : std::as_const(it.value().names())) {
|
2021-07-27 17:24:43 +03:00
|
|
|
availableOptionsListOut->insert(name, it.value());
|
|
|
|
}
|
2021-07-26 13:17:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (helpOut) {
|
2021-07-27 17:24:43 +03:00
|
|
|
options[it.key()].unite(it.value().toHelp());
|
2021-07-26 13:17:06 +03:00
|
|
|
}
|
|
|
|
}
|
2021-07-27 17:24:43 +03:00
|
|
|
|
|
|
|
for (auto it = options.begin(); it != options.end(); ++it) {
|
|
|
|
helpOut->insert(it.key(), it.value());
|
|
|
|
}
|
2021-07-26 13:17:06 +03:00
|
|
|
}
|
|
|
|
|
2021-03-26 17:18:29 +03:00
|
|
|
QString Params::getArg(const QString& key,const QString& def) {
|
2019-08-26 21:15:34 +03:00
|
|
|
return params.value(key, def);
|
2018-09-29 15:56:04 +03:00
|
|
|
}
|
2019-02-02 16:01:28 +03:00
|
|
|
|
2021-03-26 17:18:29 +03:00
|
|
|
void Params::setArg(const QString &key, const QString &val) {
|
2019-02-02 16:01:28 +03:00
|
|
|
params.insert(key, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Params::setEnable(const QString &key, bool enable) {
|
|
|
|
if (enable) {
|
|
|
|
params.insert(key, "");
|
|
|
|
} else {
|
|
|
|
params.remove(key);
|
|
|
|
}
|
|
|
|
}
|