1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the tools applications of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
49 #include <qtemporaryfile.h>
50 #include <qtextstream.h>
53 #include "generator.h"
59 An entry on the MetaStack.
73 void MetaStackEntry::open()
75 next.append(QString());
80 void MetaStackEntry::close()
89 class MetaStack : private QStack<MetaStackEntry>
94 void process(QChar ch, const Location& location);
95 QStringList getExpanded(const Location& location);
98 MetaStack::MetaStack()
100 push(MetaStackEntry());
104 void MetaStack::process(QChar ch, const Location& location)
106 if (ch == QLatin1Char('{')) {
107 push(MetaStackEntry());
110 else if (ch == QLatin1Char('}')) {
112 location.fatal(tr("Unexpected '}'"));
115 QStringList suffixes = pop().accum;
116 QStringList prefixes = top().next;
119 QStringList::ConstIterator pre = prefixes.constBegin();
120 while (pre != prefixes.constEnd()) {
121 QStringList::ConstIterator suf = suffixes.constBegin();
122 while (suf != suffixes.constEnd()) {
123 top().next << (*pre + *suf);
129 else if (ch == QLatin1Char(',') && count() > 1) {
134 QStringList::Iterator pre = top().next.begin();
135 while (pre != top().next.end()) {
142 QStringList MetaStack::getExpanded(const Location& location)
145 location.fatal(tr("Missing '}'"));
151 QT_STATIC_CONST_IMPL QString Config::dot = QLatin1String(".");
152 bool Config::generateExamples = true;
153 QString Config::overrideOutputDir;
154 QString Config::installDir;
155 QSet<QString> Config::overrideOutputFormats;
156 QMap<QString, QString> Config::extractedDirs;
157 int Config::numInstances;
158 QStack<QString> Config::workingDirs_;
162 \brief The Config class contains the configuration variables
163 for controlling how qdoc produces documentation.
165 Its load() function, reads, parses, and processes a qdocconf file.
169 The constructor sets the \a programName and initializes all
170 internal state variables to empty values.
172 Config::Config(const QString& programName)
175 loc = Location::null;
176 lastLocation_ = Location::null;
178 stringPairMap.clear();
179 stringListPairMap.clear();
184 The destructor has nothing special to do.
191 Loads and parses the qdoc configuration file \a fileName.
192 This function calls the other load() function, which does
193 the loading, parsing, and processing of the configuration
196 Intializes the location variables returned by location()
199 void Config::load(const QString& fileName)
201 load(Location::null, fileName);
203 loc = Location(fileName);
208 lastLocation_ = Location::null;
212 Writes the qdoc configuration data to the named file.
213 The previous contents of the file are overwritten.
215 void Config::unload(const QString& fileName)
217 QStringPairMap::ConstIterator v = stringPairMap.constBegin();
218 while (v != stringPairMap.constEnd()) {
219 qDebug() << v.key() << " = " << v.value().second;
222 qDebug() << "fileName:" << fileName;
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.
229 It also inserts the \a values string list into a separate map,
230 also with \a var as the key.
232 void Config::setStringList(const QString& var, const QStringList& values)
234 stringPairMap[var].first = QDir::currentPath();
235 stringPairMap[var].second = values.join(QLatin1Char(' '));
236 stringListPairMap[var].first = QDir::currentPath();
237 stringListPairMap[var].second = values;
241 Looks up the configuarion variable \a var in the string
242 map and returns the boolean value.
244 bool Config::getBool(const QString& var) const
246 return QVariant(getString(var)).toBool();
250 Looks up the configuration variable \a var in the string list
251 map. Iterates through the string list found, interpreting each
252 string in the list as an integer and adding it to a total sum.
255 int Config::getInt(const QString& var) const
257 QStringList strs = getStringList(var);
258 QStringList::ConstIterator s = strs.constBegin();
261 while (s != strs.constEnd()) {
269 Function to return the correct outputdir.
270 outputdir can be set using the qdocconf or the command-line
273 QString Config::getOutputDir() const
275 if (overrideOutputDir.isNull())
276 return getString(QLatin1String(CONFIG_OUTPUTDIR));
278 return overrideOutputDir;
282 Function to return the correct outputformats.
283 outputformats can be set using the qdocconf or the command-line
284 variable -outputformat.
286 QSet<QString> Config::getOutputFormats() const
288 if (overrideOutputFormats.isEmpty())
289 return getStringSet(QLatin1String(CONFIG_OUTPUTFORMATS));
291 return overrideOutputFormats;
295 First, this function looks up the configuration variable \a var
296 in the location map and, if found, sets the internal variable
297 \c{lastLocation_} to the Location that \a var maps to.
299 Then it looks up the configuration variable \a var in the string
300 map and returns the string that \a var maps to.
302 QString Config::getString(const QString& var) const
304 if (!locMap[var].isEmpty())
305 (Location&) lastLocation_ = locMap[var];
306 return stringPairMap[var].second;
310 This function looks up the variable \a var in the location map
311 and, if found, sets the internal variable \c{lastLocation_} to the
312 location that \a var maps to.
314 Then it looks up \a var in the configuration variable map and,
315 if found, constructs a path from the pair value, which consists
316 of the directory path of the configuration file where the value
317 came from, and the value itself. The constructed path is returned.
319 QString Config::getPath(const QString& var) const
321 if (!locMap[var].isEmpty())
322 (Location&) lastLocation_ = locMap[var];
324 if (stringPairMap.contains(var)) {
325 path = QDir(stringPairMap[var].first + "/" + stringPairMap[var].second).absolutePath();
331 Looks up the configuration variable \a var in the string
332 list map, converts the string list it maps to into a set
333 of strings, and returns the set.
335 QSet<QString> Config::getStringSet(const QString& var) const
337 return QSet<QString>::fromList(getStringList(var));
341 First, this function looks up the configuration variable \a var
342 in the location map and, if found, sets the internal variable
343 \c{lastLocation_} to the Location that \a var maps to.
345 Then it looks up the configuration variable \a var in the string
346 list map, and returns the string list that \a var maps to.
348 QStringList Config::getStringList(const QString& var) const
350 if (!locMap[var].isEmpty())
351 (Location&) lastLocation_ = locMap[var];
352 return stringListPairMap[var].second;
357 \brief Returns the a path list where all paths are canonicalized, then
358 made relative to the config file.
359 \param var The variable containing the list of paths.
360 \see Location::canonicalRelativePath()
362 QStringList Config::getCanonicalRelativePathList(const QString& var) const
364 if (!locMap[var].isEmpty())
365 (Location&) lastLocation_ = locMap[var];
367 QStringListPairMap::const_iterator it = stringListPairMap.constFind(var);
368 if (it != stringListPairMap.constEnd()) {
369 const QStringList& sl = it.value().second;
371 t.reserve(sl.size());
372 for (int i=0; i<sl.size(); ++i) {
373 const QString &canonicalized = location().canonicalRelativePath(sl[i]);
374 t.append(canonicalized);
382 This function should only be called when the configuration
383 variable \a var maps to a string list that contains file paths.
384 It cleans the paths with QDir::cleanPath() before returning
387 First, this function looks up the configuration variable \a var
388 in the location map and, if found, sets the internal variable
389 \c{lastLocation_} the Location that \a var maps to.
391 Then it looks up the configuration variable \a var in the string
392 list map, which maps to a string list that contains file paths.
393 These paths might not be clean, so QDir::cleanPath() is called
394 for each one. The string list returned contains cleaned paths.
396 QStringList Config::getCleanPathList(const QString& var) const
398 if (!locMap[var].isEmpty())
399 (Location&) lastLocation_ = locMap[var];
401 QStringListPairMap::const_iterator it = stringListPairMap.constFind(var);
402 if (it != stringListPairMap.constEnd()) {
403 const QStringList& sl = it.value().second;
405 t.reserve(sl.size());
406 for (int i=0; i<sl.size(); ++i) {
407 t.append(QDir::cleanPath(sl[i]));
415 This function should only be called when the configuration
416 variable \a var maps to a string list that contains file paths.
417 It cleans the paths with QDir::cleanPath() before returning
420 First, this function looks up the configuration variable \a var
421 in the location map and, if found, sets the internal variable
422 \c{lastLocation_} the Location that \a var maps to.
424 Then it looks up the configuration variable \a var in the string
425 list map, which maps to a string list that contains file paths.
426 These paths might not be clean, so QDir::cleanPath() is called
427 for each one. The string list returned contains cleaned paths.
429 QStringList Config::getPathList(const QString& var) const
431 if (!locMap[var].isEmpty())
432 (Location&) lastLocation_ = locMap[var];
434 QStringListPairMap::const_iterator it = stringListPairMap.constFind(var);
435 if (it != stringListPairMap.constEnd()) {
436 const QStringList& sl = it.value().second;
437 const QString d = it.value().first;
439 t.reserve(sl.size());
440 for (int i=0; i<sl.size(); ++i) {
442 QString path = d + "/" + QDir::cleanPath(sl[i]);
443 fileInfo.setFile(path);
444 if (!fileInfo.exists())
445 lastLocation_.warning(tr("File '%1' does not exist").arg(path));
456 Calls getRegExpList() with the control variable \a var and
457 iterates through the resulting list of regular expressions,
458 concatening them with some extras characters to form a single
459 QRegExp, which is returned/
463 QRegExp Config::getRegExp(const QString& var) const
466 QList<QRegExp> subRegExps = getRegExpList(var);
467 QList<QRegExp>::ConstIterator s = subRegExps.constBegin();
469 while (s != subRegExps.constEnd()) {
472 if (!pattern.isEmpty())
473 pattern += QLatin1Char('|');
474 pattern += QLatin1String("(?:") + (*s).pattern() + QLatin1Char(')');
477 if (pattern.isEmpty())
478 pattern = QLatin1String("$x"); // cannot match
479 return QRegExp(pattern);
483 Looks up the configuration variable \a var in the string list
484 map, converts the string list to a list of regular expressions,
487 QList<QRegExp> Config::getRegExpList(const QString& var) const
489 QStringList strs = getStringList(var);
490 QStringList::ConstIterator s = strs.constBegin();
491 QList<QRegExp> regExps;
493 while (s != strs.constEnd()) {
494 regExps += QRegExp(*s);
501 This function is slower than it could be. What it does is
502 find all the keys that begin with \a var + dot and return
503 the matching keys in a set, stripped of the matching prefix
506 QSet<QString> Config::subVars(const QString& var) const
508 QSet<QString> result;
509 QString varDot = var + QLatin1Char('.');
510 QStringPairMap::ConstIterator v = stringPairMap.constBegin();
511 while (v != stringPairMap.constEnd()) {
512 if (v.key().startsWith(varDot)) {
513 QString subVar = v.key().mid(varDot.length());
514 int dot = subVar.indexOf(QLatin1Char('.'));
516 subVar.truncate(dot);
517 result.insert(subVar);
525 Same as subVars(), but in this case we return a string map
526 with the matching keys (stripped of the prefix \a var and
527 mapped to their values. The pairs are inserted into \a t
529 void Config::subVarsAndValues(const QString& var, QStringPairMap& t) const
531 QString varDot = var + QLatin1Char('.');
532 QStringPairMap::ConstIterator v = stringPairMap.constBegin();
533 while (v != stringPairMap.constEnd()) {
534 if (v.key().startsWith(varDot)) {
535 QString subVar = v.key().mid(varDot.length());
536 int dot = subVar.indexOf(QLatin1Char('.'));
538 subVar.truncate(dot);
539 t.insert(subVar,v.value());
546 Builds and returns a list of file pathnames for the file
547 type specified by \a filesVar (e.g. "headers" or "sources").
548 The files are found in the directories specified by
549 \a dirsVar, and they are filtered by \a defaultNameFilter
550 if a better filter can't be constructed from \a filesVar.
551 The directories in \a excludedDirs are avoided. The files
552 in \a excludedFiles are not included in the return list.
554 QStringList Config::getAllFiles(const QString &filesVar,
555 const QString &dirsVar,
556 const QSet<QString> &excludedDirs,
557 const QSet<QString> &excludedFiles)
559 QStringList result = getStringList(filesVar);
560 QStringList dirs = getCanonicalRelativePathList(dirsVar);
562 QString nameFilter = getString(filesVar + dot + QLatin1String(CONFIG_FILEEXTENSIONS));
564 QStringList::ConstIterator d = dirs.constBegin();
565 while (d != dirs.constEnd()) {
566 result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles);
572 QStringList Config::getExampleQdocFiles(const QSet<QString> &excludedDirs,
573 const QSet<QString> &excludedFiles)
576 QStringList dirs = getCanonicalRelativePathList("exampledirs");
577 QString nameFilter = " *.qdoc";
579 QStringList::ConstIterator d = dirs.constBegin();
580 while (d != dirs.constEnd()) {
581 result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles);
587 QStringList Config::getExampleImageFiles(const QSet<QString> &excludedDirs,
588 const QSet<QString> &excludedFiles)
591 QStringList dirs = getCanonicalRelativePathList("exampledirs");
592 QString nameFilter = getString(CONFIG_EXAMPLES + dot + QLatin1String(CONFIG_IMAGEEXTENSIONS));
594 QStringList::ConstIterator d = dirs.constBegin();
595 while (d != dirs.constEnd()) {
596 result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles);
603 \a fileName is the path of the file to find.
605 \a files and \a dirs are the lists where we must find the
606 components of \a fileName.
608 \a location is used for obtaining the file and line numbers
609 for report qdoc errors.
611 QString Config::findFile(const Location& location,
612 const QStringList& files,
613 const QStringList& dirs,
614 const QString& fileName,
615 QString& userFriendlyFilePath)
617 if (fileName.isEmpty() || fileName.startsWith(QLatin1Char('/'))) {
618 userFriendlyFilePath = fileName;
623 QStringList components = fileName.split(QLatin1Char('?'));
624 QString firstComponent = components.first();
626 QStringList::ConstIterator f = files.constBegin();
627 while (f != files.constEnd()) {
628 if (*f == firstComponent ||
629 (*f).endsWith(QLatin1Char('/') + firstComponent)) {
630 fileInfo.setFile(*f);
631 if (!fileInfo.exists())
632 location.fatal(tr("File '%1' does not exist").arg(*f));
638 if (fileInfo.fileName().isEmpty()) {
639 QStringList::ConstIterator d = dirs.constBegin();
640 while (d != dirs.constEnd()) {
641 fileInfo.setFile(QDir(*d), firstComponent);
642 if (fileInfo.exists()) {
649 userFriendlyFilePath = QString();
650 if (!fileInfo.exists())
653 QStringList::ConstIterator c = components.constBegin();
655 bool isArchive = (c != components.constEnd() - 1);
656 QString userFriendly = *c;
658 userFriendlyFilePath += userFriendly;
661 QString extracted = extractedDirs[fileInfo.filePath()];
663 fileInfo.setFile(QDir(extracted), *c);
668 userFriendlyFilePath += QLatin1Char('?');
670 return fileInfo.filePath();
675 QString Config::findFile(const Location& location,
676 const QStringList& files,
677 const QStringList& dirs,
678 const QString& fileBase,
679 const QStringList& fileExtensions,
680 QString& userFriendlyFilePath)
682 QStringList::ConstIterator e = fileExtensions.constBegin();
683 while (e != fileExtensions.constEnd()) {
684 QString filePath = findFile(location,
687 fileBase + QLatin1Char('.') + *e,
688 userFriendlyFilePath);
689 if (!filePath.isEmpty())
693 return findFile(location, files, dirs, fileBase, userFriendlyFilePath);
697 Copies the \a sourceFilePath to the file name constructed by
698 concatenating \a targetDirPath and the file name from the
699 \a userFriendlySourceFilePath. \a location is for identifying
700 the file and line number where a qdoc error occurred. The
701 constructed output file name is returned.
703 QString Config::copyFile(const Location& location,
704 const QString& sourceFilePath,
705 const QString& userFriendlySourceFilePath,
706 const QString& targetDirPath)
708 QFile inFile(sourceFilePath);
709 if (!inFile.open(QFile::ReadOnly)) {
710 location.warning(tr("Cannot open input file for copy: '%1': %2")
711 .arg(sourceFilePath).arg(inFile.errorString()));
715 QString outFileName = userFriendlySourceFilePath;
716 int slash = outFileName.lastIndexOf(QLatin1Char('/'));
718 outFileName = outFileName.mid(slash);
719 if ((outFileName.size()) > 0 && (outFileName[0] != '/'))
720 outFileName = targetDirPath + QLatin1Char('/') + outFileName;
722 outFileName = targetDirPath + outFileName;
723 QFile outFile(outFileName);
724 if (!outFile.open(QFile::WriteOnly)) {
725 location.warning(tr("Cannot open output file for copy: '%1': %2")
726 .arg(outFileName).arg(outFile.errorString()));
732 while ((len = inFile.read(buffer, sizeof(buffer))) > 0) {
733 outFile.write(buffer, len);
739 Finds the largest unicode digit in \a value in the range
742 int Config::numParams(const QString& value)
745 for (int i = 0; i != value.length(); i++) {
746 uint c = value[i].unicode();
748 max = qMax(max, (int)c);
754 Removes everything from \a dir. This function is recursive.
755 It doesn't remove \a dir itself, but if it was called
756 recursively, then the caller will remove \a dir.
758 bool Config::removeDirContents(const QString& dir)
761 QFileInfoList entries = dirInfo.entryInfoList();
765 QFileInfoList::Iterator it = entries.begin();
766 while (it != entries.end()) {
767 if ((*it).isFile()) {
768 if (!dirInfo.remove((*it).fileName()))
771 else if ((*it).isDir()) {
772 if ((*it).fileName() != QLatin1String(".") && (*it).fileName() != QLatin1String("..")) {
773 if (removeDirContents((*it).absoluteFilePath())) {
774 if (!dirInfo.rmdir((*it).fileName()))
788 Returns true if \a ch is a letter, number, '_', '.',
791 bool Config::isMetaKeyChar(QChar ch)
793 return ch.isLetterOrNumber()
794 || ch == QLatin1Char('_')
795 || ch == QLatin1Char('.')
796 || ch == QLatin1Char('{')
797 || ch == QLatin1Char('}')
798 || ch == QLatin1Char(',');
802 Load, parse, and process a qdoc configuration file. This
803 function is only called by the other load() function, but
804 this one is recursive, i.e., it calls itself when it sees
805 an \c{include} statement in the qdoc configuration file.
807 void Config::load(Location location, const QString& fileName)
809 pushWorkingDir(QFileInfo(fileName).path());
810 QDir::setCurrent(QFileInfo(fileName).path());
811 QRegExp keySyntax(QLatin1String("\\w+(?:\\.\\w+)*"));
813 #define SKIP_CHAR() \
815 location.advance(c); \
821 #define SKIP_SPACES() \
822 while (c.isSpace() && cc != '\n') \
829 if (location.depth() > 16)
830 location.fatal(tr("Too many nested includes"));
833 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
834 if (!Config::installDir.isEmpty()) {
835 int prefix = location.filePath().length() - location.fileName().length();
836 fin.setFileName(Config::installDir + "/" + fileName.right(fileName.length() - prefix));
838 if (!fin.open(QFile::ReadOnly | QFile::Text))
839 location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString()));
842 QTextStream stream(&fin);
843 stream.setCodec("UTF-8");
844 QString text = stream.readAll();
845 text += QLatin1String("\n\n");
846 text += QLatin1Char('\0');
849 location.push(fileName);
853 QChar c = text.at(0);
854 uint cc = c.unicode();
855 while (i < (int) text.length()) {
858 else if (c.isSpace()) {
861 else if (cc == '#') {
864 } while (cc != '\n');
866 else if (isMetaKeyChar(c)) {
867 Location keyLoc = location;
870 QStringList stringListValue;
872 bool inQuote = false;
873 bool prevWordQuoted = true;
874 bool metWord = false;
878 stack.process(c, location);
880 } while (isMetaKeyChar(c));
882 QStringList keys = stack.getExpanded(location);
885 if (keys.count() == 1 && keys.first() == QLatin1String("include")) {
889 location.fatal(tr("Bad include syntax"));
893 while (!c.isSpace() && cc != '#' && cc != ')') {
898 while (c.isLetterOrNumber() || cc == '_') {
902 if (!var.isEmpty()) {
903 char *val = getenv(var.toLatin1().data());
905 location.fatal(tr("Environment variable '%1' undefined").arg(var));
908 includeFile += QString::fromLatin1(val);
918 location.fatal(tr("Bad include syntax"));
921 if (cc != '#' && cc != '\n')
922 location.fatal(tr("Trailing garbage"));
925 Here is the recursive call.
927 load(location, QFileInfo(QFileInfo(fileName).dir(), includeFile).filePath());
931 It wasn't an include statement, so it's something else.
938 location.fatal(tr("Expected '=' or '+=' after key"));
950 else if (cc > '0' && cc < '8') {
951 word += QChar(c.digitValue());
954 else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) != -1) {
955 word += QLatin1Char("\a\b\f\n\r\t\v"[metaCharPos]);
962 else if (c.isSpace() || cc == '#') {
965 location.fatal(tr("Unterminated string"));
969 if (!word.isEmpty()) {
971 stringValue += QLatin1Char(' ');
973 stringListValue << word;
976 prevWordQuoted = false;
978 if (cc == '\n' || cc == '#')
983 else if (cc == '"') {
986 stringValue += QLatin1Char(' ');
989 stringListValue << word;
992 prevWordQuoted = true;
997 else if (cc == '$') {
1000 while (c.isLetterOrNumber() || cc == '_') {
1004 if (!var.isEmpty()) {
1005 char *val = getenv(var.toLatin1().data());
1007 location.fatal(tr("Environment variable '%1' undefined").arg(var));
1010 word += QString::fromLatin1(val);
1015 if (!inQuote && cc == '=')
1016 location.fatal(tr("Unexpected '='"));
1021 QStringList::ConstIterator key = keys.constBegin();
1022 while (key != keys.constEnd()) {
1023 if (!keySyntax.exactMatch(*key))
1024 keyLoc.fatal(tr("Invalid key '%1'").arg(*key));
1027 if (locMap[*key].isEmpty()) {
1028 locMap[*key] = keyLoc;
1031 locMap[*key].setEtc(true);
1033 if (stringPairMap[*key].second.isEmpty()) {
1034 stringPairMap[*key].first = QDir::currentPath();
1035 stringPairMap[*key].second = stringValue;
1038 stringPairMap[*key].second += QLatin1Char(' ') + stringValue;
1040 stringListPairMap[*key].first = QDir::currentPath();
1041 stringListPairMap[*key].second += stringListValue;
1044 locMap[*key] = keyLoc;
1045 stringPairMap[*key].first = QDir::currentPath();
1046 stringPairMap[*key].second = stringValue;
1047 stringListPairMap[*key].first = QDir::currentPath();
1048 stringListPairMap[*key].second = stringListValue;
1055 location.fatal(tr("Unexpected character '%1' at beginning of line").arg(c));
1059 if (!workingDirs_.isEmpty())
1060 QDir::setCurrent(QFileInfo(workingDirs_.top()).path());
1063 QStringList Config::getFilesHere(const QString& uncleanDir,
1064 const QString& nameFilter,
1065 const Location &location,
1066 const QSet<QString> &excludedDirs,
1067 const QSet<QString> &excludedFiles)
1070 QString dir = location.isEmpty() ? QDir::cleanPath(uncleanDir) : location.canonicalRelativePath(uncleanDir);
1072 if (excludedDirs.contains(dir))
1076 QStringList fileNames;
1077 QStringList::const_iterator fn;
1079 dirInfo.setNameFilters(nameFilter.split(QLatin1Char(' ')));
1080 dirInfo.setSorting(QDir::Name);
1081 dirInfo.setFilter(QDir::Files);
1082 fileNames = dirInfo.entryList();
1083 fn = fileNames.constBegin();
1084 while (fn != fileNames.constEnd()) {
1085 if (!fn->startsWith(QLatin1Char('~'))) {
1086 QString s = dirInfo.filePath(*fn);
1087 QString c = QDir::cleanPath(s);
1088 if (!excludedFiles.contains(c)) {
1095 dirInfo.setNameFilters(QStringList(QLatin1String("*")));
1096 dirInfo.setFilter(QDir::Dirs|QDir::NoDotAndDotDot);
1097 fileNames = dirInfo.entryList();
1098 fn = fileNames.constBegin();
1099 while (fn != fileNames.constEnd()) {
1100 result += getFilesHere(dirInfo.filePath(*fn), nameFilter, location, excludedDirs, excludedFiles);
1107 Push \a dir onto the stack of working directories.
1109 void Config::pushWorkingDir(const QString& dir)
1111 workingDirs_.push(dir);
1115 If the stack of working directories is not empty, pop the
1116 top entry and return it. Otherwise return an empty string.
1118 QString Config::popWorkingDir()
1120 if (!workingDirs_.isEmpty()) {
1121 return workingDirs_.pop();
1123 qDebug() << "RETURNED EMPTY WORKING DIR";