ssu
Loading...
Searching...
No Matches
ssuvariables.cpp
Go to the documentation of this file.
1
7
8#include <QStringList>
9#include <QRegExp>
10#include <QStringRef>
11
12#include "ssuvariables_p.h"
13#include "ssulog_p.h"
14
15#include "../constants.h"
16
17SsuVariables::SsuVariables()
18 : QObject()
19{
20}
21
22QString SsuVariables::defaultSection(SsuSettings *settings, const QString &section)
23{
24 QStringList parts = section.split("-");
25
26 if (section.startsWith("var-"))
27 parts.insert(1, "default");
28 else
29 parts.replace(0, "default");
30
31 QString key = parts.join("-");
32
33 if (settings->childGroups().contains(key))
34 return key;
35 else
36 return QString();
37}
38
39QString SsuVariables::resolveString(const QString &pattern, QHash<QString, QString> *variables, int recursionDepth)
40{
41 if (recursionDepth >= SSU_MAX_RECURSION) {
42 return "maximum-recursion-level-reached";
43 }
44
45 QRegExp regex("%\\([^%]*\\)", Qt::CaseSensitive, QRegExp::RegExp2);
46 regex.setMinimal(true);
47
48 int pos = 0;
49 QString result(pattern);
50
51 while ((pos = regex.indexIn(result, pos)) != -1) {
52 QString match = regex.cap(0);
53
54 if (match.contains(":")) {
55 // variable is special, resolve before replacing
56 QString variable = resolveVariable(match, variables);
57 result.replace(match, variable);
58 pos += variable.length();
59 } else {
60 // look up variable name in hashmap, and replace it with stored value,
61 // if found, or ""
62 QString variableName = match;
63 variableName.remove(0, 2);
64 variableName.chop(1);
65 if (variables->contains(variableName)) {
66 result.replace(match, variables->value(variableName));
67 pos += variables->value(variableName).length();
68 } else {
69 result.replace(match, "");
70 }
71 }
72 }
73
74 // check if string still contains variables, and recurse
75 if (regex.indexIn(result, 0) != -1)
76 result = resolveString(result, variables, recursionDepth + 1);
77
78 return result;
79}
80
81QString SsuVariables::resolveVariable(const QString &variable, QHash<QString, QString> *variables)
82{
83 QString variableValue;
84 QString filteredVariable(variable);
85
86 if (filteredVariable.endsWith(")"))
87 filteredVariable.chop(1);
88 if (filteredVariable.startsWith("%("))
89 filteredVariable.remove(0, 2);
90
91 // hunt for your colon
92 int magic = filteredVariable.indexOf(":");
93
94 // seems you misplaced your colon
95 if (magic == -1) return filteredVariable;
96
97 QStringRef variableName(&filteredVariable, 0, magic);
98 QStringRef variableSub(&filteredVariable, magic + 2, filteredVariable.length() - magic - 2);
99
100 // Fill in variable value for later tests, if it exists
101 if (variables->contains(variableName.toString()))
102 variableValue = variables->value(variableName.toString());
103
104 // find the operator who's after your colon
105 QChar op;
106 if (filteredVariable.length() > magic + 1)
107 op = filteredVariable.at(magic + 1);
108
109 switch (op.toLatin1()) {
110 case '-':
111 // substitute default value if variable is empty
112 if (variableValue.isEmpty())
113 return variableSub.toString();
114 break;
115 case '+':
116 // substitute default value if variable is not empty
117 if (!variableValue.isEmpty())
118 return variableSub.toString();
119 break;
120 case '=': {
121 // %(%(foo):=bar?foobar|baz)
122 // if foo == bar then return foobar, else baz
123 QString sub = variableSub.toString();
124 QString a = sub.left(sub.indexOf("?"));
125 QString b = sub.right(sub.length() - sub.indexOf("?") - 1);
126 if (b.indexOf("|") == -1)
127 return b;
128 if (variableName == a)
129 return b.left(b.indexOf("|"));
130 else
131 return b.right(b.length() - b.indexOf("|") - 1);
132 }
133 }
134
135 // no proper substitution found -> return default value
136 return variableValue;
137}
138
140{
141 m_settings = settings;
142}
143
144SsuSettings *SsuVariables::settings()
145{
146 return m_settings;
147}
148
150QVariant SsuVariables::variable(const QString &section, const QString &key)
151{
152 if (m_settings != NULL)
153 return variable(m_settings, section, key);
154 else
155 return QVariant();
156}
157
158QVariant SsuVariables::variable(SsuSettings *settings, const QString &section, const QString &key)
159{
160 QVariant value = readVariable(settings, section, key, 0);
161
162 // first check if the value is defined in the main section, and fall back
163 // to default sections
164 if (value.type() == QMetaType::UnknownType) {
165 QString dSection = defaultSection(settings, section);
166 if (!dSection.isEmpty())
167 value = readVariable(settings, dSection, key, 0, false);
168 }
169
170 return value;
171}
172
173void SsuVariables::variableSection(const QString &section, QHash<QString, QString> *storageHash)
174{
175 if (m_settings != NULL)
176 variableSection(m_settings, section, storageHash);
177}
178
179void SsuVariables::variableSection(SsuSettings *settings, const QString &section, QHash<QString, QString> *storageHash)
180{
181 QString dSection = defaultSection(settings, section);
182 if (dSection.isEmpty()) {
183 readSection(settings, section, storageHash, 0);
184 } else {
185 readSection(settings, dSection, storageHash, 0);
186 readSection(settings, section, storageHash, 0, false);
187 }
188}
189
190// resolve a configuration section, recursively following all 'variables' sections.
191// variables which exist in more than one section will get overwritten when discovered
192// again
193// the section itself gets evaluated at the end, again having a chance to overwrite variables
194void SsuVariables::readSection(SsuSettings *settings, const QString &section,
195 QHash<QString, QString> *storageHash, int recursionDepth,
196 bool logOverride)
197{
198 if (recursionDepth >= SSU_MAX_RECURSION) {
199 SsuLog::instance()->print(LOG_WARNING,
200 QString("Maximum recursion depth for resolving section %1 from %2")
201 .arg(section)
202 .arg(settings->fileName()));
203 return;
204 }
205
206 if (settings->contains(section + "/variables")) {
207 // child should log unless the parent is a default section
208 bool childLogOverride = true;
209 if (section.startsWith("default-") || section.startsWith("var-default-"))
210 childLogOverride = false;
211
212 QStringList sections = settings->value(section + "/variables").toStringList();
213 foreach (const QString &section, sections) {
214 if (section.startsWith("var-"))
215 readSection(settings, section, storageHash, recursionDepth + 1, childLogOverride);
216 else
217 readSection(settings, "var-" + section, storageHash,
218 recursionDepth + 1, childLogOverride);
219 }
220 }
221
222 settings->beginGroup(section);
223 if (settings->group() != section)
224 return;
225
226 QStringList locals;
227 if (settings->contains("local"))
228 locals = settings->value("local").toStringList();
229
230 QStringList keys = settings->allKeys();
231 foreach (const QString &key, keys) {
232 // local variable
233 if (key.startsWith("_"))
234 continue;
235
236 if (locals.contains(key))
237 continue;
238
239 if (key == "variables" || key == "local")
240 continue;
241
242 if (storageHash->contains(key) && logOverride) {
243 SsuLog::instance()->print(LOG_DEBUG,
244 QString("Variable %1 overwritten from %2::%3")
245 .arg(key)
246 .arg(settings->fileName())
247 .arg(section));
248 }
249 storageHash->insert(key, settings->value(key).toString());
250 }
251 settings->endGroup();
252}
253
254QVariant SsuVariables::readVariable(SsuSettings *settings, const QString &section, const QString &key,
255 int recursionDepth, bool logOverride)
256{
257 Q_UNUSED(logOverride)
258
259 QVariant value;
260
261 if (recursionDepth >= SSU_MAX_RECURSION) {
262 SsuLog::instance()->print(LOG_WARNING,
263 QString("Maximum recursion depth for resolving %1 from %2::%3")
264 .arg(key)
265 .arg(settings->fileName())
266 .arg(section));
267 return value;
268 }
269
270 // variables directly in the section take precedence
271 if (settings->contains(section + "/" + key)) {
272 return settings->value(section + "/" + key);
273 }
274
276 if (settings->contains(section + "/variables")) {
277 // child should log unless the parent is a default section
278 bool childLogOverride = true;
279 if (section.startsWith("default-") || section.startsWith("var-default-"))
280 childLogOverride = false;
281
282 QStringList sections = settings->value(section + "/variables").toStringList();
283 foreach (const QString &section, sections) {
284 if (section.startsWith("var-"))
285 value = readVariable(settings, section, key, recursionDepth + 1, childLogOverride);
286 else
287 value = readVariable(settings, "var-" + section, key,
288 recursionDepth + 1, childLogOverride);
289 }
290 }
291
292 return value;
293}
void print(int priority, const QString &message)
Definition ssulog.cpp:27
void setSettings(SsuSettings *settings)
QVariant variable(const QString &section, const QString &key)
void variableSection(const QString &section, QHash< QString, QString > *storageHash)
static QString resolveString(const QString &pattern, QHash< QString, QString > *variables, int recursionDepth=0)
static QString defaultSection(SsuSettings *settings, const QString &section)
static QString resolveVariable(const QString &variable, QHash< QString, QString > *variables)
#define SSU_MAX_RECURSION
Maximum recursion level for resolving variables.
Definition constants.h:26