Changeset View
Changeset View
Standalone View
Standalone View
src/kconfig_compiler/KConfigXmlParser.cpp
- This file was added.
1 | /* This file is part of the KDE libraries | ||||
---|---|---|---|---|---|
2 | Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> | ||||
3 | Copyright (c) 2003 Waldo Bastian <bastian@kde.org> | ||||
4 | Copyright (c) 2003 Zack Rusin <zack@kde.org> | ||||
5 | Copyright (c) 2006 Michaël Larouche <michael.larouche@kdemail.net> | ||||
6 | Copyright (c) 2008 Allen Winter <winter@kde.org> | ||||
7 | Copyright (C) 2020 Tomaz Cananbrava (tcanabrava@kde.org) | ||||
8 | | ||||
9 | This library is free software; you can redistribute it and/or | ||||
10 | modify it under the terms of the GNU Library General Public | ||||
11 | License as published by the Free Software Foundation; either | ||||
12 | version 2 of the License, or (at your option) any later version. | ||||
13 | | ||||
14 | This library is distributed in the hope that it will be useful, | ||||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
17 | Library General Public License for more details. | ||||
18 | | ||||
19 | You should have received a copy of the GNU Library General Public License | ||||
20 | along with this library; see the file COPYING.LIB. If not, write to | ||||
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||||
22 | Boston, MA 02110-1301, USA. | ||||
23 | */ | ||||
24 | | ||||
25 | #include "KConfigXmlParser.h" | ||||
26 | #include "KConfigParameters.h" | ||||
27 | | ||||
28 | #include <QDomAttr> | ||||
29 | #include <QDomElement> | ||||
30 | #include <QDomNode> | ||||
31 | #include <QFile> | ||||
32 | #include <QList> | ||||
33 | #include <QStringList> | ||||
34 | #include <QTextStream> | ||||
35 | | ||||
36 | namespace | ||||
37 | { | ||||
38 | QTextStream cout(stdout); | ||||
39 | QTextStream cerr(stderr); | ||||
40 | } | ||||
41 | | ||||
42 | //TODO: Move preprocessDefault to Header / CPP implementation. | ||||
43 | // it makes no sense for a parser to process those values and generate code. | ||||
44 | | ||||
45 | static void preProcessDefault(QString &defaultValue, const QString &name, | ||||
46 | const QString &type, | ||||
47 | const CfgEntry::Choices &choices, | ||||
48 | QString &code, const KConfigParameters &cfg) | ||||
49 | { | ||||
50 | if (type == QLatin1String("String") && !defaultValue.isEmpty()) { | ||||
51 | defaultValue = literalString(defaultValue); | ||||
52 | | ||||
53 | } else if (type == QLatin1String("Path") && !defaultValue.isEmpty()) { | ||||
54 | defaultValue = literalString(defaultValue); | ||||
55 | } else if (type == QLatin1String("Url") && !defaultValue.isEmpty()) { | ||||
56 | // Use fromUserInput in order to support absolute paths and absolute urls, like KDE4's KUrl(QString) did. | ||||
57 | defaultValue = QLatin1String("QUrl::fromUserInput( ") + literalString(defaultValue) + QLatin1Char(')'); | ||||
58 | } else if ((type == QLatin1String("UrlList") || type == QLatin1String("StringList") || type == QLatin1String("PathList")) && !defaultValue.isEmpty()) { | ||||
59 | QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); | ||||
60 | if (!code.isEmpty()) { | ||||
61 | cpp << endl; | ||||
62 | } | ||||
63 | | ||||
64 | if (type == QLatin1String("UrlList")) { | ||||
65 | cpp << " QList<QUrl> default" << name << ";" << endl; | ||||
66 | } else { | ||||
67 | cpp << " QStringList default" << name << ";" << endl; | ||||
68 | } | ||||
69 | const QStringList defaults = defaultValue.split(QLatin1Char(',')); | ||||
70 | QStringList::ConstIterator it; | ||||
71 | for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) { | ||||
72 | cpp << " default" << name << ".append( "; | ||||
73 | if (type == QLatin1String("UrlList")) { | ||||
74 | cpp << "QUrl::fromUserInput("; | ||||
75 | } | ||||
76 | cpp << "QString::fromUtf8( \"" << *it << "\" ) "; | ||||
77 | if (type == QLatin1String("UrlList")) { | ||||
78 | cpp << ") "; | ||||
79 | } | ||||
80 | cpp << ");" << endl; | ||||
81 | } | ||||
82 | defaultValue = QLatin1String("default") + name; | ||||
83 | | ||||
84 | } else if (type == QLatin1String("Color") && !defaultValue.isEmpty()) { | ||||
85 | const QRegularExpression colorRe(QRegularExpression::anchoredPattern( | ||||
86 | QStringLiteral("\\d+,\\s*\\d+,\\s*\\d+(,\\s*\\d+)?"))); | ||||
87 | | ||||
88 | if (colorRe.match(defaultValue).hasMatch()) { | ||||
89 | defaultValue = QLatin1String("QColor( ") + defaultValue + QLatin1String(" )"); | ||||
90 | } else { | ||||
91 | defaultValue = QLatin1String("QColor( \"") + defaultValue + QLatin1String("\" )"); | ||||
92 | } | ||||
93 | | ||||
94 | } else if (type == QLatin1String("Enum")) { | ||||
95 | QList<CfgEntry::Choice>::ConstIterator it; | ||||
96 | for (it = choices.choices.constBegin(); it != choices.choices.constEnd(); ++it) { | ||||
97 | if ((*it).name == defaultValue) { | ||||
98 | if (cfg.globalEnums && choices.name().isEmpty()) { | ||||
99 | defaultValue.prepend(choices.prefix); | ||||
100 | } else { | ||||
101 | defaultValue.prepend(enumTypeQualifier(name, choices) + choices.prefix); | ||||
102 | } | ||||
103 | break; | ||||
104 | } | ||||
105 | } | ||||
106 | | ||||
107 | } else if (type == QLatin1String("IntList")) { | ||||
108 | QTextStream cpp(&code, QIODevice::WriteOnly | QIODevice::Append); | ||||
109 | if (!code.isEmpty()) { | ||||
110 | cpp << endl; | ||||
111 | } | ||||
112 | | ||||
113 | cpp << " QList<int> default" << name << ";" << endl; | ||||
114 | if (!defaultValue.isEmpty()) { | ||||
115 | const QStringList defaults = defaultValue.split(QLatin1Char(',')); | ||||
116 | QStringList::ConstIterator it; | ||||
117 | for (it = defaults.constBegin(); it != defaults.constEnd(); ++it) { | ||||
118 | cpp << " default" << name << ".append( " << *it << " );" | ||||
119 | << endl; | ||||
120 | } | ||||
121 | } | ||||
122 | defaultValue = QLatin1String("default") + name; | ||||
123 | } | ||||
124 | } | ||||
125 | | ||||
126 | static QString dumpNode(const QDomNode &node) | ||||
127 | { | ||||
128 | QString msg; | ||||
129 | QTextStream s(&msg, QIODevice::WriteOnly); | ||||
130 | node.save(s, 0); | ||||
131 | | ||||
132 | msg = msg.simplified(); | ||||
133 | if (msg.length() > 40) { | ||||
134 | return msg.left(37) + QLatin1String("..."); | ||||
135 | } | ||||
136 | return msg; | ||||
137 | } | ||||
138 | | ||||
139 | void KConfigXmlParser::readParameterFromEntry(CfgEntry &readEntry, const QDomElement &e) | ||||
140 | { | ||||
141 | readEntry.param = e.attribute(QStringLiteral("name")); | ||||
142 | readEntry.paramType = e.attribute(QStringLiteral("type")); | ||||
143 | | ||||
144 | if (readEntry.param.isEmpty()) { | ||||
145 | cerr << "Parameter must have a name: " << dumpNode(e) << endl; | ||||
146 | exit (1); | ||||
147 | } | ||||
148 | | ||||
149 | if (readEntry.paramType.isEmpty()) { | ||||
150 | cerr << "Parameter must have a type: " << dumpNode(e) << endl; | ||||
151 | exit(1); | ||||
152 | } | ||||
153 | | ||||
154 | if ((readEntry.paramType == QLatin1String("Int")) || (readEntry.paramType == QLatin1String("UInt"))) { | ||||
155 | bool ok; | ||||
156 | readEntry.paramMax = e.attribute(QStringLiteral("max")).toInt(&ok); | ||||
157 | if (!ok) { | ||||
158 | cerr << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl; | ||||
159 | exit(1); | ||||
160 | } | ||||
161 | } else if (readEntry.paramType == QLatin1String("Enum")) { | ||||
162 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | ||||
163 | if (e2.tagName() == QLatin1String("values")) { | ||||
164 | for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) { | ||||
165 | if (e3.tagName() == QLatin1String("value")) { | ||||
166 | readEntry.paramValues.append(e3.text()); | ||||
167 | } | ||||
168 | } | ||||
169 | break; | ||||
170 | } | ||||
171 | } | ||||
172 | if (readEntry.paramValues.isEmpty()) { | ||||
173 | cerr << "No values specified for parameter '" << readEntry.param << "'." << endl; | ||||
174 | exit(1); | ||||
175 | } | ||||
176 | readEntry.paramMax = readEntry.paramValues.count() - 1; | ||||
177 | } else { | ||||
178 | cerr << "Parameter '" << readEntry.param << "' has type " << readEntry.paramType | ||||
179 | << " but must be of type int, uint or Enum." << endl; | ||||
180 | exit(1); | ||||
181 | } | ||||
182 | } | ||||
183 | | ||||
184 | bool KConfigXmlParser::hasDefaultCode(CfgEntry &readEntry, const QDomElement &element) | ||||
185 | { | ||||
186 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { | ||||
187 | if (e.attribute(QStringLiteral("param")).isEmpty()) { | ||||
188 | if (e.attribute(QStringLiteral("code")) == QLatin1String("true")) { | ||||
189 | return true; | ||||
190 | } | ||||
191 | } | ||||
192 | } | ||||
193 | return false; | ||||
194 | } | ||||
195 | | ||||
196 | | ||||
197 | void KConfigXmlParser::readChoicesFromEntry(CfgEntry &readEntry, const QDomElement &e) | ||||
198 | { | ||||
199 | QList<CfgEntry::Choice> chlist; | ||||
200 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | ||||
201 | if (e2.tagName() != QLatin1String("choice")) { | ||||
202 | continue; | ||||
203 | } | ||||
204 | CfgEntry::Choice choice; | ||||
205 | choice.name = e2.attribute(QStringLiteral("name")); | ||||
206 | if (choice.name.isEmpty()) { | ||||
207 | cerr << "Tag <choice> requires attribute 'name'." << endl; | ||||
208 | } | ||||
209 | for (QDomElement e3 = e2.firstChildElement(); !e3.isNull(); e3 = e3.nextSiblingElement()) { | ||||
210 | if (e3.tagName() == QLatin1String("label")) { | ||||
211 | choice.label = e3.text(); | ||||
212 | choice.context = e3.attribute(QStringLiteral("context")); | ||||
213 | } | ||||
214 | if (e3.tagName() == QLatin1String("tooltip")) { | ||||
215 | choice.toolTip = e3.text(); | ||||
216 | choice.context = e3.attribute(QStringLiteral("context")); | ||||
217 | } | ||||
218 | if (e3.tagName() == QLatin1String("whatsthis")) { | ||||
219 | choice.whatsThis = e3.text(); | ||||
220 | choice.context = e3.attribute(QStringLiteral("context")); | ||||
221 | } | ||||
222 | } | ||||
223 | chlist.append(choice); | ||||
224 | } | ||||
225 | | ||||
226 | QString name = e.attribute(QStringLiteral("name")); | ||||
227 | QString prefix = e.attribute(QStringLiteral("prefix")); | ||||
228 | | ||||
229 | readEntry.choices = CfgEntry::Choices(chlist, name, prefix); | ||||
230 | } | ||||
231 | | ||||
232 | void KConfigXmlParser::readGroupElements(CfgEntry &readEntry, const QDomElement &element) | ||||
233 | { | ||||
234 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { | ||||
235 | QString tag = e.tagName(); | ||||
236 | if (tag == QLatin1String("label")) { | ||||
237 | readEntry.label = e.text(); | ||||
238 | readEntry.labelContext = e.attribute(QStringLiteral("context")); | ||||
239 | } else if (tag == QLatin1String("tooltip")) { | ||||
240 | readEntry.toolTip = e.text(); | ||||
241 | readEntry.toolTipContext = e.attribute(QStringLiteral("context")); | ||||
242 | } else if (tag == QLatin1String("whatsthis")) { | ||||
243 | readEntry.whatsThis = e.text(); | ||||
244 | readEntry.whatsThisContext = e.attribute(QStringLiteral("context")); | ||||
245 | } else if (tag == QLatin1String("min")) { | ||||
246 | readEntry.min = e.text(); | ||||
247 | } else if (tag == QLatin1String("max")) { | ||||
248 | readEntry.max = e.text(); | ||||
249 | } else if (tag == QLatin1String("code")) { | ||||
250 | readEntry.code = e.text(); | ||||
251 | } else if (tag == QLatin1String("parameter")) { | ||||
252 | readParameterFromEntry(readEntry, e); | ||||
253 | } else if (tag == QLatin1String("default")) { | ||||
254 | if (e.attribute(QStringLiteral("param")).isEmpty()) { | ||||
255 | readEntry.defaultValue = e.text(); | ||||
256 | } | ||||
257 | } else if (tag == QLatin1String("choices")) { | ||||
258 | readChoicesFromEntry(readEntry, e); | ||||
259 | } else if (tag == QLatin1String("emit")) { | ||||
260 | Signal signal; | ||||
261 | signal.name = e.attribute(QStringLiteral("signal")); | ||||
262 | readEntry.signalList.append(signal); | ||||
263 | } | ||||
264 | } | ||||
265 | } | ||||
266 | | ||||
267 | void KConfigXmlParser::createChangedSignal(CfgEntry &readEntry) | ||||
268 | { | ||||
269 | if (cfg.generateProperties && (cfg.allMutators || cfg.mutators.contains(readEntry.name))) { | ||||
270 | Signal s; | ||||
271 | s.name = changeSignalName(readEntry.name); | ||||
272 | s.modify = true; | ||||
273 | readEntry.signalList.append(s); | ||||
274 | } | ||||
275 | } | ||||
276 | | ||||
277 | void KConfigXmlParser::validateNameAndKey(CfgEntry &readEntry, const QDomElement &element) | ||||
278 | { | ||||
279 | bool nameIsEmpty = readEntry.name.isEmpty(); | ||||
280 | if (nameIsEmpty && readEntry.key.isEmpty()) { | ||||
281 | cerr << "Entry must have a name or a key: " << dumpNode(element) << endl; | ||||
282 | exit (1); | ||||
283 | } | ||||
284 | | ||||
285 | if (readEntry.key.isEmpty()) { | ||||
286 | readEntry.key = readEntry.name; | ||||
287 | } | ||||
288 | | ||||
289 | if (nameIsEmpty) { | ||||
290 | readEntry.name = readEntry.key; | ||||
291 | readEntry.name.remove(QLatin1Char(' ')); | ||||
292 | } else if (readEntry.name.contains(QLatin1Char(' '))) { | ||||
293 | cout << "Entry '" << readEntry.name << "' contains spaces! <name> elements can not contain spaces!" << endl; | ||||
294 | readEntry.name.remove(QLatin1Char(' ')); | ||||
295 | } | ||||
296 | | ||||
297 | if (readEntry.name.contains(QStringLiteral("$("))) { | ||||
298 | if (readEntry.param.isEmpty()) { | ||||
299 | cerr << "Name may not be parameterized: " << readEntry.name << endl; | ||||
300 | exit (1); | ||||
301 | } | ||||
302 | } else { | ||||
303 | if (!readEntry.param.isEmpty()) { | ||||
304 | cerr << "Name must contain '$(" << readEntry.param << ")': " << readEntry.name << endl; | ||||
305 | exit (1); | ||||
306 | } | ||||
307 | } | ||||
308 | } | ||||
309 | | ||||
310 | void KConfigXmlParser::readParamDefaultValues(CfgEntry &readEntry, const QDomElement &element) | ||||
311 | { | ||||
312 | if (readEntry.param.isEmpty()) { | ||||
313 | return; | ||||
314 | } | ||||
315 | // Adjust name | ||||
316 | readEntry.paramName = readEntry.name; | ||||
317 | | ||||
318 | readEntry.name.remove(QStringLiteral("$(") + readEntry.param + QLatin1Char(')')); | ||||
319 | // Lookup defaults for indexed entries | ||||
320 | for (int i = 0; i <= readEntry.paramMax; i++) { | ||||
321 | readEntry.paramDefaultValues.append(QString()); | ||||
322 | } | ||||
323 | | ||||
324 | for (QDomElement e = element.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { | ||||
325 | QString tag = e.tagName(); | ||||
326 | if (tag != QLatin1String("default")) { | ||||
327 | continue; | ||||
328 | } | ||||
329 | QString index = e.attribute(QStringLiteral("param")); | ||||
330 | if (index.isEmpty()) { | ||||
331 | continue; | ||||
332 | } | ||||
333 | | ||||
334 | bool ok; | ||||
335 | int i = index.toInt(&ok); | ||||
336 | if (!ok) { | ||||
337 | i = readEntry.paramValues.indexOf(index); | ||||
338 | if (i == -1) { | ||||
339 | cerr << "Index '" << index << "' for default value is unknown." << endl; | ||||
340 | exit (1); | ||||
341 | } | ||||
342 | } | ||||
343 | | ||||
344 | if ((i < 0) || (i > readEntry.paramMax)) { | ||||
345 | cerr << "Index '" << i << "' for default value is out of range [0, " << readEntry.paramMax << "]." << endl; | ||||
346 | exit (1); | ||||
347 | } | ||||
348 | | ||||
349 | QString tmpDefaultValue = e.text(); | ||||
350 | | ||||
351 | if (e.attribute(QStringLiteral("code")) != QLatin1String("true")) { | ||||
352 | preProcessDefault(tmpDefaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg); | ||||
353 | } | ||||
354 | | ||||
355 | readEntry.paramDefaultValues[i] = tmpDefaultValue; | ||||
356 | } | ||||
357 | } | ||||
358 | | ||||
359 | CfgEntry *KConfigXmlParser::parseEntry(const QString &group, const QDomElement &element) | ||||
360 | { | ||||
361 | CfgEntry readEntry; | ||||
362 | readEntry.type = element.attribute(QStringLiteral("type")); | ||||
363 | readEntry.name = element.attribute(QStringLiteral("name")); | ||||
364 | readEntry.key = element.attribute(QStringLiteral("key")); | ||||
365 | readEntry.hidden = element.attribute(QStringLiteral("hidden")) == QLatin1String("true");; | ||||
366 | readEntry.group = group; | ||||
367 | | ||||
368 | const bool nameIsEmpty = readEntry.name.isEmpty(); | ||||
369 | | ||||
370 | readGroupElements(readEntry, element); | ||||
371 | | ||||
372 | createChangedSignal(readEntry); | ||||
373 | validateNameAndKey(readEntry, element); | ||||
374 | | ||||
375 | if (readEntry.label.isEmpty()) { | ||||
376 | readEntry.label = readEntry.key; | ||||
377 | } | ||||
378 | | ||||
379 | if (readEntry.type.isEmpty()) { | ||||
380 | readEntry.type = QStringLiteral("String"); // XXX : implicit type might be bad | ||||
381 | } | ||||
382 | | ||||
383 | readParamDefaultValues(readEntry, element); | ||||
384 | | ||||
385 | if (!mValidNameRegexp.match(readEntry.name).hasMatch()) { | ||||
386 | if (nameIsEmpty) | ||||
387 | cerr << "The key '" << readEntry.key << "' can not be used as name for the entry because " | ||||
388 | "it is not a valid name. You need to specify a valid name for this entry." << endl; | ||||
389 | else { | ||||
390 | cerr << "The name '" << readEntry.name << "' is not a valid name for an entry." << endl; | ||||
391 | } | ||||
392 | exit (1); | ||||
393 | } | ||||
394 | | ||||
395 | if (mAllNames.contains(readEntry.name)) { | ||||
396 | if (nameIsEmpty) | ||||
397 | cerr << "The key '" << readEntry.key << "' can not be used as name for the entry because " | ||||
398 | "it does not result in a unique name. You need to specify a unique name for this entry." << endl; | ||||
399 | else { | ||||
400 | cerr << "The name '" << readEntry.name << "' is not unique." << endl; | ||||
401 | } | ||||
402 | exit (1); | ||||
403 | } | ||||
404 | | ||||
405 | mAllNames.append(readEntry.name); | ||||
406 | | ||||
407 | if (!hasDefaultCode(readEntry, element)) { | ||||
408 | // TODO: Move all the options to CfgEntry. | ||||
409 | preProcessDefault(readEntry.defaultValue, readEntry.name, readEntry.type, readEntry.choices, readEntry.code, cfg); | ||||
410 | } | ||||
411 | | ||||
412 | // TODO: Try to Just return the CfgEntry we populated instead of | ||||
413 | // creating another one to fill the code. | ||||
414 | CfgEntry *result = new CfgEntry(); | ||||
415 | result->group = readEntry.group; | ||||
416 | result->type = readEntry.type; | ||||
417 | result->key = readEntry.key; | ||||
418 | result->name = readEntry.name; | ||||
419 | result->labelContext = readEntry.labelContext; | ||||
420 | result->label = readEntry.label; | ||||
421 | result->toolTipContext = readEntry.toolTipContext; | ||||
422 | result->toolTip = readEntry.toolTip; | ||||
423 | result->whatsThisContext = readEntry.whatsThisContext; | ||||
424 | result->whatsThis = readEntry.whatsThis; | ||||
425 | result->code = readEntry.code; | ||||
426 | result->defaultValue = readEntry.defaultValue; | ||||
427 | result->choices = readEntry.choices; | ||||
428 | result->signalList = readEntry.signalList; | ||||
429 | result->hidden = readEntry.hidden; | ||||
430 | | ||||
431 | if (!readEntry.param.isEmpty()) { | ||||
432 | result->param = readEntry.param; | ||||
433 | result->paramName = readEntry.paramName; | ||||
434 | result->paramType = readEntry.paramType; | ||||
435 | result->paramValues = readEntry.paramValues; | ||||
436 | result->paramDefaultValues = readEntry.paramDefaultValues; | ||||
437 | result->paramMax = readEntry.paramMax; | ||||
438 | } | ||||
439 | result->min = readEntry.min; | ||||
440 | result->max = readEntry.max; | ||||
441 | | ||||
442 | return result; | ||||
443 | } | ||||
444 | | ||||
445 | // TODO: Change the name of the config variable. | ||||
446 | KConfigXmlParser::KConfigXmlParser(const KConfigParameters &cfg, const QString &inputFileName) | ||||
447 | : cfg(cfg), mInputFileName(inputFileName) | ||||
448 | { | ||||
449 | mValidNameRegexp.setPattern(QRegularExpression::anchoredPattern(QStringLiteral("[a-zA-Z_][a-zA-Z0-9_]*"))); | ||||
450 | } | ||||
451 | | ||||
452 | void KConfigXmlParser::start() | ||||
453 | { | ||||
454 | QFile input(mInputFileName); | ||||
455 | QDomDocument doc; | ||||
456 | QString errorMsg; | ||||
457 | int errorRow; | ||||
458 | int errorCol; | ||||
459 | if (!doc.setContent(&input, &errorMsg, &errorRow, &errorCol)) { | ||||
460 | cerr << "Unable to load document." << endl; | ||||
461 | cerr << "Parse error in " << mInputFileName << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl; | ||||
462 | exit (1); | ||||
463 | } | ||||
464 | | ||||
465 | QDomElement cfgElement = doc.documentElement(); | ||||
466 | if (cfgElement.isNull()) { | ||||
467 | cerr << "No document in kcfg file" << endl; | ||||
468 | exit (1); | ||||
469 | } | ||||
470 | | ||||
471 | for (QDomElement element = cfgElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) { | ||||
472 | QString tag = element.tagName(); | ||||
473 | | ||||
474 | if (tag == QLatin1String("include")) { | ||||
475 | readIncludeTag(element); | ||||
476 | } else if (tag == QLatin1String("kcfgfile")) { | ||||
477 | readKcfgfileTag(element); | ||||
478 | } else if (tag == QLatin1String("group")) { | ||||
479 | readGroupTag(element); | ||||
480 | } else if (tag == QLatin1String("signal")) { | ||||
481 | readSignalTag(element); | ||||
482 | } | ||||
483 | } | ||||
484 | } | ||||
485 | | ||||
486 | ParseResult KConfigXmlParser::getParseResult() const | ||||
487 | { | ||||
488 | return mParseResult; | ||||
489 | } | ||||
490 | | ||||
491 | void KConfigXmlParser::readIncludeTag(const QDomElement &e) | ||||
492 | { | ||||
493 | QString includeFile = e.text(); | ||||
494 | if (!includeFile.isEmpty()) { | ||||
495 | mParseResult.includes.append(includeFile); | ||||
496 | } | ||||
497 | } | ||||
498 | | ||||
499 | void KConfigXmlParser::readGroupTag(const QDomElement &e) | ||||
500 | { | ||||
501 | QString group = e.attribute(QStringLiteral("name")); | ||||
502 | if (group.isEmpty()) { | ||||
503 | cerr << "Group without name" << endl; | ||||
504 | exit (1); | ||||
505 | } | ||||
506 | | ||||
507 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | ||||
508 | if (e2.tagName() != QLatin1String("entry")) { | ||||
509 | continue; | ||||
510 | } | ||||
511 | CfgEntry *entry = parseEntry(group, e2); | ||||
512 | if (entry) { | ||||
513 | mParseResult.entries.append(entry); | ||||
514 | } else { | ||||
515 | cerr << "Can not parse entry." << endl; | ||||
516 | exit (1); | ||||
517 | } | ||||
518 | } | ||||
519 | } | ||||
520 | | ||||
521 | void KConfigXmlParser::readKcfgfileTag(const QDomElement &e) | ||||
522 | { | ||||
523 | mParseResult.cfgFileName = e.attribute(QStringLiteral("name")); | ||||
524 | mParseResult.cfgFileNameArg = e.attribute(QStringLiteral("arg")).toLower() == QLatin1String("true"); | ||||
525 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | ||||
526 | if (e2.tagName() == QLatin1String("parameter")) { | ||||
527 | Param p; | ||||
528 | p.name = e2.attribute(QStringLiteral("name")); | ||||
529 | p.type = e2.attribute(QStringLiteral("type")); | ||||
530 | if (p.type.isEmpty()) { | ||||
531 | p.type = QStringLiteral("String"); | ||||
532 | } | ||||
533 | mParseResult.parameters.append(p); | ||||
534 | } | ||||
535 | } | ||||
536 | } | ||||
537 | | ||||
538 | void KConfigXmlParser::readSignalTag(const QDomElement &e) | ||||
539 | { | ||||
540 | QString signalName = e.attribute(QStringLiteral("name")); | ||||
541 | if (signalName.isEmpty()) { | ||||
542 | cerr << "Signal without name." << endl; | ||||
543 | exit (1); | ||||
544 | } | ||||
545 | Signal theSignal; | ||||
546 | theSignal.name = signalName; | ||||
547 | | ||||
548 | for (QDomElement e2 = e.firstChildElement(); !e2.isNull(); e2 = e2.nextSiblingElement()) { | ||||
549 | if (e2.tagName() == QLatin1String("argument")) { | ||||
550 | Param argument; | ||||
551 | argument.type = e2.attribute(QStringLiteral("type")); | ||||
552 | if (argument.type.isEmpty()) { | ||||
553 | cerr << "Signal argument without type." << endl; | ||||
554 | exit (1); | ||||
555 | } | ||||
556 | argument.name= e2.text(); | ||||
557 | theSignal.arguments.append(argument); | ||||
558 | } else if (e2.tagName() == QLatin1String("label")) { | ||||
559 | theSignal.label = e2.text(); | ||||
560 | } | ||||
561 | } | ||||
562 | | ||||
563 | mParseResult.signalList.append(theSignal); | ||||
564 | } |