8#include <QtCore/qdir.h>
9#include <QtCore/qfile.h>
10#include <QtCore/qfileinfo.h>
11#include <QtCore/qlatin1stringview.h>
12#include <QtCore/qtemporaryfile.h>
13#include <QtCore/qtextstream.h>
14#include <QtCore/qvariant.h>
15#include <QtCore/qregularexpression.h>
19using namespace Qt::StringLiterals;
82 QStringLiteral(
"redirectdocumentationtodevnull");
84 QStringLiteral(
"reportmissingalttextforimages");
116
117
118
131
132
133
136 next.append(QString());
140
141
142
143
151
152
153
154
165
166
167
175
176
177
178
181 if (ch == QLatin1Char(
'{')) {
184 }
else if (ch == QLatin1Char(
'}')) {
186 location.fatal(QStringLiteral(
"Unexpected '}'"));
189 const QStringList suffixes = pop().accum;
190 const QStringList prefixes = top().next;
193 for (
const auto &prefix : prefixes) {
194 for (
const auto &suffix : suffixes)
195 top().next << prefix + suffix;
197 }
else if (ch == QLatin1Char(
',') && size() > 1) {
201 for (QString &topNext : top().next)
207
208
212 location.fatal(QStringLiteral(
"Missing '}'"));
219bool Config::m_debug =
false;
220bool Config::m_atomsDump =
false;
225QMap<QString, QString>
Config::m_extractedDirs;
226QStack<QString>
Config::m_workingDirs;
227QMap<QString, QStringList>
Config::m_includeFilesMap;
230
231
232
233
236
237
238
239
240
241
242
243
244
247 if (m_name.isEmpty())
248 return defaultString;
251 for (
const auto &value : std::as_const(m_values)) {
252 if (!result.isEmpty() && !result.endsWith(QChar(
'\n')))
253 result.append(QChar(
' '));
254 result.append(value.m_value);
260
261
265 for (
const auto &value : std::as_const(m_values))
266 result << value.m_value;
271
272
275 const auto &stringList = asStringList();
276 return QSet<QString>(stringList.cbegin(), stringList.cend());
280
281
284 return QVariant(asString()).toBool();
288
289
290
291
292
293
294
297 const QStringList strs = asStringList();
302 for (
const auto &str : strs)
308
309
310
313 m_expandVars << other.m_expandVars;
314 QList<ExpandVar>::Iterator it = m_expandVars.end();
315 it -= other.m_expandVars.size();
316 std::for_each(it, m_expandVars.end(), [
this](ExpandVar &v) {
317 v.m_valueIndex += m_values.size();
319 m_values << other.m_values;
320 m_location = other.m_location;
324
325
326
327
328
329
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
351
352
353
354
355void Config::
init(
const QString &programName,
const QStringList &args)
357 m_prog = programName;
358 processCommandLineOptions(args);
368
369
372 m_location = Location();
373 m_configVars.clear();
374 m_includeFilesMap.clear();
375 m_excludedPaths.reset();
376 m_sourceLink.reset();
377 m_internalFilePatterns.reset();
381
382
383
389 load(Location(), u":/qdoc/config/defaults.qdocconf"_s);
392 const auto setListFlag = [
this](
const QString &key,
bool test) {
393 setStringList(key, QStringList(test ? QStringLiteral(
"true") : QStringLiteral(
"false")));
395#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
404 m_parser.isSet(m_parser.noLinkErrorsOption)
405 || qEnvironmentVariableIsSet(
"QDOC_NOLINKERRORS"));
411
412
413
414
415
422 load(Location(), fileName);
423 if (m_location.isEmpty())
424 m_location = Location(fileName);
426 m_location.setEtc(
true);
430 setStringList(varName, getCanonicalPathList(varName, Validate));
443 m_reportMissingAltTextForImages =
446 if (!m_parser.isSet(m_parser.showInternalOption) && !qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL"))
451
452
453void Config::expandVariables()
455 for (
auto &configVar : m_configVars) {
456 for (
auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) {
457 Q_ASSERT(it->m_valueIndex < configVar.m_values.size());
458 const QString &key = it->m_var;
459 const auto &refVar = m_configVars.value(key);
460 if (refVar.m_name.isEmpty()) {
461 configVar.m_location.fatal(
462 QStringLiteral(
"Environment or configuration variable '%1' undefined")
464 }
else if (!refVar.m_expandVars.empty()) {
465 configVar.m_location.fatal(
466 QStringLiteral(
"Nested variable expansion not allowed"),
467 QStringLiteral(
"When expanding '%1' at %2:%3")
468 .arg(refVar.m_name, refVar.m_location.filePath(),
469 QString::number(refVar.m_location.lineNo())));
472 if (it->m_delim.isNull())
473 expanded = m_configVars.value(key).asStringList().join(QString());
475 expanded = m_configVars.value(key).asStringList().join(it->m_delim);
476 configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded);
478 configVar.m_expandVars.clear();
483
484
487 m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath()));
491
492
493
496 m_configVars[var].append(ConfigVar(var, values, QDir::currentPath()));
500
501
502void Config::processCommandLineOptions(
const QStringList &args)
504 m_parser.process(args);
506 m_defines = m_parser.values(m_parser.defineOption);
507 m_dependModules = m_parser.values(m_parser.dependsOption);
511 generateExamples = !m_parser.isSet(m_parser.noExamplesOption);
512 if (m_parser.isSet(m_parser.installDirOption))
513 installDir = m_parser.value(m_parser.installDirOption);
514 if (m_parser.isSet(m_parser.outputDirOption))
515 overrideOutputDir = QDir(m_parser.value(m_parser.outputDirOption)).absolutePath();
517 const auto outputFormats = m_parser.values(m_parser.outputFormatOption);
518 for (
const auto &format : outputFormats)
519 overrideOutputFormats.insert(format);
520 m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet(
"QDOC_DEBUG");
521 m_atomsDump = m_parser.isSet(m_parser.atomsDumpOption);
522 m_showInternal = m_parser.isSet(m_parser.showInternalOption)
523 || qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL");
525 if (m_parser.isSet(m_parser.prepareOption))
527 if (m_parser.isSet(m_parser.generateOption))
529 if (m_debug || m_parser.isSet(m_parser.logProgressOption))
531 if (m_parser.isSet(m_parser.timestampsOption))
533 if (m_parser.isSet(m_parser.useDocBookExtensions))
537void Config::setIncludePaths()
539 QDir currentDir = QDir::current();
540 const auto addIncludePaths = [
this, currentDir](
const char *flag,
const QStringList &paths) {
541 for (
const auto &path : paths)
542 m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag);
545 addIncludePaths(
"-I", m_parser.values(m_parser.includePathOption));
546#ifdef QDOC_PASS_ISYSTEM
547 addIncludePaths(
"-isystem", m_parser.values(m_parser.includePathSystemOption));
549 addIncludePaths(
"-F", m_parser.values(m_parser.frameworkOption));
553
554
555void Config::setIndexDirs()
557 m_indexDirs = m_parser.values(m_parser.indexDirOption);
558 auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(),
559 [](
const QString &s) {
return !QFile::exists(s); });
561 std::for_each(it, m_indexDirs.end(), [](
const QString &s) {
562 qCWarning(lcQdoc) <<
"Cannot find index directory: " << s;
564 m_indexDirs.erase(it, m_indexDirs.end());
568
569
570
571
572
576 if (overrideOutputDir.isNull())
579 t = overrideOutputDir;
582 t += QLatin1Char(
'/') + project.toLower();
584 if (m_configVars.value(format + Config::dot +
"nosubdirs").asBool()) {
585 QString singleOutputSubdir = m_configVars.value(format + Config::dot +
"outputsubdir").asString();
586 if (singleOutputSubdir.isEmpty())
587 singleOutputSubdir =
"html";
588 t += QLatin1Char(
'/') + singleOutputSubdir;
590 return QDir::cleanPath(t);
594
595
596
597
600 if (overrideOutputFormats.isEmpty())
603 return overrideOutputFormats;
621
622
623
624
625
626
630 const auto &configVar = m_configVars.value(var);
632 for (
const auto &value : configVar.m_values) {
633 const QString ¤tPath = value.m_path;
634 QString rawValue = value.m_value.simplified();
637 if (flags & IncludePaths) {
638 const QStringList prefixes = QStringList()
639 << QLatin1String(
"-I")
640 << QLatin1String(
"-F")
641 << QLatin1String(
"-isystem");
642 const auto end = std::end(prefixes);
644 std::find_if(std::begin(prefixes), end,
645 [&rawValue](
const QString &p) {
646 return rawValue.startsWith(p);
650 rawValue.remove(0, it->size());
651 if (rawValue.isEmpty())
654 prefix = prefixes[0];
658 QDir dir(rawValue.trimmed());
659 const QString path = dir.path();
661 if (dir.isRelative())
662 dir.setPath(currentPath + QLatin1Char(
'/') + path);
663 if ((flags & Validate) && !QFileInfo::exists(dir.path()))
664 configVar.m_location.warning(QStringLiteral(
"Cannot find file or directory: %1").arg(path));
666 const QString canonicalPath = dir.canonicalPath();
667 if (!canonicalPath.isEmpty())
668 result.append(prefix + canonicalPath);
669 else if (path.contains(QLatin1Char(
'*')) || path.contains(QLatin1Char(
'?')))
673 qUtf8Printable(QStringLiteral(
"%1: Ignored nonexistent path \'%2\'")
674 .arg(configVar.m_location.toString(), rawValue));
681
682
683
684
685
686
687
691 const auto subRegExps = getRegExpList(var);
693 for (
const auto ®Exp : subRegExps) {
694 if (!regExp.isValid())
696 if (!pattern.isEmpty())
697 pattern += QLatin1Char(
'|');
698 pattern += QLatin1String(
"(?:") + regExp.pattern() + QLatin1Char(
')');
700 if (pattern.isEmpty())
701 pattern = QLatin1String(
"$x");
702 return QRegularExpression(pattern);
706
707
708
709
712 const QStringList strs = m_configVars.value(var).asStringList();
713 QList<QRegularExpression> regExps;
714 for (
const auto &str : strs)
715 regExps += QRegularExpression(str);
720
721
722
723
724
727 QSet<QString> result;
728 QString varDot = var + QLatin1Char(
'.');
729 for (
auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) {
730 if (it.key().startsWith(varDot)) {
731 QString subVar = it.key().mid(varDot.size());
732 int dot = subVar.indexOf(QLatin1Char(
'.'));
734 subVar.truncate(dot);
735 result.insert(subVar);
742
743
744
745
748 QString ext = QFileInfo(fileName).suffix();
750 if (!m_includeFilesMap.contains(ext)) {
752 result.erase(std::remove_if(result.begin(), result.end(),
753 [&](
const QString &s) {
return !s.endsWith(ext); }),
755 const QStringList dirs =
759 for (
const auto &dir : dirs)
760 result += getFilesHere(dir,
"*." + ext, location());
761 result.removeDuplicates();
762 m_includeFilesMap.insert(ext, result);
764 const QStringList &paths = (*m_includeFilesMap.find(ext));
765 QString match = fileName;
766 if (!match.startsWith(
'/'))
768 for (
const auto &path : paths) {
769 if (path.endsWith(match))
776
777
778
779
780
781
782
783
785 const QSet<QString> &excludedDirs,
786 const QSet<QString> &excludedFiles)
788 QStringList result = getCanonicalPathList(filesVar, Validate);
789 const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
793 for (
const auto &dir : dirs)
794 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
799 const QSet<QString> &excludedFiles)
802 const QStringList dirs = getCanonicalPathList(
"exampledirs");
803 const QString nameFilter =
" *.qdoc";
805 for (
const auto &dir : dirs)
806 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
811 const QSet<QString> &excludedFiles)
814 const QStringList dirs = getCanonicalPathList(
"exampledirs");
817 for (
const auto &dir : dirs)
818 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
830
831
832
835 QFileInfo fileInfo(examplePath);
836 QStringList validNames;
837 validNames << QLatin1String(
"CMakeLists.txt")
838 << fileInfo.fileName() + QLatin1String(
".pro")
839 << fileInfo.fileName() + QLatin1String(
".qmlproject")
840 << fileInfo.fileName() + QLatin1String(
".pyproject")
841 << QLatin1String(
"qbuild.pro");
845 for (
const auto &name : std::as_const(validNames)) {
846 projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs,
847 examplePath + QLatin1Char(
'/') + name);
848 if (!projectFile.isEmpty())
874
875
876
877
878
879
880
881
883 const QStringList &dirs,
const QString &fileName,
884 QString *userFriendlyFilePath)
886 if (fileName.isEmpty() || fileName.startsWith(QLatin1Char(
'/'))) {
887 if (userFriendlyFilePath)
888 *userFriendlyFilePath = fileName;
893 QStringList components = fileName.split(QLatin1Char(
'?'));
894 QString firstComponent = components.first();
896 for (
const auto &file : files) {
897 if (file == firstComponent || file.endsWith(QLatin1Char(
'/') + firstComponent)) {
898 fileInfo.setFile(file);
899 if (!fileInfo.exists())
900 location.fatal(QStringLiteral(
"File '%1' does not exist").arg(file));
905 if (fileInfo.fileName().isEmpty()) {
906 for (
const auto &dir : dirs) {
907 fileInfo.setFile(QDir(dir), firstComponent);
908 if (fileInfo.exists())
913 if (userFriendlyFilePath)
914 userFriendlyFilePath->clear();
915 if (!fileInfo.exists())
925 if (userFriendlyFilePath) {
926 for (
auto c = components.constBegin();;) {
927 bool isArchive = (c != components.constEnd() - 1);
928 userFriendlyFilePath->append(*c);
931 QString extracted = m_extractedDirs[fileInfo.filePath()];
934 fileInfo.setFile(QDir(extracted), *c);
939 userFriendlyFilePath->append(QLatin1Char(
'?'));
944 return fileInfo.filePath();
960
961
962
963
964
965
967 const QString &userFriendlySourceFilePath,
const QString &targetDirPath)
978 QFile inFile(sourceFilePath);
979 if (!inFile.open(QFile::ReadOnly)) {
980 location.warning(QStringLiteral(
"Cannot open input file for copy: '%1': %2")
981 .arg(sourceFilePath, inFile.errorString()));
1019 QString outFileName{userFriendlySourceFilePath};
1020 QFileInfo outFileNameInfo{userFriendlySourceFilePath};
1021 if (outFileNameInfo.isAbsolute())
1022 outFileName = outFileNameInfo.fileName();
1024 outFileName = targetDirPath +
"/" + outFileName;
1025 QDir targetDir(targetDirPath);
1026 if (!targetDir.exists())
1027 targetDir.mkpath(
".");
1029 QFile outFile(outFileName);
1030 if (!outFile.open(QFile::WriteOnly)) {
1032 location.warning(QStringLiteral(
"Cannot open output file for copy: '%1': %2")
1033 .arg(outFileName, outFile.errorString()));
1045 while ((len = inFile.read(buffer,
sizeof(buffer))) > 0)
1046 outFile.write(buffer, len);
1051
1052
1053
1057 for (
int i = 0; i != value.size(); ++i) {
1058 uint c = value[i].unicode();
1060 max = qMax(max,
static_cast<
int>(c));
1066
1067
1068
1069bool Config::isMetaKeyChar(QChar ch)
1071 return ch.isLetterOrNumber() || ch == QLatin1Char(
'_') || ch == QLatin1Char(
'.')
1072 || ch == QLatin1Char(
'{') || ch == QLatin1Char(
'}') || ch == QLatin1Char(
',');
1076
1077
1078
1079QStringList
Config::loadMaster(
const QString &fileName)
1082 QFile fin(fileName);
1083 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1084 if (!Config::installDir.isEmpty()) {
1085 qsizetype prefix = location.filePath().size() - location.fileName().size();
1086 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1087 + fileName.right(fileName.size() - prefix));
1089 if (!fin.open(QFile::ReadOnly | QFile::Text))
1090 location.fatal(QStringLiteral(
"Cannot open master qdocconf file '%1': %2")
1091 .arg(fileName, fin.errorString()));
1093 QTextStream stream(&fin);
1094 QStringList qdocFiles;
1095 QDir configDir(QFileInfo(fileName).canonicalPath());
1096 QString line = stream.readLine();
1097 while (!line.isNull()) {
1098 if (!line.isEmpty())
1099 qdocFiles.append(QFileInfo(configDir, line).filePath());
1100 line = stream.readLine();
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1120 QFileInfo fileInfo(fileName);
1121 const bool isResource = fileName.startsWith(u':');
1123 pushWorkingDir(fileInfo.canonicalPath());
1124 static const QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String(
"\\w+(?:\\.\\w+)*")));
1128 location.advance(c);
1134#define SKIP_SPACES()
1135 while (c.isSpace() && cc != '\n')
1143 location.fatal(QStringLiteral(
"Too many nested includes"));
1145 QFile fin(isResource ? fileInfo.filePath() : fileInfo.fileName());
1146 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1147 if (!Config::installDir.isEmpty()) {
1148 qsizetype prefix = location.filePath().size() - location.fileName().size();
1149 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1150 + fileName.right(fileName.size() - prefix));
1152 if (!fin.open(QFile::ReadOnly | QFile::Text))
1154 QStringLiteral(
"Cannot open file '%1': %2").arg(fileName, fin.errorString()));
1157 QTextStream stream(&fin);
1158 QString text = stream.readAll();
1159 text += QLatin1String(
"\n\n");
1160 text += QLatin1Char(
'\0');
1163 location.push(fileName);
1167 QChar c = text.at(0);
1168 uint cc = c.unicode();
1169 while (i < text.size()) {
1172 }
else if (c.isSpace()) {
1174 }
else if (cc ==
'#') {
1177 }
while (cc !=
'\n');
1178 }
else if (isMetaKeyChar(c)) {
1181 QStringList rhsValues;
1182 QList<ExpandVar> expandVars;
1184 bool inQuote =
false;
1185 bool needsExpansion =
false;
1189 stack.process(c, location);
1191 }
while (isMetaKeyChar(c));
1193 const QStringList keys = stack.getExpanded(location);
1196 if (keys.size() == 1 && keys.first() == QLatin1String(
"include")) {
1197 QString includeFile;
1200 location.fatal(QStringLiteral(
"Bad include syntax"));
1204 while (!c.isSpace() && cc !=
'#' && cc !=
')') {
1209 while (c.isLetterOrNumber() || cc ==
'_') {
1213 if (!var.isEmpty()) {
1214 const QByteArray val = qgetenv(var.toLatin1().data());
1216 location.fatal(QStringLiteral(
"Environment variable '%1' undefined")
1219 includeFile += QString::fromLatin1(val);
1229 location.fatal(QStringLiteral(
"Bad include syntax"));
1232 if (cc !=
'#' && cc !=
'\n')
1233 location.fatal(QStringLiteral(
"Trailing garbage"));
1236
1237
1239 load(location, includeFile);
1241 load(location, QFileInfo(QDir(m_workingDirs.top()), includeFile).filePath());
1244
1245
1246
1252 location.fatal(QStringLiteral(
"Expected '=' or '+=' after key"));
1258 qsizetype metaCharPos;
1263 }
else if (cc >
'0' && cc <
'8') {
1264 word += QChar(c.digitValue());
1266 }
else if ((metaCharPos = QString::fromLatin1(
"abfnrtv").indexOf(c))
1268 word += QLatin1Char(
"\a\b\f\n\r\t\v"[metaCharPos]);
1273 }
else if (c.isSpace() || cc ==
'#') {
1276 location.fatal(QStringLiteral(
"Unterminated string"));
1279 if (!word.isEmpty() || needsExpansion) {
1282 needsExpansion =
false;
1284 if (cc ==
'\n' || cc ==
'#')
1288 }
else if (cc ==
'"') {
1290 if (!word.isEmpty() || needsExpansion)
1293 needsExpansion =
false;
1297 }
else if (cc ==
'$') {
1300 bool braces =
false;
1306 while (c.isLetterOrNumber() || cc ==
'_') {
1318 else if (delim ==
'}')
1321 location.fatal(QStringLiteral(
"Missing '}'"));
1323 if (!var.isEmpty()) {
1324 const QByteArray val = qgetenv(var.toLatin1().constData());
1326 expandVars <<
ExpandVar(rhsValues.size(), word.size(),
std::move(var), delim);
1327 needsExpansion =
true;
1328 }
else if (braces) {
1329 text.insert(i, QString::fromLatin1(val));
1333 word += QString::fromLatin1(val);
1337 if (!inQuote && cc ==
'=')
1338 location.fatal(QStringLiteral(
"Unexpected '='"));
1342 for (
const auto &key : keys) {
1343 if (!keySyntax.match(key).hasMatch())
1344 keyLoc.fatal(QStringLiteral(
"Invalid key '%1'").arg(key));
1346 ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
1347 if (plus && m_configVars.contains(key)) {
1348 m_configVars[key].append(configVar);
1350 m_configVars.insert(key, configVar);
1355 location.fatal(QStringLiteral(
"Unexpected character '%1' at beginning of line").arg(c));
1366bool Config::isFileExcluded(
const QString &fileName,
const QSet<QString> &excludedFiles)
1368 for (
const QString &entry : excludedFiles) {
1369 if (entry.contains(QLatin1Char(
'*')) || entry.contains(QLatin1Char(
'?'))) {
1370 QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry));
1371 if (re.match(fileName).hasMatch())
1375 return excludedFiles.contains(fileName);
1378QStringList
Config::getFilesHere(
const QString &uncleanDir,
const QString &nameFilter,
1379 const Location &location,
const QSet<QString> &excludedDirs,
1380 const QSet<QString> &excludedFiles)
1385 location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath();
1387 if (excludedDirs.contains(dir))
1392 dirInfo.setNameFilters(nameFilter.split(QLatin1Char(
' ')));
1393 dirInfo.setSorting(QDir::Name);
1394 dirInfo.setFilter(QDir::Files);
1395 QStringList fileNames = dirInfo.entryList();
1396 for (
const auto &file : std::as_const(fileNames)) {
1399 if (!file.startsWith(QLatin1Char(
'~'))) {
1400 QString s = dirInfo.filePath(file);
1401 QString c = QDir::cleanPath(s);
1402 if (!isFileExcluded(c, excludedFiles))
1407 dirInfo.setNameFilters(QStringList(QLatin1String(
"*")));
1408 dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1409 fileNames = dirInfo.entryList();
1410 for (
const auto &file : fileNames)
1411 result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs,
1417
1418
1419
1420void Config::pushWorkingDir(
const QString &dir)
1422 m_workingDirs.push(dir);
1423 QDir::setCurrent(dir);
1427
1428
1429
1430
1433 Q_ASSERT(!m_workingDirs.isEmpty());
1434 m_workingDirs.pop();
1435 if (!m_workingDirs.isEmpty())
1436 QDir::setCurrent(m_workingDirs.top());
1440 if (m_excludedPaths)
1441 return *m_excludedPaths;
1446 QSet<QString> excludedDirs = QSet<QString>(excludedDirList.cbegin(), excludedDirList.cend());
1447 QSet<QString> excludedFiles = QSet<QString>(excludedFilesList.cbegin(), excludedFilesList.cend());
1449 m_excludedPaths.emplace(ExcludedPaths{std::move(excludedDirs), std::move(excludedFiles)});
1451 return *m_excludedPaths;
1455
1456
1457
1458
1459
1460
1461
1465 return QSet<QString>(patterns.cbegin(), patterns.cend());
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1483 if (m_internalFilePatterns)
1484 return *m_internalFilePatterns;
1489 for (
const QString &pattern : patterns) {
1490 static const QRegularExpression regexMetaChars(
1491 uR"(\.\*|\.\+|\.\{|\\[\.\*\?]|[\^\$\[\]{}()|+])"_s);
1492 bool isRawRegex = regexMetaChars.match(pattern).hasMatch();
1495 QRegularExpression re(pattern);
1496 if (!re.isValid()) {
1497 qWarning() <<
"Invalid regex pattern in internalfilepatterns:" << pattern
1498 <<
"-" << re.errorString();
1502 compiled.regexPatterns.append(re);
1503 }
else if (pattern.contains(u'*') || pattern.contains(u'?')) {
1504 QString regexPattern = QRegularExpression::wildcardToRegularExpression(pattern);
1505 QRegularExpression re(regexPattern);
1507 compiled.globPatterns.append(re);
1509 compiled.exactMatches.insert(pattern);
1513 m_internalFilePatterns.emplace(std::move(compiled));
1514 return *m_internalFilePatterns;
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532bool Config::matchesInternalFilePattern(
const QString &filePath,
1535 if (patterns.exactMatches.isEmpty() && patterns.globPatterns.isEmpty()
1536 && patterns.regexPatterns.isEmpty())
1539 QString norm = filePath;
1540 norm.replace(QChar(
'\\'), QChar(
'/'));
1542 if (patterns.exactMatches.contains(norm))
1545 const QString fileName = QFileInfo(norm).fileName();
1546 for (
const QRegularExpression &re : patterns.globPatterns) {
1547 if (re.match(fileName).hasMatch())
1551 for (
const QRegularExpression &re : patterns.regexPatterns) {
1552 if (re.match(norm).hasMatch())
1560
1561
1562
1566 return *m_sourceLink;
1570 const auto baseUrl = m_configVars.value(srcUrl).asString();
1571 const auto rootPath = m_configVars.value(srcUrl + dot +
CONFIG_ROOTDIR).asString();
1572 const auto linkText = m_configVars.value(srcUrl + dot +
"linktext").asString();
1573 const auto enabled = m_configVars.value(srcUrl + dot +
"enabled").asBool();
1575 m_sourceLink.emplace(SourceLink{baseUrl, rootPath, linkText, enabled});
1576 return *m_sourceLink;
1580 static QStringList accepted_header_file_extensions{
1581 "ch",
"h",
"h++",
"hh",
"hpp",
"hxx"
1586 QStringList headerList =
1589 std::set<HeaderFilePath> headers{};
1591 for (
const auto& header : headerList) {
1592 if (header.contains(
"doc/snippets"))
continue;
1594 if (!accepted_header_file_extensions.contains(QFileInfo{header}.suffix()))
1597 headers.insert(HeaderFilePath{QFileInfo{header}.canonicalPath(), QFileInfo{header}.fileName()});
1610 InclusionPolicy policy;
contains all the information for a single config variable in a .qdocconf file.
QString asString(const QString defaultString=QString()) const
Returns this configuration variable as a string.
QStringList asStringList() const
Returns this config variable as a string list.
int asInt() const
Returns this configuration variable as an integer; iterates through the string list,...
bool asBool() const
Returns this config variable as a boolean.
QSet< QString > asStringSet() const
Returns this config variable as a string set.
The Config class contains the configuration variables for controlling how qdoc produces documentation...
static QString installDir
QString getOutputDir(const QString &format=QString("HTML")) const
Function to return the correct outputdir for the output format.
std::set< HeaderFilePath > getHeaderFiles()
static bool generateExamples
void insertStringList(const QString &var, const QStringList &values)
Adds the values from a string list to the configuration variable var.
QStringList getAllFiles(const QString &filesVar, const QString &dirsVar, const QSet< QString > &excludedDirs=QSet< QString >(), const QSet< QString > &excludedFiles=QSet< QString >())
Builds and returns a list of file pathnames for the file type specified by filesVar (e....
QSet< QString > getInternalFilePatterns() const
Returns the set of file patterns that identify internal implementation files.
void reset()
Resets the Config instance and loads the default values.
InclusionPolicy createInclusionPolicy() const
void setStringList(const QString &var, const QStringList &values)
Sets the values of a configuration variable var from a string list.
void clear()
Clears the location and internal maps for config variables.
QSet< QString > subVars(const QString &var) const
This function is slower than it could be.
bool includePrivateType() const
PathFlags
Flags used for retrieving canonicalized paths from Config.
bool includePrivateVariable() const
const ExcludedPaths & getExcludedPaths()
QSet< QString > getOutputFormats() const
Function to return the correct outputformats.
static void popWorkingDir()
Pop the top entry from the stack of working directories.
bool showAutoGeneratedDocs() const
QRegularExpression getRegExp(const QString &var) const
Calls getRegExpList() with the control variable var and iterates through the resulting list of regula...
QString getExampleProjectFile(const QString &examplePath)
Returns the path to the project file for examplePath, or an empty string if no project file was found...
bool includePrivateFunction() const
static QSet< QString > overrideOutputFormats
static QString overrideOutputDir
QStringList getCanonicalPathList(const QString &var, PathFlags flags=None) const
Returns a path list where all paths from the config variable var are canonicalized.
void load(const QString &fileName)
Loads and parses the qdoc configuration file fileName.
const SourceLink & getSourceLink()
Returns a SourceLink struct with settings required to construct source links to API entities.
bool showInternal() const
QList< QRegularExpression > getRegExpList(const QString &var) const
Looks up the configuration variable var in the string list map, converts the string list to a list of...
QStringList getExampleImageFiles(const QSet< QString > &excludedDirs, const QSet< QString > &excludedFiles)
QStringList getExampleQdocFiles(const QSet< QString > &excludedDirs, const QSet< QString > &excludedFiles)
const InternalFilePatterns & getInternalFilePatternsCompiled()
Returns a reference to the pre-compiled internal file patterns structure.
void init(const QString &programName, const QStringList &args)
Initializes the Config with programName and sets all internal state variables to either default value...
QString getIncludeFilePath(const QString &fileName) const
Searches for a path to fileName in 'sources', 'sourcedirs', and 'exampledirs' config variables and re...
The Location class provides a way to mark a location in a file.
void start()
If the file position on top of the stack has a line number less than 1, set its line number to 1 and ...
An entry in a stack, where each entry is a list of string values.
void close()
Stop accumulating values and append the list of accumulated values to the complete list of accumulate...
void open()
Start accumulating values in a list by appending an empty string to the list.
Q_DECLARE_TYPEINFO(MetaStackEntry, Q_RELOCATABLE_TYPE)
#define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL
#define CONFIG_FILEEXTENSIONS
#define CONFIG_AUTOLINKERRORS
#define CONFIG_SHOWINTERNAL
#define CONFIG_SHOWAUTOGENERATEDDOCS
#define CONFIG_DOCBOOKEXTENSIONS
#define CONFIG_SINGLEEXEC
#define CONFIG_EXAMPLEDIRS
#define CONFIG_SYNTAXHIGHLIGHTING
#define CONFIG_TIMESTAMPS
#define CONFIG_NOLINKERRORS
#define CONFIG_LOGPROGRESS
#define CONFIG_SOURCEDIRS
#define CONFIG_INTERNALFILEPATTERNS
#define CONFIG_OUTPUTFORMATS
#define CONFIG_IMAGEEXTENSIONS
#define CONFIG_EXCLUDEFILES
#define CONFIG_EXCLUDEDIRS
#define CONFIG_HEADERDIRS
#define CONFIG_REPORTMISSINGALTTEXTFORIMAGES
#define CONFIG_INCLUDEPATHS
Combined button and popup list for selecting options.
static QString HEADERSTYLES
static QString IGNORESINCE
static QString CODESUFFIX
static QString EXAMPLEDIRS
static QString CODEINDENT
static QString CODELANGUAGES
static QString HEADERDIRS
static QString NATURALLANGUAGE
static QString WARNABOUTMISSINGPROJECTFILES
static QString SINGLEEXEC
static QString SOURCEDIRS
static QString IGNOREDIRECTIVES
static QString SHOWAUTOGENERATEDDOCS
static QString EXCLUDEDIRS
static QString FILEEXTENSIONS
static QString AUTOLINKERRORS
static QString LOGWARNINGSDISABLECLIARGS
static QString OUTPUTFORMATS
static QString REDIRECTDOCUMENTATIONTODEVNULL
static QString LANDINGPAGE
static QString MODULEHEADER
static QString CPPCLASSESPAGE
static QString PRODUCTNAME
static QString BUILDVERSION
static QString DOCBOOKEXTENSIONS
static QString VERSIONSYM
static QString IMAGEEXTENSIONS
static QString EXAMPLESINSTALLPATH
static QString INCLUDEPRIVATE
static QString HEADERSCRIPTS
static QString SOURCEENCODING
static QString IGNORETOKENS
static QString NAVIGATION
static QString SYNTAXHIGHLIGHTING
static QString IGNOREWORDS
static QString INCLUDEPATHS
static QString WARNINGLIMIT
static QString STYLESHEETS
static QString LANDINGTITLE
static QString USEALTTEXTASTITLE
static QString CODEPREFIX
static QString LOGPROGRESS
static QString FALSEHOODS
static QString IMAGESOUTPUTDIR
static QString TRADEMARKSPAGE
static QString QMLTYPESPAGE
static QString LOGWARNINGS
static QString EXCLUDEFILES
static QString EXTRAIMAGES
static QString PRELIMINARY
static QString NOLINKERRORS
static QString LOCATIONINFO
static QString TIMESTAMPS
static QString WARNABOUTMISSINGIMAGES
static QString DOCUMENTATIONINHEADERS
static QString SHOWINTERNAL
static QString CPPCLASSESTITLE
static QString QUOTINGINFORMATION
static QString FORMATTING
static QString MANIFESTMETA
static QString OUTPUTPREFIXES
static QString DESCRIPTION
static QString REPORTMISSINGALTTEXTFORIMAGES
static QString INTERNALFILEPATTERNS
static QString OUTPUTSUFFIXES
static QString PROJECTROOT
static QString QMLTYPESTITLE