ssu
ssuvariables.cpp
Go to the documentation of this file.
1 
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 
17 SsuVariables::SsuVariables()
18  : QObject()
19 {
20 }
21 
22 QString 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 
39 QString 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 
81 QString 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 
144 SsuSettings *SsuVariables::settings()
145 {
146  return m_settings;
147 }
148 
150 QVariant 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 
158 QVariant 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 
173 void SsuVariables::variableSection(const QString &section, QHash<QString, QString> *storageHash)
174 {
175  if (m_settings != NULL)
176  variableSection(m_settings, section, storageHash);
177 }
178 
179 void 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
194 void 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 
254 QVariant 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 }
SSU_MAX_RECURSION
#define SSU_MAX_RECURSION
Maximum recursion level for resolving variables.
Definition: constants.h:26
SsuVariables::variableSection
void variableSection(const QString &section, QHash< QString, QString > *storageHash)
Definition: ssuvariables.cpp:173
SsuSettings
Definition: ssusettings_p.h:30
SsuVariables::resolveVariable
static QString resolveVariable(const QString &variable, QHash< QString, QString > *variables)
Definition: ssuvariables.cpp:81
SsuVariables::defaultSection
static QString defaultSection(SsuSettings *settings, const QString &section)
Definition: ssuvariables.cpp:22
ssuvariables_p.h
SsuVariables::variable
QVariant variable(const QString &section, const QString &key)
Definition: ssuvariables.cpp:150
SsuLog::print
void print(int priority, const QString &message)
Definition: ssulog.cpp:27
ssulog_p.h
SsuVariables::setSettings
void setSettings(SsuSettings *settings)
Definition: ssuvariables.cpp:139
SsuVariables::resolveString
static QString resolveString(const QString &pattern, QHash< QString, QString > *variables, int recursionDepth=0)
Definition: ssuvariables.cpp:39