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
55QT_BEGIN_NAMESPACE
56
57/*
58 An entry on the MetaStack.
59 */
60class MetaStackEntry
61{
62public:
63 void open();
64 void close();
65
66 QStringList accum;
67 QStringList next;
68};
69
70/*
71 */
72void MetaStackEntry::open()
73{
74 next.append(QString());
75}
76
77/*
78 */
79void MetaStackEntry::close()
80{
81 accum += next;
82 next.clear();
83}
84
85/*
86 ###
87*/
88class MetaStack : private QStack<MetaStackEntry>
89{
90public:
91 MetaStack();
92
93 void process(QChar ch, const Location& location);
94 QStringList getExpanded(const Location& location);
95};
96
97MetaStack::MetaStack()
98{
99 push(MetaStackEntry());
100 top().open();
101}
102
103void 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(',') && count() > 1) {
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
141QStringList 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
150QT_STATIC_CONST_IMPL QString Config::dot = QLatin1String(".");
151QMap<QString, QString> Config::extractedDirs;
152int 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 */
166Config::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 */
180Config::~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 */
193void 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 */
209void 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 */
237void 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 */
247bool 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 */
258int 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 */
279QString 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 */
291QSet<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 */
304QStringList 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 */
319QRegExp 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 */
343QList<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 */
362QSet<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 */
385void 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 */
409QStringList 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 */
435QString 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('/') + firstComponent)) {
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 */
499QString 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 */
527QString 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 */
563int 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 */
579bool 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 */
612bool 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 */
628void 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('\0');
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 != '\n');
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 != '#' && 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 != '#' && cc != '\n')
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 == '\n') {
747 SKIP_CHAR();
748 }
749 else if (cc > '0' && cc < '8') {
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 == '\n')
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 == '\n' || 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(' ') + stringValue;
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
857QStringList 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
891QT_END_NAMESPACE
892

Warning: That file was not part of the compilation database. It may have many parsing errors.