QuasarAppLib
params.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2018-2025 QuasarApp.
3 * Distributed under the lgplv3 software license, see the accompanying
4 * Everyone is permitted to copy and distribute verbatim copies
5 * of this license document, but changing it is not allowed.
6*/
7
8#include "params.h"
9#include <QVariantMap>
10#include <QDebug>
11#include <QFileInfo>
12#include <QDateTime>
13#include <QCoreApplication>
14#include "qaglobalutils.h"
15#include <QtLogging>
16
17#ifdef Q_OS_DARWIN
18#include <mach-o/dyld.h>
19#endif
20
21#ifdef Q_OS_WIN
22#include "windows.h"
23#else
24#include <unistd.h>
25#endif
26
27using namespace QuasarAppUtils;
28QMap<QString, QString> Params::params = QMap<QString, QString>();
29QString Params::appPath = "";
30QString Params::appName = "";
31Help::Section Params::userHelp = {};
32OptionsDataList Params::inputOptions = {};
33
34
35bool Params::isEndable(const QString& key) {
36 return params.contains(key);
37}
38
39void Params::log(const QString &log, VerboseLvl vLvl) {
40
41 auto lvl = getVerboseLvl();
42 if (vLvl <= lvl) {
43
44 switch (vLvl) {
45
46 case VerboseLvl::Error:
47 qCritical().noquote() << log;
48 break;
49
50 case VerboseLvl::Warning: {
51 qWarning().noquote() << log;
52 break;
53 }
54 case VerboseLvl::Debug: {
55 qDebug().noquote() << log;
56 break;
57 }
58
59 case VerboseLvl::Info:
60 default: {
61 qInfo().noquote() << log;
62 break;
63 }
64
65 }
66
67 }
68}
69
70
71VerboseLvl Params::getVerboseLvl() {
72 return static_cast<VerboseLvl>(getArg("verbose", DEFAULT_VERBOSE_LVL).toInt());
73}
74
75bool Params::isDebug() {
76 return getVerboseLvl() >= VerboseLvl::Debug;
77}
78
79bool Params::isDebugBuild() {
80#ifdef QT_DEBUG
81 return true;
82#else
83 return false;
84#endif
85}
86
87void Params::showHelp() {
88
89 if (inputOptions.size() > 1) {
90 showHelpForInputOptions();
91 } else {
92 Help::print(userHelp);
93 }
94}
95
96void Params::showHelpForInputOptions() {
97 Help::print(getHelpOfInputOptions());
98}
99
100Help::Section Params::getHelpOfInputOptions() {
101
102 if (inputOptions.size() <= 1 ) {
103 return {};
104 }
105
106 Help::Options help;
107 for (const auto &optionData: std::as_const(inputOptions) ) {
108 help.unite(optionData.toHelp());
109 }
110
111 return Help::Section{{"Information about using options", help}};
112}
113
114const Help::Section &Params::getHelp() {
115 return userHelp;
116}
117
118const QMap<QString, QString>& Params::getUserParamsMap() {
119 return params;
120}
121
122void Params::clearParsedData() {
123 params.clear();
124 appPath = "";
125 appName = "";
126}
127
128QString Params::getCurrentExecutable() {
129 return getCurrentExecutableDir() + "/" + appName;
130}
131
132QString Params::getCurrentExecutableDir() {
133 return appPath;
134}
135
136OptionsDataList Params::availableArguments() {
137 return OptionsDataList{
138 {
139 "Base Options",
141 {"-verbose"}, "(level 1 - 3)", "Shows debug log"
142 }
143
144 },
145 {
146 "Base Options",
148 {"-fileLog"}, "(path to file)", "Sets path of log file. Default it is path to executable file with suffix '.log'"
149 }
150 }
151 };
152}
153
154int Params::size() {
155 return params.size();
156}
157
158bool Params::optionsForEach(const QStringList &paramsArray,
159 const OptionsDataList& availableOptions) {
160
161 for (int i = 0 ; i < paramsArray.size(); ++i) {
162
163 QStringList virtualOptionsList = paramsArray[i].split('=');
164
165 if (virtualOptionsList.size() > 1) {
166 return optionsForEach(virtualOptionsList, availableOptions);
167 }
168
169 auto optionData = availableOptions.value(paramsArray[i], {{}});
170 if (!checkOption(optionData, paramsArray[i])) {
171 return false;
172 }
173
174 inputOptions.insert(paramsArray[i], optionData);
175
176 if (paramsArray[i][0] == '-') {
177
178 if (i < (paramsArray.size() - 1) && paramsArray[i + 1][0] != '-') {
179 params[paramsArray[i].mid(1)] = paramsArray[i + 1];
180 i++;
181 } else {
182 qCritical() << "Missing argument for " + paramsArray[i];
183 return false;
184 }
185 } else {
186 params[paramsArray[i]] = "";
187 }
188 }
189
190 return true;
191}
192
193bool Params::parseParams(const int argc, const char *argv[], const OptionsDataList& options) {
194
195 QStringList params;
196 for (int i = 1; i < argc; i++) {
197 params.push_back(argv[i]);
198 }
199
200 return parseParams(params, options);
201}
202
203bool Params::parseParams(int argc, char *argv[], const OptionsDataList& options) {
204 return parseParams(argc, const_cast<const char**>(argv), options);
205}
206
207bool Params::parseParams(const QStringList &paramsArray, const OptionsDataList &options) {
208 params.clear();
209 OptionsDataList availableOptions;
210
211 parseAvailableOptions(OptionsDataList{}.unite(options).unite(availableArguments()),
212 &availableOptions,
213 &userHelp);
214
215#ifdef Q_OS_WIN
216 char buffer[MAX_PATH];
217 memset(buffer, 0, sizeof buffer);
218
219 GetModuleFileNameA(nullptr, buffer, MAX_PATH);
220 appPath = QFileInfo(buffer).absolutePath();
221 appName = QFileInfo(buffer).fileName();
222#endif
223
224#ifdef Q_OS_LINUX
225 char path[2048];
226 memset(path, 0, sizeof path);
227
228 if (readlink("/proc/self/exe", path, 2048) < 0) {
229 qCritical() << "parseParams can't get self path!";
230 return false;
231 }
232 appPath = QFileInfo(path).absolutePath();
233 appName = QFileInfo(path).fileName();
234
235#endif
236#ifdef Q_OS_DARWIN
237 uint32_t size = 0;
238 _NSGetExecutablePath(nullptr, &size); // request to buffer size
239 std::vector<char> buffer(size);
240 if (_NSGetExecutablePath(buffer.data(), &size) == 0) {
241 appPath = QString::fromUtf8(buffer.data());
242 } else {
243 appPath = QString();
244 }
245
246 appName = QCoreApplication::applicationName();
247#endif
248
249 if (!appPath.size()) {
250 return false;
251 }
252
253 if (!optionsForEach(paramsArray, availableOptions)) {
254 return false;
255 }
256
257 printWorkingOptions();
258
259 return true;
260}
261
262void Params::printWorkingOptions() {
263 qDebug() << "--- Working options table start ---";
264
265 QMap<QString, QString>::const_iterator iter = params.constBegin();
266 while (iter != params.constEnd()) {
267
268 QString row = QString{"Option[%0]"}.arg(iter.key());
269
270 QString value = iter.value();
271 if (!value.isEmpty()) {
272 row += QString{": %1"}.arg(value);
273 }
274
275 qDebug() << row;
276
277 ++iter;
278 }
279
280 qDebug() << "--- Working options table end ---";
281}
282
283bool Params::checkOption(const OptionData& optionData, const QString& rawOptionName) {
284
285#ifndef QA_ALLOW_NOT_SUPPORTED_OPTIONS
286 if (!optionData.isValid()) {
287
288 qCritical() << QString("The '%0' option not exists!"
289 " You use wrong option name,"
290 " please check the help before run your commnad.").
291 arg(rawOptionName);
292
293 return false;
294 }
295#else
296 Q_UNUSED(rawOptionName);
297#endif
298
299 if (optionData.isDepricated()) {
300
301
302
303 if (optionData.isRemoved()) {
304 qCritical() << optionData.depricatedMsg();
305
306 return false;
307 }
308
309 qWarning() << QString("The %0 option(s) marked as deprecated! "
310 "And most likely will be removed in next release.").
311 arg(optionData.names().join("/"));
312
313 qWarning() << QString("Option message: %0").arg(optionData.depricatedMsg());
314
315 }
316
317 return true;
318}
319
320void Params::parseAvailableOptions(const OptionsDataList &availableOptionsListIn,
321 OptionsDataList *availableOptionsListOut,
322 Help::Section *helpOut) {
323
324 if (!(availableOptionsListOut && helpOut))
325 return;
326
327 helpOut->clear();
328
329 QHash<QString, Help::Options> options;
330 for (auto it = availableOptionsListIn.begin(); it != availableOptionsListIn.end(); ++it) {
331
332 if (availableOptionsListOut) {
333 for (const auto &name : std::as_const(it.value().names())) {
334 availableOptionsListOut->insert(name, it.value());
335 }
336 }
337
338 if (helpOut) {
339 options[it.key()].unite(it.value().toHelp());
340 }
341 }
342
343 for (auto it = options.begin(); it != options.end(); ++it) {
344 helpOut->insert(it.key(), it.value());
345 }
346}
347
348QString Params::getArg(const QString& key,const QString& def) {
349 return params.value(key, def);
350}
351
352void Params::setArg(const QString &key, const QString &val) {
353 params.insert(key, val);
354}
355
356void Params::setEnable(const QString &key, bool enable) {
357 if (enable) {
358 params.insert(key, "");
359 } else {
360 params.remove(key);
361 }
362}
The OptionData class contains information about one option.
Definition optiondata.h:21
bool isDepricated() const
isDepricated This method return true if this option is depricated.
bool isValid() const
isValid This method return true if the option is valid. If option do not contain a name then it is in...
const QString & depricatedMsg() const
depricatedWarning This is a message that will be printed as a warning if user will use this option....
bool isRemoved() const
isRemoved This method return true if the option is removed.
const QStringList & names() const
name This is name of the option. It is a required argument and cannot be empty.
QMultiMap< QString, QString > Options
Options this is list of key-descriptions pairs of help. The key is name of the available argument and...
Definition helpdata.h:32
void print(const QString &key, const QString &value, int keyLength)
Definition helpdata.cpp:37
QMultiMap< QString, Options > Section
Section This is list of the help Sections. The one section it is Title of the section and Help::Optio...
Definition helpdata.h:45
The QuasaraAppUtils class This lib include base functions for the all applications of QuasarApp group...
Definition helpdata.cpp:18
QMultiHash< QString, OptionData > OptionsDataList
OptionsList is Hash map of the OptionData items. Where the key it is group name and value it is optio...
Definition optiondata.h:150
VerboseLvl
The VerboseLvl enum uses for sets log level.
Definition params.h:23
#define DEFAULT_VERBOSE_LVL
Definition params.h:40