/* * Copyright (C) 2018-2025 QuasarApp. * 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 #include #include #include #include #include "qaglobalutils.h" #include #ifdef Q_OS_DARWIN #include #endif #ifdef Q_OS_WIN #include "windows.h" #else #include #endif using namespace QuasarAppUtils; QMap Params::params = QMap(); QString Params::appPath = ""; QString Params::appName = ""; Help::Section Params::userHelp = {}; OptionsDataList Params::inputOptions = {}; bool Params::isEndable(const QString& key) { return params.contains(key); } void Params::log(const QString &log, VerboseLvl vLvl) { auto lvl = getVerboseLvl(); if (vLvl <= lvl) { switch (vLvl) { case VerboseLvl::Error: qCritical().noquote() << log; break; case VerboseLvl::Warning: { qWarning().noquote() << log; break; } case VerboseLvl::Debug: { qDebug().noquote() << log; break; } case VerboseLvl::Info: default: { qInfo().noquote() << log; break; } } } } VerboseLvl Params::getVerboseLvl() { return static_cast(getArg("verbose", DEFAULT_VERBOSE_LVL).toInt()); } bool Params::isDebug() { return getVerboseLvl() >= VerboseLvl::Debug; } bool Params::isDebugBuild() { #ifdef QT_DEBUG return true; #else return false; #endif } void Params::showHelp() { if (inputOptions.size() > 1) { showHelpForInputOptions(); } else { Help::print(userHelp); } } void Params::showHelpForInputOptions() { Help::print(getHelpOfInputOptions()); } Help::Section Params::getHelpOfInputOptions() { if (inputOptions.size() <= 1 ) { return {}; } Help::Options help; for (const auto &optionData: std::as_const(inputOptions) ) { help.unite(optionData.toHelp()); } return Help::Section{{"Information about using options", help}}; } const Help::Section &Params::getHelp() { return userHelp; } const QMap& Params::getUserParamsMap() { return params; } void Params::clearParsedData() { params.clear(); appPath = ""; appName = ""; } QString Params::getCurrentExecutable() { return getCurrentExecutableDir() + "/" + appName; } QString Params::getCurrentExecutableDir() { return appPath; } OptionsDataList Params::availableArguments() { return OptionsDataList{ { "Base Options", OptionData{ {"-verbose"}, "(level 1 - 3)", "Shows debug log" } }, { "Base Options", OptionData{ {"-fileLog"}, "(path to file)", "Sets path of log file. Default it is path to executable file with suffix '.log'" } } }; } int Params::size() { return params.size(); } 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 { qCritical() << "Missing argument for " + paramsArray[i]; return false; } } else { params[paramsArray[i]] = ""; } } return true; } bool Params::parseParams(const int argc, const char *argv[], const OptionsDataList& options) { QStringList params; for (int i = 1; i < argc; i++) { params.push_back(argv[i]); } return parseParams(params, options); } bool Params::parseParams(int argc, char *argv[], const OptionsDataList& options) { return parseParams(argc, const_cast(argv), options); } bool Params::parseParams(const QStringList ¶msArray, const OptionsDataList &options) { params.clear(); OptionsDataList availableOptions; parseAvailableOptions(OptionsDataList{}.unite(options).unite(availableArguments()), &availableOptions, &userHelp); #ifdef Q_OS_WIN char buffer[MAX_PATH]; memset(buffer, 0, sizeof buffer); GetModuleFileNameA(nullptr, buffer, MAX_PATH); appPath = QFileInfo(buffer).absolutePath(); appName = QFileInfo(buffer).fileName(); #endif #ifdef Q_OS_LINUX char path[2048]; memset(path, 0, sizeof path); if (readlink("/proc/self/exe", path, 2048) < 0) { qCritical() << "parseParams can't get self path!"; return false; } appPath = QFileInfo(path).absolutePath(); appName = QFileInfo(path).fileName(); #endif #ifdef Q_OS_DARWIN uint32_t size = 0; _NSGetExecutablePath(nullptr, &size); // request to buffer size std::vector buffer(size); if (_NSGetExecutablePath(buffer.data(), &size) == 0) { appPath = QString::fromUtf8(buffer.data()); } else { appPath = QString(); } appName = QCoreApplication::applicationName(); #endif if (!appPath.size()) { return false; } if (!optionsForEach(paramsArray, availableOptions)) { return false; } printWorkingOptions(); return true; } void Params::printWorkingOptions() { qDebug() << "--- Working options table start ---"; QMap::const_iterator iter = params.constBegin(); while (iter != params.constEnd()) { QString row = QString{"Option[%0]"}.arg(iter.key()); QString value = iter.value(); if (!value.isEmpty()) { row += QString{": %1"}.arg(value); } qDebug() << row; ++iter; } qDebug() << "--- Working options table end ---"; } bool Params::checkOption(const OptionData& optionData, const QString& rawOptionName) { #ifndef QA_ALLOW_NOT_SUPPORTED_OPTIONS if (!optionData.isValid()) { qCritical() << QString("The '%0' option not exists!" " You use wrong option name," " please check the help before run your commnad."). arg(rawOptionName); return false; } #else Q_UNUSED(rawOptionName); #endif if (optionData.isDepricated()) { if (optionData.isRemoved()) { qCritical() << optionData.depricatedMsg(); return false; } qWarning() << QString("The %0 option(s) marked as deprecated! " "And most likely will be removed in next release."). arg(optionData.names().join("/")); qWarning() << QString("Option message: %0").arg(optionData.depricatedMsg()); } return true; } void Params::parseAvailableOptions(const OptionsDataList &availableOptionsListIn, OptionsDataList *availableOptionsListOut, Help::Section *helpOut) { if (!(availableOptionsListOut && helpOut)) return; helpOut->clear(); QHash options; for (auto it = availableOptionsListIn.begin(); it != availableOptionsListIn.end(); ++it) { if (availableOptionsListOut) { for (const auto &name : std::as_const(it.value().names())) { availableOptionsListOut->insert(name, it.value()); } } if (helpOut) { options[it.key()].unite(it.value().toHelp()); } } for (auto it = options.begin(); it != options.end(); ++it) { helpOut->insert(it.key(), it.value()); } } QString Params::getArg(const QString& key,const QString& def) { return params.value(key, def); } void Params::setArg(const QString &key, const QString &val) { params.insert(key, val); } void Params::setEnable(const QString &key, bool enable) { if (enable) { params.insert(key, ""); } else { params.remove(key); } }