summaryrefslogtreecommitdiffstats
path: root/src/qdoc/config.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qdoc/config.cpp')
-rw-r--r--src/qdoc/config.cpp1314
1 files changed, 0 insertions, 1314 deletions
diff --git a/src/qdoc/config.cpp b/src/qdoc/config.cpp
deleted file mode 100644
index 41dc9b2c6..000000000
--- a/src/qdoc/config.cpp
+++ /dev/null
@@ -1,1314 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "config.h"
-#include "utilities.h"
-
-#include <QtCore/qdir.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qtemporaryfile.h>
-#include <QtCore/qtextstream.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qregularexpression.h>
-
-QT_BEGIN_NAMESPACE
-
-QString ConfigStrings::ALIAS = QStringLiteral("alias");
-QString ConfigStrings::AUTOLINKERRORS = QStringLiteral("autolinkerrors");
-QString ConfigStrings::BUILDVERSION = QStringLiteral("buildversion");
-QString ConfigStrings::CLANGDEFINES = QStringLiteral("clangdefines");
-QString ConfigStrings::CODEINDENT = QStringLiteral("codeindent");
-QString ConfigStrings::CODEPREFIX = QStringLiteral("codeprefix");
-QString ConfigStrings::CODESUFFIX = QStringLiteral("codesuffix");
-QString ConfigStrings::CPPCLASSESPAGE = QStringLiteral("cppclassespage");
-QString ConfigStrings::CPPCLASSESTITLE = QStringLiteral("cppclassestitle");
-QString ConfigStrings::DEFINES = QStringLiteral("defines");
-QString ConfigStrings::DEPENDS = QStringLiteral("depends");
-QString ConfigStrings::DESCRIPTION = QStringLiteral("description");
-QString ConfigStrings::DOCBOOKEXTENSIONS = QStringLiteral("usedocbookextensions");
-QString ConfigStrings::ENDHEADER = QStringLiteral("endheader");
-QString ConfigStrings::EXAMPLEDIRS = QStringLiteral("exampledirs");
-QString ConfigStrings::EXAMPLES = QStringLiteral("examples");
-QString ConfigStrings::EXAMPLESINSTALLPATH = QStringLiteral("examplesinstallpath");
-QString ConfigStrings::EXCLUDEDIRS = QStringLiteral("excludedirs");
-QString ConfigStrings::EXCLUDEFILES = QStringLiteral("excludefiles");
-QString ConfigStrings::EXTRAIMAGES = QStringLiteral("extraimages");
-QString ConfigStrings::FALSEHOODS = QStringLiteral("falsehoods");
-QString ConfigStrings::FORMATTING = QStringLiteral("formatting");
-QString ConfigStrings::HEADERDIRS = QStringLiteral("headerdirs");
-QString ConfigStrings::HEADERS = QStringLiteral("headers");
-QString ConfigStrings::HEADERSCRIPTS = QStringLiteral("headerscripts");
-QString ConfigStrings::HEADERSTYLES = QStringLiteral("headerstyles");
-QString ConfigStrings::HOMEPAGE = QStringLiteral("homepage");
-QString ConfigStrings::HOMETITLE = QStringLiteral("hometitle");
-QString ConfigStrings::IGNOREDIRECTIVES = QStringLiteral("ignoredirectives");
-QString ConfigStrings::IGNORESINCE = QStringLiteral("ignoresince");
-QString ConfigStrings::IGNORETOKENS = QStringLiteral("ignoretokens");
-QString ConfigStrings::IGNOREWORDS = QStringLiteral("ignorewords");
-QString ConfigStrings::IMAGEDIRS = QStringLiteral("imagedirs");
-QString ConfigStrings::IMAGES = QStringLiteral("images");
-QString ConfigStrings::INCLUDEPATHS = QStringLiteral("includepaths");
-QString ConfigStrings::INDEXES = QStringLiteral("indexes");
-QString ConfigStrings::LANDINGPAGE = QStringLiteral("landingpage");
-QString ConfigStrings::LANDINGTITLE = QStringLiteral("landingtitle");
-QString ConfigStrings::LANGUAGE = QStringLiteral("language");
-QString ConfigStrings::LOCATIONINFO = QStringLiteral("locationinfo");
-QString ConfigStrings::LOGPROGRESS = QStringLiteral("logprogress");
-QString ConfigStrings::MACRO = QStringLiteral("macro");
-QString ConfigStrings::MANIFESTMETA = QStringLiteral("manifestmeta");
-QString ConfigStrings::MODULEHEADER = QStringLiteral("moduleheader");
-QString ConfigStrings::NATURALLANGUAGE = QStringLiteral("naturallanguage");
-QString ConfigStrings::NAVIGATION = QStringLiteral("navigation");
-QString ConfigStrings::NOLINKERRORS = QStringLiteral("nolinkerrors");
-QString ConfigStrings::OUTPUTDIR = QStringLiteral("outputdir");
-QString ConfigStrings::OUTPUTFORMATS = QStringLiteral("outputformats");
-QString ConfigStrings::OUTPUTPREFIXES = QStringLiteral("outputprefixes");
-QString ConfigStrings::OUTPUTSUFFIXES = QStringLiteral("outputsuffixes");
-QString ConfigStrings::PROJECT = QStringLiteral("project");
-QString ConfigStrings::REDIRECTDOCUMENTATIONTODEVNULL =
- QStringLiteral("redirectdocumentationtodevnull");
-QString ConfigStrings::QHP = QStringLiteral("qhp");
-QString ConfigStrings::QUOTINGINFORMATION = QStringLiteral("quotinginformation");
-QString ConfigStrings::SCRIPTS = QStringLiteral("scripts");
-QString ConfigStrings::SHOWINTERNAL = QStringLiteral("showinternal");
-QString ConfigStrings::SINGLEEXEC = QStringLiteral("singleexec");
-QString ConfigStrings::SOURCEDIRS = QStringLiteral("sourcedirs");
-QString ConfigStrings::SOURCEENCODING = QStringLiteral("sourceencoding");
-QString ConfigStrings::SOURCES = QStringLiteral("sources");
-QString ConfigStrings::SPURIOUS = QStringLiteral("spurious");
-QString ConfigStrings::STYLESHEETS = QStringLiteral("stylesheets");
-QString ConfigStrings::SYNTAXHIGHLIGHTING = QStringLiteral("syntaxhighlighting");
-QString ConfigStrings::TABSIZE = QStringLiteral("tabsize");
-QString ConfigStrings::TAGFILE = QStringLiteral("tagfile");
-QString ConfigStrings::TIMESTAMPS = QStringLiteral("timestamps");
-QString ConfigStrings::TOCTITLES = QStringLiteral("toctitles");
-QString ConfigStrings::TRANSLATORS = QStringLiteral("translators");
-QString ConfigStrings::URL = QStringLiteral("url");
-QString ConfigStrings::VERSION = QStringLiteral("version");
-QString ConfigStrings::VERSIONSYM = QStringLiteral("versionsym");
-QString ConfigStrings::FILEEXTENSIONS = QStringLiteral("fileextensions");
-QString ConfigStrings::IMAGEEXTENSIONS = QStringLiteral("imageextensions");
-QString ConfigStrings::QMLTYPESPAGE = QStringLiteral("qmltypespage");
-QString ConfigStrings::QMLTYPESTITLE = QStringLiteral("qmltypestitle");
-QString ConfigStrings::WARNINGLIMIT = QStringLiteral("warninglimit");
-
-/*!
- An entry in a stack, where each entry is a list
- of string values.
- */
-class MetaStackEntry
-{
-public:
- void open();
- void close();
-
- QStringList accum;
- QStringList next;
-};
-Q_DECLARE_TYPEINFO(MetaStackEntry, Q_RELOCATABLE_TYPE);
-
-/*!
- Start accumulating values in a list by appending an empty
- string to the list.
- */
-void MetaStackEntry::open()
-{
- next.append(QString());
-}
-
-/*!
- Stop accumulating values and append the list of accumulated
- values to the complete list of accumulated values.
-
- */
-void MetaStackEntry::close()
-{
- accum += next;
- next.clear();
-}
-
-/*!
- \class MetaStack
-
- This class maintains a stack of values of config file variables.
-*/
-class MetaStack : private QStack<MetaStackEntry>
-{
-public:
- MetaStack();
-
- void process(QChar ch, const Location &location);
- QStringList getExpanded(const Location &location);
-};
-
-/*!
- The default constructor pushes a new stack entry and
- opens it.
- */
-MetaStack::MetaStack()
-{
- push(MetaStackEntry());
- top().open();
-}
-
-/*!
- Processes the character \a ch using the \a location.
- It really just builds up a name by appending \a ch to
- it.
- */
-void MetaStack::process(QChar ch, const Location &location)
-{
- if (ch == QLatin1Char('{')) {
- push(MetaStackEntry());
- top().open();
- } else if (ch == QLatin1Char('}')) {
- if (count() == 1)
- location.fatal(QStringLiteral("Unexpected '}'"));
-
- top().close();
- const QStringList suffixes = pop().accum;
- const QStringList prefixes = top().next;
-
- top().next.clear();
- for (const auto &prefix : prefixes) {
- for (const auto &suffix : suffixes)
- top().next << prefix + suffix;
- }
- } else if (ch == QLatin1Char(',') && count() > 1) {
- top().close();
- top().open();
- } else {
- for (QString &topNext : top().next)
- topNext += ch;
- }
-}
-
-/*!
- Returns the accumulated string values.
- */
-QStringList MetaStack::getExpanded(const Location &location)
-{
- if (count() > 1)
- location.fatal(QStringLiteral("Missing '}'"));
-
- top().close();
- return top().accum;
-}
-
-const QString Config::dot = QLatin1String(".");
-bool Config::m_debug = false;
-bool Config::generateExamples = true;
-QString Config::overrideOutputDir;
-QString Config::installDir;
-QSet<QString> Config::overrideOutputFormats;
-QMap<QString, QString> Config::m_extractedDirs;
-QStack<QString> Config::m_workingDirs;
-QMap<QString, QStringList> Config::m_includeFilesMap;
-
-/*!
- \class Config
- \brief The Config class contains the configuration variables
- for controlling how qdoc produces documentation.
-
- Its load() function reads, parses, and processes a qdocconf file.
- */
-
-/*!
- \enum Config::PathFlags
-
- Flags used for retrieving canonicalized paths from Config.
-
- \value Validate
- Issue a warning for paths that do not exist and
- remove them from the returned list.
-
- \value IncludePaths
- Assume the variable contains include paths with
- prefixes such as \c{-I} that are to be removed
- before canonicalizing and then re-inserted.
-
- \omitvalue None
-
- \sa getCanonicalPathList()
-*/
-
-/*!
- Initializes the Config with \a programName and sets all
- internal state variables to either default values or to ones
- defined in command line arguments \a args.
- */
-void Config::init(const QString &programName, const QStringList &args)
-{
- m_prog = programName;
- processCommandLineOptions(args);
- reset();
-}
-
-Config::~Config()
-{
- clear();
-}
-
-/*!
- Clears the location and internal maps for config variables.
- */
-void Config::clear()
-{
- m_location = m_lastLocation = Location();
- m_configVars.clear();
- m_includeFilesMap.clear();
-}
-
-/*!
- Resets the Config instance - used by load()
- */
-void Config::reset()
-{
- clear();
-
- // Default values
- setStringList(CONFIG_CODEINDENT, QStringList("0"));
- setStringList(CONFIG_FALSEHOODS, QStringList("0"));
- setStringList(CONFIG_FILEEXTENSIONS, QStringList("*.cpp *.h *.qdoc *.qml"));
- setStringList(CONFIG_LANGUAGE, QStringList("Cpp")); // i.e. C++
- setStringList(CONFIG_OUTPUTFORMATS, QStringList("HTML"));
- setStringList(CONFIG_TABSIZE, QStringList("8"));
- setStringList(CONFIG_LOCATIONINFO, QStringList("true"));
-
- // Publish options from the command line as config variables
- const auto setListFlag = [this](const QString &key, bool test) {
- setStringList(key, QStringList(test ? QStringLiteral("true") : QStringLiteral("false")));
- };
-#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
- SET(CONFIG_SYNTAXHIGHLIGHTING, highlightingOption);
- SET(CONFIG_SHOWINTERNAL, showInternalOption);
- SET(CONFIG_SINGLEEXEC, singleExecOption);
- SET(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, redirectDocumentationToDevNullOption);
- SET(CONFIG_AUTOLINKERRORS, autoLinkErrorsOption);
-#undef SET
- m_showInternal = getBool(CONFIG_SHOWINTERNAL);
- setListFlag(CONFIG_NOLINKERRORS,
- m_parser.isSet(m_parser.noLinkErrorsOption)
- || qEnvironmentVariableIsSet("QDOC_NOLINKERRORS"));
-
- // CONFIG_DEFINES and CONFIG_INCLUDEPATHS are set in load()
-}
-
-/*!
- Loads and parses the qdoc configuration file \a fileName.
- If a previous project was loaded, this function first resets the
- Config instance. Then it calls the other load() function, which
- does the loading, parsing, and processing of the configuration file.
- */
-void Config::load(const QString &fileName)
-{
- // Reset if a previous project was loaded
- if (m_configVars.contains(CONFIG_PROJECT))
- reset();
-
- load(Location(), fileName);
- if (m_location.isEmpty())
- m_location = Location(fileName);
- else
- m_location.setEtc(true);
- m_lastLocation = Location();
-
- expandVariables();
-
- // Add defines and includepaths from command line to their
- // respective configuration variables. Values set here are
- // always added to what's defined in configuration file.
- insertStringList(CONFIG_DEFINES, m_defines);
- insertStringList(CONFIG_INCLUDEPATHS, m_includePaths);
-
- // Prefetch values that are used internally
- m_exampleFiles = getCanonicalPathList(CONFIG_EXAMPLES);
- m_exampleDirs = getCanonicalPathList(CONFIG_EXAMPLEDIRS);
-}
-
-/*!
- Expands other config variables referred to in all stored ConfigVars.
-*/
-void Config::expandVariables()
-{
- for (auto &configVar : m_configVars) {
- for (auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) {
- Q_ASSERT(it->m_valueIndex < configVar.m_values.size());
- const QString &key = it->m_var;
- const auto &refVar = m_configVars.value(key);
- if (refVar.m_name.isEmpty()) {
- configVar.m_location.fatal(
- QStringLiteral("Environment or configuration variable '%1' undefined")
- .arg(it->m_var));
- } else if (!refVar.m_expandVars.empty()) {
- configVar.m_location.fatal(
- QStringLiteral("Nested variable expansion not allowed"),
- QStringLiteral("When expanding '%1' at %2:%3")
- .arg(refVar.m_name, refVar.m_location.filePath(),
- QString::number(refVar.m_location.lineNo())));
- }
- QString expanded;
- if (it->m_delim.isNull())
- expanded = getStringList(key).join(QString());
- else
- expanded = getStringList(key).join(it->m_delim);
- configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded);
- }
- configVar.m_expandVars.clear();
- }
-}
-
-/*!
- Sets the \a values of a configuration variable \a var from a string list.
- */
-void Config::setStringList(const QString &var, const QStringList &values)
-{
- m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath()));
-}
-
-/*!
- Adds the \a values from a string list to the configuration variable \a var.
- Existing value(s) are kept.
-*/
-void Config::insertStringList(const QString &var, const QStringList &values)
-{
- m_configVars[var].append(ConfigVar(var, values, QDir::currentPath()));
-}
-
-/*!
- Process and store variables from the command line.
- */
-void Config::processCommandLineOptions(const QStringList &args)
-{
- m_parser.process(args);
-
- m_defines = m_parser.values(m_parser.defineOption);
- m_dependModules = m_parser.values(m_parser.dependsOption);
- setIndexDirs();
- setIncludePaths();
-
- generateExamples = !m_parser.isSet(m_parser.noExamplesOption);
- if (m_parser.isSet(m_parser.installDirOption))
- installDir = m_parser.value(m_parser.installDirOption);
- if (m_parser.isSet(m_parser.outputDirOption))
- overrideOutputDir = m_parser.value(m_parser.outputDirOption);
-
- const auto outputFormats = m_parser.values(m_parser.outputFormatOption);
- for (const auto &format : outputFormats)
- overrideOutputFormats.insert(format);
- m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet("QDOC_DEBUG");
- m_showInternal = m_parser.isSet(m_parser.showInternalOption)
- || qEnvironmentVariableIsSet("QDOC_SHOW_INTERNAL");
-
- if (m_parser.isSet(m_parser.prepareOption))
- m_qdocPass = Prepare;
- if (m_parser.isSet(m_parser.generateOption))
- m_qdocPass = Generate;
- if (m_parser.isSet(m_parser.logProgressOption))
- setStringList(CONFIG_LOGPROGRESS, QStringList("true"));
- if (m_parser.isSet(m_parser.timestampsOption))
- setStringList(CONFIG_TIMESTAMPS, QStringList("true"));
- if (m_parser.isSet(m_parser.useDocBookExtensions))
- setStringList(CONFIG_DOCBOOKEXTENSIONS, QStringList("true"));
-}
-
-void Config::setIncludePaths()
-{
- QDir currentDir = QDir::current();
- const auto addIncludePaths = [this, currentDir](const char *flag, const QStringList &paths) {
- for (const auto &path : paths)
- m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag);
- };
-
- addIncludePaths("-I", m_parser.values(m_parser.includePathOption));
-#ifdef QDOC_PASS_ISYSTEM
- addIncludePaths("-isystem", m_parser.values(m_parser.includePathSystemOption));
-#endif
- addIncludePaths("-F", m_parser.values(m_parser.frameworkOption));
-}
-
-/*!
- Stores paths from -indexdir command line option(s).
- */
-void Config::setIndexDirs()
-{
- m_indexDirs = m_parser.values(m_parser.indexDirOption);
- auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(),
- [](const QString &s) { return !QFile::exists(s); });
-
- std::for_each(it, m_indexDirs.end(), [](const QString &s) {
- qCWarning(lcQdoc) << "Cannot find index directory: " << s;
- });
- m_indexDirs.erase(it, m_indexDirs.end());
-}
-
-/*!
- Looks up the configuration variable \a var in the string
- map and returns the boolean value.
- */
-bool Config::getBool(const QString &var) const
-{
- return QVariant(getString(var)).toBool();
-}
-
-/*!
- Looks up the configuration variable \a var in the string list
- map. Iterates through the string list found, interpreting each
- string in the list as an integer and adding it to a total sum.
- Returns the sum or \c -1 if \a var is not set.
- */
-int Config::getInt(const QString &var) const
-{
- const QStringList strs = getStringList(var);
- if (strs.isEmpty())
- return -1;
-
- int sum = 0;
- for (const auto &str : strs)
- sum += str.toInt();
- return sum;
-}
-
-/*!
- Function to return the correct outputdir for the output \a format.
- If \a format is not specified, defaults to 'HTML'.
- outputdir can be set using the qdocconf or the command-line
- variable -outputdir.
- */
-QString Config::getOutputDir(const QString &format) const
-{
- QString t;
- if (overrideOutputDir.isNull())
- t = getString(CONFIG_OUTPUTDIR);
- else
- t = overrideOutputDir;
- if (getBool(CONFIG_SINGLEEXEC)) {
- QString project = getString(CONFIG_PROJECT);
- t += QLatin1Char('/') + project.toLower();
- }
- if (getBool(format + Config::dot + "nosubdirs")) {
- t = t.left(t.lastIndexOf('/'));
- QString singleOutputSubdir = getString(format + Config::dot + "outputsubdir");
- if (singleOutputSubdir.isEmpty())
- singleOutputSubdir = "html";
- t += QLatin1Char('/') + singleOutputSubdir;
- }
- return t;
-}
-
-/*!
- Function to return the correct outputformats.
- outputformats can be set using the qdocconf or the command-line
- variable -outputformat.
- */
-QSet<QString> Config::getOutputFormats() const
-{
- if (overrideOutputFormats.isEmpty())
- return getStringSet(CONFIG_OUTPUTFORMATS);
- else
- return overrideOutputFormats;
-}
-
-/*!
- Returns the value of a configuration variable \a var
- as a string. If \a var is defined, updates the internal
- location to the location of \a var for the purposes of
- error reporting.
-
- If \a var is not defined, returns \a defaultString.
-
- \note By default, \a defaultString is a null string. If \a var
- is found but contains an empty string, that is returned instead.
- This allows determining whether a configuration variable is
- undefined (null string) or defined as empty (empty string).
- */
-QString Config::getString(const QString &var, const QString &defaultString) const
-{
- const auto &configVar = m_configVars.value(var);
-
- if (configVar.m_name.isEmpty())
- return defaultString;
- updateLocation(configVar);
-
- QString result(""); // an empty but non-null string
- for (const auto &value : configVar.m_values) {
- if (!result.isEmpty() && !result.endsWith(QChar('\n')))
- result.append(QChar(' '));
- result.append(value.m_value);
- }
- return result;
-}
-
-/*!
- Looks up the configuration variable \a var in the string
- list map, converts the string list it maps to into a set
- of strings, and returns the set.
- */
-QSet<QString> Config::getStringSet(const QString &var) const
-{
- const auto &stringList = getStringList(var);
- return QSet<QString>(stringList.cbegin(), stringList.cend());
-}
-
-/*!
- Returns the string list contained in the configuration variable
- \a var. If \a var is defined, updates the internal location
- to the location of \a var for the purposes of error reporting.
- */
-QStringList Config::getStringList(const QString &var) const
-{
- const auto &configVar = m_configVars.value(var);
- updateLocation(configVar);
-
- QStringList result;
- for (const auto &value : configVar.m_values)
- result << value.m_value;
- return result;
-}
-
-/*!
- Returns a path list where all paths from the config variable \a var
- are canonicalized. If \a flags contains \c Validate, outputs a warning
- for invalid paths. The \c IncludePaths flag is used as a hint to strip
- away potential prefixes found in include paths before attempting to
- canonicalize.
-
- \note The internal location is updated to the location of \a var for
- the purposes of error reporting.
- */
-QStringList Config::getCanonicalPathList(const QString &var, PathFlags flags) const
-{
- QStringList result;
- const auto &configVar = m_configVars.value(var);
- updateLocation(configVar);
-
- for (const auto &value : configVar.m_values) {
- const QString &currentPath = value.m_path;
- QString rawValue = value.m_value.simplified();
- QString prefix;
-
- if (flags & IncludePaths) {
- const QStringList prefixes = QStringList()
- << QLatin1String("-I")
- << QLatin1String("-F")
- << QLatin1String("-isystem");
- const auto end = std::end(prefixes);
- const auto it =
- std::find_if(std::begin(prefixes), end,
- [&rawValue](const QString &p) {
- return rawValue.startsWith(p);
- });
- if (it != end) {
- prefix = *it;
- rawValue.remove(0, it->size());
- if (rawValue.isEmpty())
- continue;
- } else {
- prefix = prefixes[0]; // -I as default
- }
- }
-
- QDir dir(rawValue.trimmed());
- const QString path = dir.path();
-
- if (dir.isRelative())
- dir.setPath(currentPath + QLatin1Char('/') + path);
- if ((flags & Validate) && !QFileInfo::exists(dir.path()))
- m_lastLocation.warning(QStringLiteral("Cannot find file or directory: %1").arg(path));
- else {
- const QString canonicalPath = dir.canonicalPath();
- if (!canonicalPath.isEmpty())
- result.append(prefix + canonicalPath);
- else if (path.contains(QLatin1Char('*')) || path.contains(QLatin1Char('?')))
- result.append(path);
- else
- qCDebug(lcQdoc) <<
- qUtf8Printable(QStringLiteral("%1: Ignored nonexistent path \'%2\'")
- .arg(m_lastLocation.toString()).arg(rawValue));
- }
- }
- return result;
-}
-
-/*!
- Calls getRegExpList() with the control variable \a var and
- iterates through the resulting list of regular expressions,
- concatenating them with extra characters to form a single
- QRegularExpression, which is then returned.
-
- \sa getRegExpList()
- */
-QRegularExpression Config::getRegExp(const QString &var) const
-{
- QString pattern;
- const auto subRegExps = getRegExpList(var);
-
- for (const auto &regExp : subRegExps) {
- if (!regExp.isValid())
- return regExp;
- if (!pattern.isEmpty())
- pattern += QLatin1Char('|');
- pattern += QLatin1String("(?:") + regExp.pattern() + QLatin1Char(')');
- }
- if (pattern.isEmpty())
- pattern = QLatin1String("$x"); // cannot match
- return QRegularExpression(pattern);
-}
-
-/*!
- Looks up the configuration variable \a var in the string list
- map, converts the string list to a list of regular expressions,
- and returns it.
- */
-QList<QRegularExpression> Config::getRegExpList(const QString &var) const
-{
- const QStringList strs = getStringList(var);
- QList<QRegularExpression> regExps;
- for (const auto &str : strs)
- regExps += QRegularExpression(str);
- return regExps;
-}
-
-/*!
- This function is slower than it could be. What it does is
- find all the keys that begin with \a var + dot and return
- the matching keys in a set, stripped of the matching prefix
- and dot.
- */
-QSet<QString> Config::subVars(const QString &var) const
-{
- QSet<QString> result;
- QString varDot = var + QLatin1Char('.');
- for (auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) {
- if (it.key().startsWith(varDot)) {
- QString subVar = it.key().mid(varDot.length());
- int dot = subVar.indexOf(QLatin1Char('.'));
- if (dot != -1)
- subVar.truncate(dot);
- result.insert(subVar);
- }
- }
- return result;
-}
-
-/*!
- Searches for a path to \a fileName in 'sources', 'sourcedirs', and
- 'exampledirs' config variables and returns a full path to the first
- match found. If the file is not found, returns an empty string.
- */
-QString Config::getIncludeFilePath(const QString &fileName) const
-{
- QString ext = QFileInfo(fileName).suffix();
-
- if (!m_includeFilesMap.contains(ext)) {
- QStringList result = getCanonicalPathList(CONFIG_SOURCES);
- result.erase(std::remove_if(result.begin(), result.end(),
- [&](const QString &s) { return !s.endsWith(ext); }),
- result.end());
- const QStringList dirs =
- getCanonicalPathList(CONFIG_SOURCEDIRS) +
- getCanonicalPathList(CONFIG_EXAMPLEDIRS);
-
- for (const auto &dir : dirs)
- result += getFilesHere(dir, "*." + ext, location());
- result.removeDuplicates();
- m_includeFilesMap.insert(ext, result);
- }
- const QStringList &paths = (*m_includeFilesMap.find(ext));
- QString match = fileName;
- if (!match.startsWith('/'))
- match.prepend('/');
- for (const auto &path : paths) {
- if (path.endsWith(match))
- return path;
- }
- return QString();
-}
-
-/*!
- Builds and returns a list of file pathnames for the file
- type specified by \a filesVar (e.g. "headers" or "sources").
- The files are found in the directories specified by
- \a dirsVar, and they are filtered by \a defaultNameFilter
- if a better filter can't be constructed from \a filesVar.
- The directories in \a excludedDirs are avoided. The files
- in \a excludedFiles are not included in the return list.
- */
-QStringList Config::getAllFiles(const QString &filesVar, const QString &dirsVar,
- const QSet<QString> &excludedDirs,
- const QSet<QString> &excludedFiles)
-{
- QStringList result = getCanonicalPathList(filesVar, Validate);
- const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
-
- const QString nameFilter = getString(filesVar + dot + CONFIG_FILEEXTENSIONS);
-
- for (const auto &dir : dirs)
- result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
- return result;
-}
-
-QStringList Config::getExampleQdocFiles(const QSet<QString> &excludedDirs,
- const QSet<QString> &excludedFiles)
-{
- QStringList result;
- const QStringList dirs = getCanonicalPathList("exampledirs");
- const QString nameFilter = " *.qdoc";
-
- for (const auto &dir : dirs)
- result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
- return result;
-}
-
-QStringList Config::getExampleImageFiles(const QSet<QString> &excludedDirs,
- const QSet<QString> &excludedFiles)
-{
- QStringList result;
- const QStringList dirs = getCanonicalPathList("exampledirs");
- const QString nameFilter = getString(CONFIG_EXAMPLES + dot + CONFIG_IMAGEEXTENSIONS);
-
- for (const auto &dir : dirs)
- result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
- return result;
-}
-
-/*!
- Returns the path to the project file for \a examplePath, or an empty string
- if no project file was found.
- */
-QString Config::getExampleProjectFile(const QString &examplePath)
-{
- QFileInfo fileInfo(examplePath);
- QStringList validNames;
- validNames << fileInfo.fileName() + QLatin1String(".pro")
- << fileInfo.fileName() + QLatin1String(".qmlproject")
- << fileInfo.fileName() + QLatin1String(".pyproject")
- << QLatin1String("CMakeLists.txt")
- << QLatin1String("qbuild.pro"); // legacy
-
- QString projectFile;
-
- for (const auto &name : qAsConst(validNames)) {
- projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs,
- examplePath + QLatin1Char('/') + name);
- if (!projectFile.isEmpty())
- return projectFile;
- }
-
- return projectFile;
-}
-
-/*!
- \a fileName is the path of the file to find.
-
- \a files and \a dirs are the lists where we must find the
- components of \a fileName.
-
- \a location is used for obtaining the file and line numbers
- for report qdoc errors.
- */
-QString Config::findFile(const Location &location, const QStringList &files,
- const QStringList &dirs, const QString &fileName,
- QString *userFriendlyFilePath)
-{
- if (fileName.isEmpty() || fileName.startsWith(QLatin1Char('/'))) {
- if (userFriendlyFilePath)
- *userFriendlyFilePath = fileName;
- return fileName;
- }
-
- QFileInfo fileInfo;
- QStringList components = fileName.split(QLatin1Char('?'));
- QString firstComponent = components.first();
-
- for (const auto &file : files) {
- if (file == firstComponent || file.endsWith(QLatin1Char('/') + firstComponent)) {
- fileInfo.setFile(file);
- if (!fileInfo.exists())
- location.fatal(QStringLiteral("File '%1' does not exist").arg(file));
- break;
- }
- }
-
- if (fileInfo.fileName().isEmpty()) {
- for (const auto &dir : dirs) {
- fileInfo.setFile(QDir(dir), firstComponent);
- if (fileInfo.exists())
- break;
- }
- }
-
- if (userFriendlyFilePath)
- userFriendlyFilePath->clear();
- if (!fileInfo.exists())
- return QString();
-
- if (userFriendlyFilePath) {
- for (auto c = components.constBegin();;) {
- bool isArchive = (c != components.constEnd() - 1);
- userFriendlyFilePath->append(*c);
-
- if (isArchive) {
- QString extracted = m_extractedDirs[fileInfo.filePath()];
- ++c;
- fileInfo.setFile(QDir(extracted), *c);
- } else {
- break;
- }
-
- userFriendlyFilePath->append(QLatin1Char('?'));
- }
- }
- return fileInfo.filePath();
-}
-
-/*!
- */
-QString Config::findFile(const Location &location, const QStringList &files,
- const QStringList &dirs, const QString &fileBase,
- const QStringList &fileExtensions, QString *userFriendlyFilePath)
-{
- for (const auto &extension : fileExtensions) {
- QString filePath = findFile(location, files, dirs, fileBase + QLatin1Char('.') + extension,
- userFriendlyFilePath);
- if (!filePath.isEmpty())
- return filePath;
- }
- return findFile(location, files, dirs, fileBase, userFriendlyFilePath);
-}
-
-/*!
- Copies the \a sourceFilePath to the file name constructed by
- concatenating \a targetDirPath and the file name from the
- \a userFriendlySourceFilePath. \a location is for identifying
- the file and line number where a qdoc error occurred. The
- constructed output file name is returned.
- */
-QString Config::copyFile(const Location &location, const QString &sourceFilePath,
- const QString &userFriendlySourceFilePath, const QString &targetDirPath)
-{
- QFile inFile(sourceFilePath);
- if (!inFile.open(QFile::ReadOnly)) {
- location.warning(QStringLiteral("Cannot open input file for copy: '%1': %2")
- .arg(sourceFilePath, inFile.errorString()));
- return QString();
- }
-
- QString outFileName = userFriendlySourceFilePath;
- qsizetype slash = outFileName.lastIndexOf(QLatin1Char('/'));
- if (slash != -1)
- outFileName = outFileName.mid(slash);
- if ((outFileName.size()) > 0 && (outFileName[0] != '/'))
- outFileName = targetDirPath + QLatin1Char('/') + outFileName;
- else
- outFileName = targetDirPath + outFileName;
- QFile outFile(outFileName);
- if (!outFile.open(QFile::WriteOnly)) {
- location.warning(QStringLiteral("Cannot open output file for copy: '%1': %2")
- .arg(outFileName, outFile.errorString()));
- return QString();
- }
-
- char buffer[1024];
- qsizetype len;
- while ((len = inFile.read(buffer, sizeof(buffer))) > 0)
- outFile.write(buffer, len);
- return outFileName;
-}
-
-/*!
- Finds the largest unicode digit in \a value in the range
- 1..7 and returns it.
- */
-int Config::numParams(const QString &value)
-{
- int max = 0;
- for (int i = 0; i != value.length(); ++i) {
- uint c = value[i].unicode();
- if (c > 0 && c < 8)
- max = qMax(max, static_cast<int>(c));
- }
- return max;
-}
-
-/*!
- Returns \c true if \a ch is a letter, number, '_', '.',
- '{', '}', or ','.
- */
-bool Config::isMetaKeyChar(QChar ch)
-{
- return ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char('.')
- || ch == QLatin1Char('{') || ch == QLatin1Char('}') || ch == QLatin1Char(',');
-}
-
-/*!
- \a fileName is a master qdocconf file. It contains a list of
- qdocconf files and nothing else. Read the list and return it.
- */
-QStringList Config::loadMaster(const QString &fileName)
-{
- Location location;
- QFile fin(fileName);
- if (!fin.open(QFile::ReadOnly | QFile::Text)) {
- if (!Config::installDir.isEmpty()) {
- qsizetype prefix = location.filePath().length() - location.fileName().length();
- fin.setFileName(Config::installDir + QLatin1Char('/')
- + fileName.right(fileName.length() - prefix));
- }
- if (!fin.open(QFile::ReadOnly | QFile::Text))
- location.fatal(QStringLiteral("Cannot open master qdocconf file '%1': %2")
- .arg(fileName, fin.errorString()));
- }
- QTextStream stream(&fin);
- QStringList qdocFiles;
- QDir configDir(QFileInfo(fileName).canonicalPath());
- QString line = stream.readLine();
- while (!line.isNull()) {
- qdocFiles.append(QFileInfo(configDir, line).filePath());
- line = stream.readLine();
- }
- fin.close();
- return qdocFiles;
-}
-
-/*!
- Load, parse, and process a qdoc configuration file. This
- function is only called by the other load() function, but
- this one is recursive, i.e., it calls itself when it sees
- an \c{include} statement in the qdoc configuration file.
- */
-void Config::load(Location location, const QString &fileName)
-{
- QFileInfo fileInfo(fileName);
- QString path = fileInfo.canonicalPath();
- pushWorkingDir(path);
- QDir::setCurrent(path);
- QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String("\\w+(?:\\.\\w+)*")));
-
-#define SKIP_CHAR() \
- do { \
- location.advance(c); \
- ++i; \
- c = text.at(i); \
- cc = c.unicode(); \
- } while (0)
-
-#define SKIP_SPACES() \
- while (c.isSpace() && cc != '\n') \
- SKIP_CHAR()
-
-#define PUT_CHAR() \
- word += c; \
- SKIP_CHAR();
-
- if (location.depth() > 16)
- location.fatal(QStringLiteral("Too many nested includes"));
-
- QFile fin(fileInfo.fileName());
- if (!fin.open(QFile::ReadOnly | QFile::Text)) {
- if (!Config::installDir.isEmpty()) {
- qsizetype prefix = location.filePath().length() - location.fileName().length();
- fin.setFileName(Config::installDir + QLatin1Char('/')
- + fileName.right(fileName.length() - prefix));
- }
- if (!fin.open(QFile::ReadOnly | QFile::Text))
- location.fatal(
- QStringLiteral("Cannot open file '%1': %2").arg(fileName, fin.errorString()));
- }
-
- QTextStream stream(&fin);
- QString text = stream.readAll();
- text += QLatin1String("\n\n");
- text += QLatin1Char('\0');
- fin.close();
-
- location.push(fileName);
- location.start();
-
- int i = 0;
- QChar c = text.at(0);
- uint cc = c.unicode();
- while (i < text.length()) {
- if (cc == 0) {
- ++i;
- } else if (c.isSpace()) {
- SKIP_CHAR();
- } else if (cc == '#') {
- do {
- SKIP_CHAR();
- } while (cc != '\n');
- } else if (isMetaKeyChar(c)) {
- Location keyLoc = location;
- bool plus = false;
- QStringList rhsValues;
- QList<ExpandVar> expandVars;
- QString word;
- bool inQuote = false;
- bool needsExpansion = false;
-
- MetaStack stack;
- do {
- stack.process(c, location);
- SKIP_CHAR();
- } while (isMetaKeyChar(c));
-
- const QStringList keys = stack.getExpanded(location);
- SKIP_SPACES();
-
- if (keys.count() == 1 && keys.first() == QLatin1String("include")) {
- QString includeFile;
-
- if (cc != '(')
- location.fatal(QStringLiteral("Bad include syntax"));
- SKIP_CHAR();
- SKIP_SPACES();
-
- while (!c.isSpace() && cc != '#' && cc != ')') {
-
- if (cc == '$') {
- QString var;
- SKIP_CHAR();
- while (c.isLetterOrNumber() || cc == '_') {
- var += c;
- SKIP_CHAR();
- }
- if (!var.isEmpty()) {
- const QByteArray val = qgetenv(var.toLatin1().data());
- if (val.isNull()) {
- location.fatal(QStringLiteral("Environment variable '%1' undefined")
- .arg(var));
- } else {
- includeFile += QString::fromLatin1(val);
- }
- }
- } else {
- includeFile += c;
- SKIP_CHAR();
- }
- }
- SKIP_SPACES();
- if (cc != ')')
- location.fatal(QStringLiteral("Bad include syntax"));
- SKIP_CHAR();
- SKIP_SPACES();
- if (cc != '#' && cc != '\n')
- location.fatal(QStringLiteral("Trailing garbage"));
-
- /*
- Here is the recursive call.
- */
- load(location, QFileInfo(QDir(path), includeFile).filePath());
- } else {
- /*
- It wasn't an include statement, so it's something else.
- We must see either '=' or '+=' next. If not, fatal error.
- */
- if (cc == '+') {
- plus = true;
- SKIP_CHAR();
- }
- if (cc != '=')
- location.fatal(QStringLiteral("Expected '=' or '+=' after key"));
- SKIP_CHAR();
- SKIP_SPACES();
-
- for (;;) {
- if (cc == '\\') {
- qsizetype metaCharPos;
-
- SKIP_CHAR();
- if (cc == '\n') {
- SKIP_CHAR();
- } else if (cc > '0' && cc < '8') {
- word += QChar(c.digitValue());
- SKIP_CHAR();
- } else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c))
- != -1) {
- word += QLatin1Char("\a\b\f\n\r\t\v"[metaCharPos]);
- SKIP_CHAR();
- } else {
- PUT_CHAR();
- }
- } else if (c.isSpace() || cc == '#') {
- if (inQuote) {
- if (cc == '\n')
- location.fatal(QStringLiteral("Unterminated string"));
- PUT_CHAR();
- } else {
- if (!word.isEmpty() || needsExpansion) {
- rhsValues << word;
- word.clear();
- needsExpansion = false;
- }
- if (cc == '\n' || cc == '#')
- break;
- SKIP_SPACES();
- }
- } else if (cc == '"') {
- if (inQuote) {
- if (!word.isEmpty() || needsExpansion)
- rhsValues << word;
- word.clear();
- needsExpansion = false;
- }
- inQuote = !inQuote;
- SKIP_CHAR();
- } else if (cc == '$') {
- QString var;
- QChar delim(' ');
- bool braces = false;
- SKIP_CHAR();
- if (cc == '{') {
- SKIP_CHAR();
- braces = true;
- }
- while (c.isLetterOrNumber() || cc == '_') {
- var += c;
- SKIP_CHAR();
- }
- if (braces) {
- if (cc == ',') {
- SKIP_CHAR();
- delim = c;
- SKIP_CHAR();
- }
- if (cc == '}')
- SKIP_CHAR();
- else if (delim == '}')
- delim = QChar(); // null delimiter
- else
- location.fatal(QStringLiteral("Missing '}'"));
- }
- if (!var.isEmpty()) {
- const QByteArray val = qgetenv(var.toLatin1().constData());
- if (val.isNull()) {
- expandVars << ExpandVar(rhsValues.size(), word.size(), var, delim);
- needsExpansion = true;
- } else if (braces) { // ${VAR} inserts content from an env. variable for processing
- text.insert(i, QString::fromLatin1(val));
- c = text.at(i);
- cc = c.unicode();
- } else { // while $VAR simply reads the value and stores it to a config variable.
- word += QString::fromLatin1(val);
- }
- }
- } else {
- if (!inQuote && cc == '=')
- location.fatal(QStringLiteral("Unexpected '='"));
- PUT_CHAR();
- }
- }
- for (const auto &key : keys) {
- if (!keySyntax.match(key).hasMatch())
- keyLoc.fatal(QStringLiteral("Invalid key '%1'").arg(key));
-
- ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
- if (plus && m_configVars.contains(key)) {
- m_configVars[key].append(configVar);
- } else {
- m_configVars.insert(key, configVar);
- }
- }
- }
- } else {
- location.fatal(QStringLiteral("Unexpected character '%1' at beginning of line").arg(c));
- }
- }
- popWorkingDir();
- if (!m_workingDirs.isEmpty())
- QDir::setCurrent(m_workingDirs.top());
-}
-
-bool Config::isFileExcluded(const QString &fileName, const QSet<QString> &excludedFiles)
-{
- for (const QString &entry : excludedFiles) {
- if (entry.contains(QLatin1Char('*')) || entry.contains(QLatin1Char('?'))) {
- QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry));
- if (re.match(fileName).hasMatch())
- return true;
- }
- }
- return excludedFiles.contains(fileName);
-}
-
-QStringList Config::getFilesHere(const QString &uncleanDir, const QString &nameFilter,
- const Location &location, const QSet<QString> &excludedDirs,
- const QSet<QString> &excludedFiles)
-{
- QString dir =
- location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath();
- QStringList result;
- if (excludedDirs.contains(dir))
- return result;
-
- QDir dirInfo(dir);
-
- dirInfo.setNameFilters(nameFilter.split(QLatin1Char(' ')));
- dirInfo.setSorting(QDir::Name);
- dirInfo.setFilter(QDir::Files);
- QStringList fileNames = dirInfo.entryList();
- for (const auto &file : qAsConst(fileNames)) {
- if (!file.startsWith(QLatin1Char('~'))) {
- QString s = dirInfo.filePath(file);
- QString c = QDir::cleanPath(s);
- if (!isFileExcluded(c, excludedFiles))
- result.append(c);
- }
- }
-
- dirInfo.setNameFilters(QStringList(QLatin1String("*")));
- dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
- fileNames = dirInfo.entryList();
- for (const auto &file : fileNames)
- result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs,
- excludedFiles);
- return result;
-}
-
-/*!
- Push \a dir onto the stack of working directories.
- */
-void Config::pushWorkingDir(const QString &dir)
-{
- m_workingDirs.push(dir);
-}
-
-/*!
- If the stack of working directories is not empty, pop the
- top entry and return it. Otherwise return an empty string.
- */
-QString Config::popWorkingDir()
-{
- if (!m_workingDirs.isEmpty())
- return m_workingDirs.pop();
-
- qDebug() << "RETURNED EMPTY WORKING DIR";
- return QString();
-}
-
-QT_END_NAMESPACE