Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | /* |
43 | config.cpp |
44 | */ |
45 | |
46 | #include <QDir> |
47 | #include <QVariant> |
48 | #include <QFile> |
49 | #include <QTemporaryFile> |
50 | #include <QTextStream> |
51 | #include <qdebug.h> |
52 | #include "config.h" |
53 | #include <stdlib.h> |
54 | |
55 | QT_BEGIN_NAMESPACE |
56 | |
57 | /* |
58 | An entry on the MetaStack. |
59 | */ |
60 | class MetaStackEntry |
61 | { |
62 | public: |
63 | void open(); |
64 | void close(); |
65 | |
66 | QStringList accum; |
67 | QStringList next; |
68 | }; |
69 | |
70 | /* |
71 | */ |
72 | void MetaStackEntry::open() |
73 | { |
74 | next.append(QString()); |
75 | } |
76 | |
77 | /* |
78 | */ |
79 | void MetaStackEntry::close() |
80 | { |
81 | accum += next; |
82 | next.clear(); |
83 | } |
84 | |
85 | /* |
86 | ### |
87 | */ |
88 | class MetaStack : private QStack<MetaStackEntry> |
89 | { |
90 | public: |
91 | MetaStack(); |
92 | |
93 | void process(QChar ch, const Location& location); |
94 | QStringList getExpanded(const Location& location); |
95 | }; |
96 | |
97 | MetaStack::MetaStack() |
98 | { |
99 | push(MetaStackEntry()); |
100 | top().open(); |
101 | } |
102 | |
103 | void MetaStack::process(QChar ch, const Location& location) |
104 | { |
105 | if (ch == QLatin1Char( |
106 | push(MetaStackEntry()); |
107 | top().open(); |
108 | } |
109 | else if (ch == QLatin1Char( |
110 | if (count() == 1) |
111 | location.fatal(tr("Unexpected '}'")); |
112 | |
113 | top().close(); |
114 | QStringList suffixes = pop().accum; |
115 | QStringList prefixes = top().next; |
116 | |
117 | top().next.clear(); |
118 | QStringList::ConstIterator pre = prefixes.begin(); |
119 | while (pre != prefixes.end()) { |
120 | QStringList::ConstIterator suf = suffixes.begin(); |
121 | while (suf != suffixes.end()) { |
122 | top().next << (*pre + *suf); |
123 | ++suf; |
124 | } |
125 | ++pre; |
126 | } |
127 | } |
128 | else if (ch == QLatin1Char( |
129 | top().close(); |
130 | top().open(); |
131 | } |
132 | else { |
133 | QStringList::Iterator pre = top().next.begin(); |
134 | while (pre != top().next.end()) { |
135 | *pre += ch; |
136 | ++pre; |
137 | } |
138 | } |
139 | } |
140 | |
141 | QStringList MetaStack::getExpanded(const Location& location) |
142 | { |
143 | if (count() > 1) |
144 | location.fatal(tr("Missing '}'")); |
145 | |
146 | top().close(); |
147 | return top().accum; |
148 | } |
149 | |
150 | QT_STATIC_CONST_IMPL QString Config::dot = QLatin1String("."); |
151 | QMap<QString, QString> Config::extractedDirs; |
152 | int Config::numInstances; |
153 | |
154 | /*! |
155 | \class Config |
156 | \brief The Config class contains the configuration variables |
157 | for controlling how qdoc produces documentation. |
158 | |
159 | Its load() function, reads, parses, and processes a qdocconf file. |
160 | */ |
161 | |
162 | /*! |
163 | The constructor sets the \a programName and initializes all |
164 | internal state variables to empty values. |
165 | */ |
166 | Config::Config(const QString& programName) |
167 | : prog(programName) |
168 | { |
169 | loc = Location::null; |
170 | lastLoc = Location::null; |
171 | locMap.clear(); |
172 | stringValueMap.clear(); |
173 | stringListValueMap.clear(); |
174 | numInstances++; |
175 | } |
176 | |
177 | /*! |
178 | The destructor has nothing special to do. |
179 | */ |
180 | Config::~Config() |
181 | { |
182 | } |
183 | |
184 | /*! |
185 | Loads and parses the qdoc configuration file \a fileName. |
186 | This function calls the other load() function, which does |
187 | the loading, parsing, and processing of the configuration |
188 | file. |
189 | |
190 | Intializes the location variables returned by location() |
191 | and lastLocation(). |
192 | */ |
193 | void Config::load(const QString& fileName) |
194 | { |
195 | load(Location::null, fileName); |
196 | if (loc.isEmpty()) { |
197 | loc = Location(fileName); |
198 | } |
199 | else { |
200 | loc.setEtc(true); |
201 | } |
202 | lastLoc = Location::null; |
203 | } |
204 | |
205 | /*! |
206 | Writes the qdoc configuration data to the named file. |
207 | The previous contents of the file are overwritten. |
208 | */ |
209 | void Config::unload(const QString& fileName) |
210 | { |
211 | |
212 | QStringMultiMap::ConstIterator v = stringValueMap.begin(); |
213 | while (v != stringValueMap.end()) { |
214 | qDebug() << v.key() << " = "<< v.value(); |
215 | #if 0 |
216 | if (v.key().startsWith(varDot)) { |
217 | QString subVar = v.key().mid(varDot.length()); |
218 | int dot = subVar.indexOf(QLatin1Char( |
219 | if (dot != -1) |
220 | subVar.truncate(dot); |
221 | t.insert(subVar,v.value()); |
222 | } |
223 | #endif |
224 | ++v; |
225 | } |
226 | qDebug() << "fileName:"<< fileName; |
227 | } |
228 | |
229 | /*! |
230 | Joins all the strings in \a values into a single string with the |
231 | individual \a values separated by ' '. Then it inserts the result |
232 | into the string list map with \a var as the key. |
233 | |
234 | It also inserts the \a values string list into a separate map, |
235 | also with \a var as the key. |
236 | */ |
237 | void Config::setStringList(const QString& var, const QStringList& values) |
238 | { |
239 | stringValueMap[var] = values.join(QLatin1String(" ")); |
240 | stringListValueMap[var] = values; |
241 | } |
242 | |
243 | /*! |
244 | Looks up the configuarion variable \a var in the string |
245 | map and returns the boolean value. |
246 | */ |
247 | bool Config::getBool(const QString& var) const |
248 | { |
249 | return QVariant(getString(var)).toBool(); |
250 | } |
251 | |
252 | /*! |
253 | Looks up the configuration variable \a var in the string list |
254 | map. Iterates through the string list found, interpreting each |
255 | string in the list as an integer and adding it to a total sum. |
256 | Returns the sum. |
257 | */ |
258 | int Config::getInt(const QString& var) const |
259 | { |
260 | QStringList strs = getStringList(var); |
261 | QStringList::ConstIterator s = strs.begin(); |
262 | int sum = 0; |
263 | |
264 | while (s != strs.end()) { |
265 | sum += (*s).toInt(); |
266 | ++s; |
267 | } |
268 | return sum; |
269 | } |
270 | |
271 | /*! |
272 | First, this function looks up the configuration variable \a var |
273 | in the location map and, if found, sets the internal variable |
274 | \c{lastLoc} to the Location that \a var maps to. |
275 | |
276 | Then it looks up the configuration variable \a var in the string |
277 | map, and returns the string that \a var maps to. |
278 | */ |
279 | QString Config::getString(const QString& var) const |
280 | { |
281 | if (!locMap[var].isEmpty()) |
282 | (Location&) lastLoc = locMap[var]; |
283 | return stringValueMap[var]; |
284 | } |
285 | |
286 | /*! |
287 | Looks up the configuration variable \a var in the string |
288 | list map, converts the string list it maps to into a set |
289 | of strings, and returns the set. |
290 | */ |
291 | QSet<QString> Config::getStringSet(const QString& var) const |
292 | { |
293 | return QSet<QString>::fromList(getStringList(var)); |
294 | } |
295 | |
296 | /*! |
297 | First, this function looks up the configuration variable \a var |
298 | in the location map and, if found, sets the internal variable |
299 | \c{lastLoc} the Location that \a var maps to. |
300 | |
301 | Then it looks up the configuration variable \a var in the string |
302 | list map, and returns the string list that \a var maps to. |
303 | */ |
304 | QStringList Config::getStringList(const QString& var) const |
305 | { |
306 | if (!locMap[var].isEmpty()) |
307 | (Location&) lastLoc = locMap[var]; |
308 | return stringListValueMap[var]; |
309 | } |
310 | |
311 | /*! |
312 | Calls getRegExpList() with the control variable \a var and |
313 | iterates through the resulting list of regular expressions, |
314 | concatening them with some extras characters to form a single |
315 | QRegExp, which is returned/ |
316 | |
317 | \sa getRegExpList() |
318 | */ |
319 | QRegExp Config::getRegExp(const QString& var) const |
320 | { |
321 | QString pattern; |
322 | QList<QRegExp> subRegExps = getRegExpList(var); |
323 | QList<QRegExp>::ConstIterator s = subRegExps.begin(); |
324 | |
325 | while (s != subRegExps.end()) { |
326 | if (!(*s).isValid()) |
327 | return *s; |
328 | if (!pattern.isEmpty()) |
329 | pattern += QLatin1Char( |
330 | pattern += QLatin1String("(?:") + (*s).pattern() + QLatin1Char( |
331 | ++s; |
332 | } |
333 | if (pattern.isEmpty()) |
334 | pattern = QLatin1String("$x"); // cannot match |
335 | return QRegExp(pattern); |
336 | } |
337 | |
338 | /*! |
339 | Looks up the configuration variable \a var in the string list |
340 | map, converts the string list to a list of regular expressions, |
341 | and returns it. |
342 | */ |
343 | QList<QRegExp> Config::getRegExpList(const QString& var) const |
344 | { |
345 | QStringList strs = getStringList(var); |
346 | QStringList::ConstIterator s = strs.begin(); |
347 | QList<QRegExp> regExps; |
348 | |
349 | while (s != strs.end()) { |
350 | regExps += QRegExp(*s); |
351 | ++s; |
352 | } |
353 | return regExps; |
354 | } |
355 | |
356 | /*! |
357 | This function is slower than it could be. What it does is |
358 | find all the keys that begin with \a var + dot and return |
359 | the matching keys in a set, stripped of the matching prefix |
360 | and dot. |
361 | */ |
362 | QSet<QString> Config::subVars(const QString& var) const |
363 | { |
364 | QSet<QString> result; |
365 | QString varDot = var + QLatin1Char( |
366 | QStringMultiMap::ConstIterator v = stringValueMap.begin(); |
367 | while (v != stringValueMap.end()) { |
368 | if (v.key().startsWith(varDot)) { |
369 | QString subVar = v.key().mid(varDot.length()); |
370 | int dot = subVar.indexOf(QLatin1Char( |
371 | if (dot != -1) |
372 | subVar.truncate(dot); |
373 | result.insert(subVar); |
374 | } |
375 | ++v; |
376 | } |
377 | return result; |
378 | } |
379 | |
380 | /*! |
381 | Same as subVars(), but in this case we return a string map |
382 | with the matching keys (stripped of the prefix \a var and |
383 | mapped to their values. The pairs are inserted into \a t |
384 | */ |
385 | void Config::subVarsAndValues(const QString& var, QStringMultiMap& t) const |
386 | { |
387 | QString varDot = var + QLatin1Char( |
388 | QStringMultiMap::ConstIterator v = stringValueMap.begin(); |
389 | while (v != stringValueMap.end()) { |
390 | if (v.key().startsWith(varDot)) { |
391 | QString subVar = v.key().mid(varDot.length()); |
392 | int dot = subVar.indexOf(QLatin1Char( |
393 | if (dot != -1) |
394 | subVar.truncate(dot); |
395 | t.insert(subVar,v.value()); |
396 | } |
397 | ++v; |
398 | } |
399 | } |
400 | |
401 | /*! |
402 | Builds and returns a list of file pathnames for the file |
403 | type specified by \a filesVar (e.g. "headers" or "sources"). |
404 | The files are found in the directories specified by |
405 | \a dirsVar, and they are filtered by \a defaultNameFilter |
406 | if a better filter can't be constructed from \a filesVar. |
407 | The directories in \a excludedDirs are avoided. |
408 | */ |
409 | QStringList Config::getAllFiles(const QString &filesVar, |
410 | const QString &dirsVar, |
411 | const QSet<QString> &excludedDirs) |
412 | { |
413 | QStringList result = getStringList(filesVar); |
414 | QStringList dirs = getStringList(dirsVar); |
415 | |
416 | QString nameFilter = getString(filesVar + dot + QLatin1String(CONFIG_FILEEXTENSIONS)); |
417 | |
418 | QStringList::ConstIterator d = dirs.begin(); |
419 | while (d != dirs.end()) { |
420 | result += getFilesHere(*d, nameFilter, excludedDirs); |
421 | ++d; |
422 | } |
423 | return result; |
424 | } |
425 | |
426 | /*! |
427 | \a fileName is the path of the file to find. |
428 | |
429 | \a files and \a dirs are the lists where we must find the |
430 | components of \a fileName. |
431 | |
432 | \a location is used for obtaining the file and line numbers |
433 | for report qdoc errors. |
434 | */ |
435 | QString Config::findFile(const Location& location, |
436 | const QStringList& files, |
437 | const QStringList& dirs, |
438 | const QString& fileName, |
439 | QString& userFriendlyFilePath) |
440 | { |
441 | if (fileName.isEmpty() || fileName.startsWith(QLatin1Char( |
442 | userFriendlyFilePath = fileName; |
443 | return fileName; |
444 | } |
445 | |
446 | QFileInfo fileInfo; |
447 | QStringList components = fileName.split(QLatin1Char( |
448 | QString firstComponent = components.first(); |
449 | |
450 | QStringList::ConstIterator f = files.begin(); |
451 | while (f != files.end()) { |
452 | if (*f == firstComponent || |
453 | (*f).endsWith(QLatin1Char( |
454 | fileInfo.setFile(*f); |
455 | if (!fileInfo.exists()) |
456 | location.fatal(tr("File '%1' does not exist").arg(*f)); |
457 | break; |
458 | } |
459 | ++f; |
460 | } |
461 | |
462 | if (fileInfo.fileName().isEmpty()) { |
463 | QStringList::ConstIterator d = dirs.begin(); |
464 | while (d != dirs.end()) { |
465 | fileInfo.setFile(QDir(*d), firstComponent); |
466 | if (fileInfo.exists()) { |
467 | break; |
468 | } |
469 | ++d; |
470 | } |
471 | } |
472 | |
473 | userFriendlyFilePath = QString(); |
474 | if (!fileInfo.exists()) |
475 | return QString(); |
476 | |
477 | QStringList::ConstIterator c = components.begin(); |
478 | for (;;) { |
479 | bool isArchive = (c != components.end() - 1); |
480 | QString userFriendly = *c; |
481 | |
482 | userFriendlyFilePath += userFriendly; |
483 | |
484 | if (isArchive) { |
485 | QString extracted = extractedDirs[fileInfo.filePath()]; |
486 | ++c; |
487 | fileInfo.setFile(QDir(extracted), *c); |
488 | } |
489 | else |
490 | break; |
491 | |
492 | userFriendlyFilePath += "?"; |
493 | } |
494 | return fileInfo.filePath(); |
495 | } |
496 | |
497 | /*! |
498 | */ |
499 | QString Config::findFile(const Location& location, |
500 | const QStringList& files, |
501 | const QStringList& dirs, |
502 | const QString& fileBase, |
503 | const QStringList& fileExtensions, |
504 | QString& userFriendlyFilePath) |
505 | { |
506 | QStringList::ConstIterator e = fileExtensions.begin(); |
507 | while (e != fileExtensions.end()) { |
508 | QString filePath = findFile(location, |
509 | files, |
510 | dirs, |
511 | fileBase + "."+ *e, |
512 | userFriendlyFilePath); |
513 | if (!filePath.isEmpty()) |
514 | return filePath; |
515 | ++e; |
516 | } |
517 | return findFile(location, files, dirs, fileBase, userFriendlyFilePath); |
518 | } |
519 | |
520 | /*! |
521 | Copies the \a sourceFilePath to the file name constructed by |
522 | concatenating \a targetDirPath and \a userFriendlySourceFilePath. |
523 | \a location is for identifying the file and line number where |
524 | a qdoc error occurred. The constructed output file name is |
525 | returned. |
526 | */ |
527 | QString Config::copyFile(const Location& location, |
528 | const QString& sourceFilePath, |
529 | const QString& userFriendlySourceFilePath, |
530 | const QString& targetDirPath) |
531 | { |
532 | QFile inFile(sourceFilePath); |
533 | if (!inFile.open(QFile::ReadOnly)) { |
534 | location.fatal(tr("Cannot open input file '%1': %2") |
535 | .arg(inFile.fileName()).arg(inFile.errorString())); |
536 | return ""; |
537 | } |
538 | |
539 | QString outFileName = userFriendlySourceFilePath; |
540 | int slash = outFileName.lastIndexOf("/"); |
541 | if (slash != -1) |
542 | outFileName = outFileName.mid(slash); |
543 | |
544 | QFile outFile(targetDirPath + "/"+ outFileName); |
545 | if (!outFile.open(QFile::WriteOnly)) { |
546 | location.fatal(tr("Cannot open output file '%1': %2") |
547 | .arg(outFile.fileName()).arg(outFile.errorString())); |
548 | return ""; |
549 | } |
550 | |
551 | char buffer[1024]; |
552 | int len; |
553 | while ((len = inFile.read(buffer, sizeof(buffer))) > 0) { |
554 | outFile.write(buffer, len); |
555 | } |
556 | return outFileName; |
557 | } |
558 | |
559 | /*! |
560 | Finds the largest unicode digit in \a value in the range |
561 | 1..7 and returns it. |
562 | */ |
563 | int Config::numParams(const QString& value) |
564 | { |
565 | int max = 0; |
566 | for (int i = 0; i != value.length(); i++) { |
567 | uint c = value[i].unicode(); |
568 | if (c > 0 && c < 8) |
569 | max = qMax(max, (int)c); |
570 | } |
571 | return max; |
572 | } |
573 | |
574 | /*! |
575 | Removes everything from \a dir. This function is recursive. |
576 | It doesn't remove \a dir itself, but if it was called |
577 | recursively, then the caller will remove \a dir. |
578 | */ |
579 | bool Config::removeDirContents(const QString& dir) |
580 | { |
581 | QDir dirInfo(dir); |
582 | QFileInfoList entries = dirInfo.entryInfoList(); |
583 | |
584 | bool ok = true; |
585 | |
586 | QFileInfoList::Iterator it = entries.begin(); |
587 | while (it != entries.end()) { |
588 | if ((*it).isFile()) { |
589 | if (!dirInfo.remove((*it).fileName())) |
590 | ok = false; |
591 | } |
592 | else if ((*it).isDir()) { |
593 | if ((*it).fileName() != "."&& (*it).fileName() != "..") { |
594 | if (removeDirContents((*it).absoluteFilePath())) { |
595 | if (!dirInfo.rmdir((*it).fileName())) |
596 | ok = false; |
597 | } |
598 | else { |
599 | ok = false; |
600 | } |
601 | } |
602 | } |
603 | ++it; |
604 | } |
605 | return ok; |
606 | } |
607 | |
608 | /*! |
609 | Returns true if \a ch is a letter, number, '_', '.', |
610 | '{', '}', or ','. |
611 | */ |
612 | bool Config::isMetaKeyChar(QChar ch) |
613 | { |
614 | return ch.isLetterOrNumber() |
615 | || ch == QLatin1Char( |
616 | || ch == QLatin1Char( |
617 | || ch == QLatin1Char( |
618 | || ch == QLatin1Char( |
619 | || ch == QLatin1Char( |
620 | } |
621 | |
622 | /*! |
623 | Load, parse, and process a qdoc configuration file. This |
624 | function is only called by the other load() function, but |
625 | this one is recursive, i.e., it calls itself when it sees |
626 | an \c{include} statement in the qdog configuration file. |
627 | */ |
628 | void Config::load(Location location, const QString& fileName) |
629 | { |
630 | QRegExp keySyntax("\\w+(?:\\.\\w+)*"); |
631 | |
632 | #define SKIP_CHAR() \ |
633 | do { \ |
634 | location.advance(c); \ |
635 | ++i; \ |
636 | c = text.at(i); \ |
637 | cc = c.unicode(); \ |
638 | } while (0) |
639 | |
640 | #define SKIP_SPACES() \ |
641 | while (c.isSpace() && cc != '\n') \ |
642 | SKIP_CHAR() |
643 | |
644 | #define PUT_CHAR() \ |
645 | word += c; \ |
646 | SKIP_CHAR(); |
647 | |
648 | if (location.depth() > 16) |
649 | location.fatal(tr("Too many nested includes")); |
650 | |
651 | QFile fin(fileName); |
652 | if (!fin.open(QFile::ReadOnly | QFile::Text)) { |
653 | fin.setFileName(fileName + ".qdoc"); |
654 | if (!fin.open(QFile::ReadOnly | QFile::Text)) |
655 | location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString())); |
656 | } |
657 | |
658 | QTextStream stream(&fin); |
659 | stream.setCodec("UTF-8"); |
660 | QString text = stream.readAll(); |
661 | text += QLatin1String("\n\n"); |
662 | text += QChar( |
663 | fin.close(); |
664 | |
665 | location.push(fileName); |
666 | location.start(); |
667 | |
668 | int i = 0; |
669 | QChar c = text.at(0); |
670 | uint cc = c.unicode(); |
671 | while (i < (int) text.length()) { |
672 | if (cc == 0) |
673 | ++i; |
674 | else if (c.isSpace()) { |
675 | SKIP_CHAR(); |
676 | } |
677 | else if (cc == |
678 | do { |
679 | SKIP_CHAR(); |
680 | } while (cc != |
681 | } |
682 | else if (isMetaKeyChar(c)) { |
683 | Location keyLoc = location; |
684 | bool plus = false; |
685 | QString stringValue; |
686 | QStringList stringListValue; |
687 | QString word; |
688 | bool inQuote = false; |
689 | bool prevWordQuoted = true; |
690 | bool metWord = false; |
691 | |
692 | MetaStack stack; |
693 | do { |
694 | stack.process(c, location); |
695 | SKIP_CHAR(); |
696 | } while (isMetaKeyChar(c)); |
697 | |
698 | QStringList keys = stack.getExpanded(location); |
699 | //qDebug() << "KEYS:" << keys; |
700 | SKIP_SPACES(); |
701 | |
702 | if (keys.count() == 1 && keys.first() == "include") { |
703 | QString includeFile; |
704 | |
705 | if (cc != |
706 | location.fatal(tr("Bad include syntax")); |
707 | SKIP_CHAR(); |
708 | SKIP_SPACES(); |
709 | while (!c.isSpace() && cc != |
710 | includeFile += c; |
711 | SKIP_CHAR(); |
712 | } |
713 | SKIP_SPACES(); |
714 | if (cc != |
715 | location.fatal(tr("Bad include syntax")); |
716 | SKIP_CHAR(); |
717 | SKIP_SPACES(); |
718 | if (cc != |
719 | location.fatal(tr("Trailing garbage")); |
720 | |
721 | /* |
722 | Here is the recursive call. |
723 | */ |
724 | load(location, |
725 | QFileInfo(QFileInfo(fileName).dir(), includeFile) |
726 | .filePath()); |
727 | } |
728 | else { |
729 | /* |
730 | It wasn't an include statement, so it;s something else. |
731 | */ |
732 | if (cc == |
733 | plus = true; |
734 | SKIP_CHAR(); |
735 | } |
736 | if (cc != |
737 | location.fatal(tr("Expected '=' or '+=' after key")); |
738 | SKIP_CHAR(); |
739 | SKIP_SPACES(); |
740 | |
741 | for (;;) { |
742 | if (cc == |
743 | int metaCharPos; |
744 | |
745 | SKIP_CHAR(); |
746 | if (cc == |
747 | SKIP_CHAR(); |
748 | } |
749 | else if (cc > |
750 | word += QChar(c.digitValue()); |
751 | SKIP_CHAR(); |
752 | } |
753 | else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) != -1) { |
754 | word += "\a\b\f\n\r\t\v"[metaCharPos]; |
755 | SKIP_CHAR(); |
756 | } |
757 | else { |
758 | PUT_CHAR(); |
759 | } |
760 | } |
761 | else if (c.isSpace() || cc == |
762 | if (inQuote) { |
763 | if (cc == |
764 | location.fatal(tr("Unterminated string")); |
765 | PUT_CHAR(); |
766 | } |
767 | else { |
768 | if (!word.isEmpty()) { |
769 | if (metWord) |
770 | stringValue += QLatin1Char( |
771 | stringValue += word; |
772 | stringListValue << word; |
773 | metWord = true; |
774 | word.clear(); |
775 | prevWordQuoted = false; |
776 | } |
777 | if (cc == |
778 | break; |
779 | SKIP_SPACES(); |
780 | } |
781 | } |
782 | else if (cc == |
783 | if (inQuote) { |
784 | if (!prevWordQuoted) |
785 | stringValue += QLatin1Char( |
786 | stringValue += word; |
787 | if (!word.isEmpty()) |
788 | stringListValue << word; |
789 | metWord = true; |
790 | word.clear(); |
791 | prevWordQuoted = true; |
792 | } |
793 | inQuote = !inQuote; |
794 | SKIP_CHAR(); |
795 | } |
796 | else if (cc == |
797 | QString var; |
798 | SKIP_CHAR(); |
799 | while (c.isLetterOrNumber() || cc == |
800 | var += c; |
801 | SKIP_CHAR(); |
802 | } |
803 | if (!var.isEmpty()) { |
804 | char *val = getenv(var.toLatin1().data()); |
805 | if (val == 0) { |
806 | location.fatal(tr("Environment variable '%1' undefined").arg(var)); |
807 | } |
808 | else { |
809 | word += QString(val); |
810 | } |
811 | } |
812 | } |
813 | else { |
814 | if (!inQuote && cc == |
815 | location.fatal(tr("Unexpected '='")); |
816 | PUT_CHAR(); |
817 | } |
818 | } |
819 | |
820 | QStringList::ConstIterator key = keys.begin(); |
821 | while (key != keys.end()) { |
822 | if (!keySyntax.exactMatch(*key)) |
823 | keyLoc.fatal(tr("Invalid key '%1'").arg(*key)); |
824 | |
825 | if (plus) { |
826 | if (locMap[*key].isEmpty()) { |
827 | locMap[*key] = keyLoc; |
828 | } |
829 | else { |
830 | locMap[*key].setEtc(true); |
831 | } |
832 | if (stringValueMap[*key].isEmpty()) { |
833 | stringValueMap[*key] = stringValue; |
834 | } |
835 | else { |
836 | stringValueMap[*key] += |
837 | QLatin1Char( |
838 | } |
839 | stringListValueMap[*key] += stringListValue; |
840 | } |
841 | else { |
842 | locMap[*key] = keyLoc; |
843 | stringValueMap[*key] = stringValue; |
844 | stringListValueMap[*key] = stringListValue; |
845 | } |
846 | ++key; |
847 | } |
848 | } |
849 | } |
850 | else { |
851 | location.fatal(tr("Unexpected character '%1' at beginning of line") |
852 | .arg(c)); |
853 | } |
854 | } |
855 | } |
856 | |
857 | QStringList Config::getFilesHere(const QString& dir, |
858 | const QString& nameFilter, |
859 | const QSet<QString> &excludedDirs) |
860 | { |
861 | QStringList result; |
862 | if (excludedDirs.contains(dir)) |
863 | return result; |
864 | |
865 | QDir dirInfo(dir); |
866 | QStringList fileNames; |
867 | QStringList::const_iterator fn; |
868 | |
869 | dirInfo.setNameFilters(nameFilter.split( |
870 | dirInfo.setSorting(QDir::Name); |
871 | dirInfo.setFilter(QDir::Files); |
872 | fileNames = dirInfo.entryList(); |
873 | fn = fileNames.constBegin(); |
874 | while (fn != fileNames.constEnd()) { |
875 | if (!fn->startsWith(QLatin1Char( |
876 | result.append(dirInfo.filePath(*fn)); |
877 | ++fn; |
878 | } |
879 | |
880 | dirInfo.setNameFilters(QStringList("*")); |
881 | dirInfo.setFilter(QDir::Dirs|QDir::NoDotAndDotDot); |
882 | fileNames = dirInfo.entryList(); |
883 | fn = fileNames.constBegin(); |
884 | while (fn != fileNames.constEnd()) { |
885 | result += getFilesHere(dirInfo.filePath(*fn), nameFilter, excludedDirs); |
886 | ++fn; |
887 | } |
888 | return result; |
889 | } |
890 | |
891 | QT_END_NAMESPACE |
892 |
Warning: That file was not part of the compilation database. It may have many parsing errors.