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