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

Last change on this file since 1077 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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