source: trunk/tools/qdoc3/config.cpp@ 348

Last change on this file since 348 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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