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
403 QStringList(
"This \1 is under development and is subject to change."));
406 const auto setListFlag = [
this](
const QString &key,
bool test) {
407 setStringList(key, QStringList(test ? QStringLiteral(
"true") : QStringLiteral(
"false")));
409#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
418 m_parser.isSet(m_parser.noLinkErrorsOption)
419 || qEnvironmentVariableIsSet(
"QDOC_NOLINKERRORS"));
425
426
427
428
429
436 load(Location(), fileName);
437 if (m_location.isEmpty())
438 m_location = Location(fileName);
440 m_location.setEtc(
true);
444 setStringList(varName, getCanonicalPathList(varName, Validate));
457 m_reportMissingAltTextForImages =
460 if (!m_parser.isSet(m_parser.showInternalOption) && !qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL"))
465
466
467void Config::expandVariables()
469 for (
auto &configVar : m_configVars) {
470 for (
auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) {
471 Q_ASSERT(it->m_valueIndex < configVar.m_values.size());
472 const QString &key = it->m_var;
473 const auto &refVar = m_configVars.value(key);
474 if (refVar.m_name.isEmpty()) {
475 configVar.m_location.fatal(
476 QStringLiteral(
"Environment or configuration variable '%1' undefined")
478 }
else if (!refVar.m_expandVars.empty()) {
479 configVar.m_location.fatal(
480 QStringLiteral(
"Nested variable expansion not allowed"),
481 QStringLiteral(
"When expanding '%1' at %2:%3")
482 .arg(refVar.m_name, refVar.m_location.filePath(),
483 QString::number(refVar.m_location.lineNo())));
486 if (it->m_delim.isNull())
487 expanded = m_configVars.value(key).asStringList().join(QString());
489 expanded = m_configVars.value(key).asStringList().join(it->m_delim);
490 configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded);
492 configVar.m_expandVars.clear();
497
498
501 m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath()));
505
506
507
510 m_configVars[var].append(ConfigVar(var, values, QDir::currentPath()));
514
515
516void Config::processCommandLineOptions(
const QStringList &args)
518 m_parser.process(args);
520 m_defines = m_parser.values(m_parser.defineOption);
521 m_dependModules = m_parser.values(m_parser.dependsOption);
525 generateExamples = !m_parser.isSet(m_parser.noExamplesOption);
526 if (m_parser.isSet(m_parser.installDirOption))
527 installDir = m_parser.value(m_parser.installDirOption);
528 if (m_parser.isSet(m_parser.outputDirOption))
529 overrideOutputDir = QDir(m_parser.value(m_parser.outputDirOption)).absolutePath();
531 const auto outputFormats = m_parser.values(m_parser.outputFormatOption);
532 for (
const auto &format : outputFormats)
533 overrideOutputFormats.insert(format);
534 m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet(
"QDOC_DEBUG");
535 m_atomsDump = m_parser.isSet(m_parser.atomsDumpOption);
536 m_showInternal = m_parser.isSet(m_parser.showInternalOption)
537 || qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL");
539 if (m_parser.isSet(m_parser.prepareOption))
541 if (m_parser.isSet(m_parser.generateOption))
543 if (m_debug || m_parser.isSet(m_parser.logProgressOption))
545 if (m_parser.isSet(m_parser.timestampsOption))
547 if (m_parser.isSet(m_parser.useDocBookExtensions))
551void Config::setIncludePaths()
553 QDir currentDir = QDir::current();
554 const auto addIncludePaths = [
this, currentDir](
const char *flag,
const QStringList &paths) {
555 for (
const auto &path : paths)
556 m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag);
559 addIncludePaths(
"-I", m_parser.values(m_parser.includePathOption));
560#ifdef QDOC_PASS_ISYSTEM
561 addIncludePaths(
"-isystem", m_parser.values(m_parser.includePathSystemOption));
563 addIncludePaths(
"-F", m_parser.values(m_parser.frameworkOption));
567
568
569void Config::setIndexDirs()
571 m_indexDirs = m_parser.values(m_parser.indexDirOption);
572 auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(),
573 [](
const QString &s) {
return !QFile::exists(s); });
575 std::for_each(it, m_indexDirs.end(), [](
const QString &s) {
576 qCWarning(lcQdoc) <<
"Cannot find index directory: " << s;
578 m_indexDirs.erase(it, m_indexDirs.end());
582
583
584
585
586
590 if (overrideOutputDir.isNull())
593 t = overrideOutputDir;
596 t += QLatin1Char(
'/') + project.toLower();
598 if (m_configVars.value(format + Config::dot +
"nosubdirs").asBool()) {
599 QString singleOutputSubdir = m_configVars.value(format + Config::dot +
"outputsubdir").asString();
600 if (singleOutputSubdir.isEmpty())
601 singleOutputSubdir =
"html";
602 t += QLatin1Char(
'/') + singleOutputSubdir;
604 return QDir::cleanPath(t);
608
609
610
611
614 if (overrideOutputFormats.isEmpty())
617 return overrideOutputFormats;
635
636
637
638
639
640
644 const auto &configVar = m_configVars.value(var);
646 for (
const auto &value : configVar.m_values) {
647 const QString ¤tPath = value.m_path;
648 QString rawValue = value.m_value.simplified();
651 if (flags & IncludePaths) {
652 const QStringList prefixes = QStringList()
653 << QLatin1String(
"-I")
654 << QLatin1String(
"-F")
655 << QLatin1String(
"-isystem");
656 const auto end = std::end(prefixes);
658 std::find_if(std::begin(prefixes), end,
659 [&rawValue](
const QString &p) {
660 return rawValue.startsWith(p);
664 rawValue.remove(0, it->size());
665 if (rawValue.isEmpty())
668 prefix = prefixes[0];
672 QDir dir(rawValue.trimmed());
673 const QString path = dir.path();
675 if (dir.isRelative())
676 dir.setPath(currentPath + QLatin1Char(
'/') + path);
677 if ((flags & Validate) && !QFileInfo::exists(dir.path()))
678 configVar.m_location.warning(QStringLiteral(
"Cannot find file or directory: %1").arg(path));
680 const QString canonicalPath = dir.canonicalPath();
681 if (!canonicalPath.isEmpty())
682 result.append(prefix + canonicalPath);
683 else if (path.contains(QLatin1Char(
'*')) || path.contains(QLatin1Char(
'?')))
687 qUtf8Printable(QStringLiteral(
"%1: Ignored nonexistent path \'%2\'")
688 .arg(configVar.m_location.toString(), rawValue));
695
696
697
698
699
700
701
705 const auto subRegExps = getRegExpList(var);
707 for (
const auto ®Exp : subRegExps) {
708 if (!regExp.isValid())
710 if (!pattern.isEmpty())
711 pattern += QLatin1Char(
'|');
712 pattern += QLatin1String(
"(?:") + regExp.pattern() + QLatin1Char(
')');
714 if (pattern.isEmpty())
715 pattern = QLatin1String(
"$x");
716 return QRegularExpression(pattern);
720
721
722
723
726 const QStringList strs = m_configVars.value(var).asStringList();
727 QList<QRegularExpression> regExps;
728 for (
const auto &str : strs)
729 regExps += QRegularExpression(str);
734
735
736
737
738
741 QSet<QString> result;
742 QString varDot = var + QLatin1Char(
'.');
743 for (
auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) {
744 if (it.key().startsWith(varDot)) {
745 QString subVar = it.key().mid(varDot.size());
746 int dot = subVar.indexOf(QLatin1Char(
'.'));
748 subVar.truncate(dot);
749 result.insert(subVar);
756
757
758
759
762 QString ext = QFileInfo(fileName).suffix();
764 if (!m_includeFilesMap.contains(ext)) {
766 result.erase(std::remove_if(result.begin(), result.end(),
767 [&](
const QString &s) {
return !s.endsWith(ext); }),
769 const QStringList dirs =
773 for (
const auto &dir : dirs)
774 result += getFilesHere(dir,
"*." + ext, location());
775 result.removeDuplicates();
776 m_includeFilesMap.insert(ext, result);
778 const QStringList &paths = (*m_includeFilesMap.find(ext));
779 QString match = fileName;
780 if (!match.startsWith(
'/'))
782 for (
const auto &path : paths) {
783 if (path.endsWith(match))
790
791
792
793
794
795
796
797
799 const QSet<QString> &excludedDirs,
800 const QSet<QString> &excludedFiles)
802 QStringList result = getCanonicalPathList(filesVar, Validate);
803 const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
807 for (
const auto &dir : dirs)
808 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
813 const QSet<QString> &excludedFiles)
816 const QStringList dirs = getCanonicalPathList(
"exampledirs");
817 const QString nameFilter =
" *.qdoc";
819 for (
const auto &dir : dirs)
820 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
825 const QSet<QString> &excludedFiles)
828 const QStringList dirs = getCanonicalPathList(
"exampledirs");
831 for (
const auto &dir : dirs)
832 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
844
845
846
849 QFileInfo fileInfo(examplePath);
850 QStringList validNames;
851 validNames << QLatin1String(
"CMakeLists.txt")
852 << fileInfo.fileName() + QLatin1String(
".pro")
853 << fileInfo.fileName() + QLatin1String(
".qmlproject")
854 << fileInfo.fileName() + QLatin1String(
".pyproject")
855 << QLatin1String(
"qbuild.pro");
859 for (
const auto &name : std::as_const(validNames)) {
860 projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs,
861 examplePath + QLatin1Char(
'/') + name);
862 if (!projectFile.isEmpty())
888
889
890
891
892
893
894
895
897 const QStringList &dirs,
const QString &fileName,
898 QString *userFriendlyFilePath)
900 if (fileName.isEmpty() || fileName.startsWith(QLatin1Char(
'/'))) {
901 if (userFriendlyFilePath)
902 *userFriendlyFilePath = fileName;
907 QStringList components = fileName.split(QLatin1Char(
'?'));
908 QString firstComponent = components.first();
910 for (
const auto &file : files) {
911 if (file == firstComponent || file.endsWith(QLatin1Char(
'/') + firstComponent)) {
912 fileInfo.setFile(file);
913 if (!fileInfo.exists())
914 location.fatal(QStringLiteral(
"File '%1' does not exist").arg(file));
919 if (fileInfo.fileName().isEmpty()) {
920 for (
const auto &dir : dirs) {
921 fileInfo.setFile(QDir(dir), firstComponent);
922 if (fileInfo.exists())
927 if (userFriendlyFilePath)
928 userFriendlyFilePath->clear();
929 if (!fileInfo.exists())
939 if (userFriendlyFilePath) {
940 for (
auto c = components.constBegin();;) {
941 bool isArchive = (c != components.constEnd() - 1);
942 userFriendlyFilePath->append(*c);
945 QString extracted = m_extractedDirs[fileInfo.filePath()];
948 fileInfo.setFile(QDir(extracted), *c);
953 userFriendlyFilePath->append(QLatin1Char(
'?'));
958 return fileInfo.filePath();
974
975
976
977
978
979
981 const QString &userFriendlySourceFilePath,
const QString &targetDirPath)
992 QFile inFile(sourceFilePath);
993 if (!inFile.open(QFile::ReadOnly)) {
994 location.warning(QStringLiteral(
"Cannot open input file for copy: '%1': %2")
995 .arg(sourceFilePath, inFile.errorString()));
1033 QString outFileName{userFriendlySourceFilePath};
1034 QFileInfo outFileNameInfo{userFriendlySourceFilePath};
1035 if (outFileNameInfo.isAbsolute())
1036 outFileName = outFileNameInfo.fileName();
1038 outFileName = targetDirPath +
"/" + outFileName;
1039 QDir targetDir(targetDirPath);
1040 if (!targetDir.exists())
1041 targetDir.mkpath(
".");
1043 QFile outFile(outFileName);
1044 if (!outFile.open(QFile::WriteOnly)) {
1046 location.warning(QStringLiteral(
"Cannot open output file for copy: '%1': %2")
1047 .arg(outFileName, outFile.errorString()));
1059 while ((len = inFile.read(buffer,
sizeof(buffer))) > 0)
1060 outFile.write(buffer, len);
1065
1066
1067
1071 for (
int i = 0; i != value.size(); ++i) {
1072 uint c = value[i].unicode();
1074 max = qMax(max,
static_cast<
int>(c));
1080
1081
1082
1083bool Config::isMetaKeyChar(QChar ch)
1085 return ch.isLetterOrNumber() || ch == QLatin1Char(
'_') || ch == QLatin1Char(
'.')
1086 || ch == QLatin1Char(
'{') || ch == QLatin1Char(
'}') || ch == QLatin1Char(
',');
1090
1091
1092
1093QStringList
Config::loadMaster(
const QString &fileName)
1096 QFile fin(fileName);
1097 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1098 if (!Config::installDir.isEmpty()) {
1099 qsizetype prefix = location.filePath().size() - location.fileName().size();
1100 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1101 + fileName.right(fileName.size() - prefix));
1103 if (!fin.open(QFile::ReadOnly | QFile::Text))
1104 location.fatal(QStringLiteral(
"Cannot open master qdocconf file '%1': %2")
1105 .arg(fileName, fin.errorString()));
1107 QTextStream stream(&fin);
1108 QStringList qdocFiles;
1109 QDir configDir(QFileInfo(fileName).canonicalPath());
1110 QString line = stream.readLine();
1111 while (!line.isNull()) {
1112 if (!line.isEmpty())
1113 qdocFiles.append(QFileInfo(configDir, line).filePath());
1114 line = stream.readLine();
1121
1122
1123
1124
1125
1128 QFileInfo fileInfo(fileName);
1129 pushWorkingDir(fileInfo.canonicalPath());
1130 static const QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String(
"\\w+(?:\\.\\w+)*")));
1134 location.advance(c);
1140#define SKIP_SPACES()
1141 while (c.isSpace() && cc != '\n')
1149 location.fatal(QStringLiteral(
"Too many nested includes"));
1151 QFile fin(fileInfo.fileName());
1152 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1153 if (!Config::installDir.isEmpty()) {
1154 qsizetype prefix = location.filePath().size() - location.fileName().size();
1155 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1156 + fileName.right(fileName.size() - prefix));
1158 if (!fin.open(QFile::ReadOnly | QFile::Text))
1160 QStringLiteral(
"Cannot open file '%1': %2").arg(fileName, fin.errorString()));
1163 QTextStream stream(&fin);
1164 QString text = stream.readAll();
1165 text += QLatin1String(
"\n\n");
1166 text += QLatin1Char(
'\0');
1169 location.push(fileName);
1173 QChar c = text.at(0);
1174 uint cc = c.unicode();
1175 while (i < text.size()) {
1178 }
else if (c.isSpace()) {
1180 }
else if (cc ==
'#') {
1183 }
while (cc !=
'\n');
1184 }
else if (isMetaKeyChar(c)) {
1187 QStringList rhsValues;
1188 QList<ExpandVar> expandVars;
1190 bool inQuote =
false;
1191 bool needsExpansion =
false;
1195 stack.process(c, location);
1197 }
while (isMetaKeyChar(c));
1199 const QStringList keys = stack.getExpanded(location);
1202 if (keys.size() == 1 && keys.first() == QLatin1String(
"include")) {
1203 QString includeFile;
1206 location.fatal(QStringLiteral(
"Bad include syntax"));
1210 while (!c.isSpace() && cc !=
'#' && cc !=
')') {
1215 while (c.isLetterOrNumber() || cc ==
'_') {
1219 if (!var.isEmpty()) {
1220 const QByteArray val = qgetenv(var.toLatin1().data());
1222 location.fatal(QStringLiteral(
"Environment variable '%1' undefined")
1225 includeFile += QString::fromLatin1(val);
1235 location.fatal(QStringLiteral(
"Bad include syntax"));
1238 if (cc !=
'#' && cc !=
'\n')
1239 location.fatal(QStringLiteral(
"Trailing garbage"));
1242
1243
1244 load(location, QFileInfo(QDir(m_workingDirs.top()), includeFile).filePath());
1247
1248
1249
1255 location.fatal(QStringLiteral(
"Expected '=' or '+=' after key"));
1261 qsizetype metaCharPos;
1266 }
else if (cc >
'0' && cc <
'8') {
1267 word += QChar(c.digitValue());
1269 }
else if ((metaCharPos = QString::fromLatin1(
"abfnrtv").indexOf(c))
1271 word += QLatin1Char(
"\a\b\f\n\r\t\v"[metaCharPos]);
1276 }
else if (c.isSpace() || cc ==
'#') {
1279 location.fatal(QStringLiteral(
"Unterminated string"));
1282 if (!word.isEmpty() || needsExpansion) {
1285 needsExpansion =
false;
1287 if (cc ==
'\n' || cc ==
'#')
1291 }
else if (cc ==
'"') {
1293 if (!word.isEmpty() || needsExpansion)
1296 needsExpansion =
false;
1300 }
else if (cc ==
'$') {
1303 bool braces =
false;
1309 while (c.isLetterOrNumber() || cc ==
'_') {
1321 else if (delim ==
'}')
1324 location.fatal(QStringLiteral(
"Missing '}'"));
1326 if (!var.isEmpty()) {
1327 const QByteArray val = qgetenv(var.toLatin1().constData());
1329 expandVars <<
ExpandVar(rhsValues.size(), word.size(),
std::move(var), delim);
1330 needsExpansion =
true;
1331 }
else if (braces) {
1332 text.insert(i, QString::fromLatin1(val));
1336 word += QString::fromLatin1(val);
1340 if (!inQuote && cc ==
'=')
1341 location.fatal(QStringLiteral(
"Unexpected '='"));
1345 for (
const auto &key : keys) {
1346 if (!keySyntax.match(key).hasMatch())
1347 keyLoc.fatal(QStringLiteral(
"Invalid key '%1'").arg(key));
1349 ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
1350 if (plus && m_configVars.contains(key)) {
1351 m_configVars[key].append(configVar);
1353 m_configVars.insert(key, configVar);
1358 location.fatal(QStringLiteral(
"Unexpected character '%1' at beginning of line").arg(c));
1368bool Config::isFileExcluded(
const QString &fileName,
const QSet<QString> &excludedFiles)
1370 for (
const QString &entry : excludedFiles) {
1371 if (entry.contains(QLatin1Char(
'*')) || entry.contains(QLatin1Char(
'?'))) {
1372 QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry));
1373 if (re.match(fileName).hasMatch())
1377 return excludedFiles.contains(fileName);
1380QStringList
Config::getFilesHere(
const QString &uncleanDir,
const QString &nameFilter,
1381 const Location &location,
const QSet<QString> &excludedDirs,
1382 const QSet<QString> &excludedFiles)
1387 location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath();
1389 if (excludedDirs.contains(dir))
1394 dirInfo.setNameFilters(nameFilter.split(QLatin1Char(
' ')));
1395 dirInfo.setSorting(QDir::Name);
1396 dirInfo.setFilter(QDir::Files);
1397 QStringList fileNames = dirInfo.entryList();
1398 for (
const auto &file : std::as_const(fileNames)) {
1401 if (!file.startsWith(QLatin1Char(
'~'))) {
1402 QString s = dirInfo.filePath(file);
1403 QString c = QDir::cleanPath(s);
1404 if (!isFileExcluded(c, excludedFiles))
1409 dirInfo.setNameFilters(QStringList(QLatin1String(
"*")));
1410 dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1411 fileNames = dirInfo.entryList();
1412 for (
const auto &file : fileNames)
1413 result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs,
1419
1420
1421
1422void Config::pushWorkingDir(
const QString &dir)
1424 m_workingDirs.push(dir);
1425 QDir::setCurrent(dir);
1429
1430
1431
1432
1435 Q_ASSERT(!m_workingDirs.isEmpty());
1436 m_workingDirs.pop();
1437 if (!m_workingDirs.isEmpty())
1438 QDir::setCurrent(m_workingDirs.top());
1442 if (m_excludedPaths)
1443 return *m_excludedPaths;
1448 QSet<QString> excludedDirs = QSet<QString>(excludedDirList.cbegin(), excludedDirList.cend());
1449 QSet<QString> excludedFiles = QSet<QString>(excludedFilesList.cbegin(), excludedFilesList.cend());
1451 m_excludedPaths.emplace(ExcludedPaths{std::move(excludedDirs), std::move(excludedFiles)});
1453 return *m_excludedPaths;
1457
1458
1459
1460
1461
1462
1463
1467 return QSet<QString>(patterns.cbegin(), patterns.cend());
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1485 if (m_internalFilePatterns)
1486 return *m_internalFilePatterns;
1491 for (
const QString &pattern : patterns) {
1492 static const QRegularExpression regexMetaChars(
1493 uR"(\.\*|\.\+|\.\{|\\[\.\*\?]|[\^\$\[\]{}()|+])"_s);
1494 bool isRawRegex = regexMetaChars.match(pattern).hasMatch();
1497 QRegularExpression re(pattern);
1498 if (!re.isValid()) {
1499 qWarning() <<
"Invalid regex pattern in internalfilepatterns:" << pattern
1500 <<
"-" << re.errorString();
1504 compiled.regexPatterns.append(re);
1505 }
else if (pattern.contains(u'*') || pattern.contains(u'?')) {
1506 QString regexPattern = QRegularExpression::wildcardToRegularExpression(pattern);
1507 QRegularExpression re(regexPattern);
1509 compiled.globPatterns.append(re);
1511 compiled.exactMatches.insert(pattern);
1515 m_internalFilePatterns.emplace(std::move(compiled));
1516 return *m_internalFilePatterns;
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534bool Config::matchesInternalFilePattern(
const QString &filePath,
1537 if (patterns.exactMatches.isEmpty() && patterns.globPatterns.isEmpty()
1538 && patterns.regexPatterns.isEmpty())
1541 QString norm = filePath;
1542 norm.replace(QChar(
'\\'), QChar(
'/'));
1544 if (patterns.exactMatches.contains(norm))
1547 const QString fileName = QFileInfo(norm).fileName();
1548 for (
const QRegularExpression &re : patterns.globPatterns) {
1549 if (re.match(fileName).hasMatch())
1553 for (
const QRegularExpression &re : patterns.regexPatterns) {
1554 if (re.match(norm).hasMatch())
1562
1563
1564
1568 return *m_sourceLink;
1572 const auto baseUrl = m_configVars.value(srcUrl).asString();
1573 const auto rootPath = m_configVars.value(srcUrl + dot +
CONFIG_ROOTDIR).asString();
1574 const auto linkText = m_configVars.value(srcUrl + dot +
"linktext").asString();
1575 const auto enabled = m_configVars.value(srcUrl + dot +
"enabled").asBool();
1577 m_sourceLink.emplace(SourceLink{baseUrl, rootPath, linkText, enabled});
1578 return *m_sourceLink;
1582 static QStringList accepted_header_file_extensions{
1583 "ch",
"h",
"h++",
"hh",
"hpp",
"hxx"
1588 QStringList headerList =
1591 std::set<HeaderFilePath> headers{};
1593 for (
const auto& header : headerList) {
1594 if (header.contains(
"doc/snippets"))
continue;
1596 if (!accepted_header_file_extensions.contains(QFileInfo{header}.suffix()))
1599 headers.insert(HeaderFilePath{QFileInfo{header}.canonicalPath(), QFileInfo{header}.fileName()});
1612 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 - used by load().
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_FALSEHOODS
#define CONFIG_EXAMPLEDIRS
#define CONFIG_WARNABOUTMISSINGPROJECTFILES
#define CONFIG_SYNTAXHIGHLIGHTING
#define CONFIG_PRELIMINARY
#define CONFIG_TIMESTAMPS
#define CONFIG_NOLINKERRORS
#define CONFIG_LOGPROGRESS
#define CONFIG_CODELANGUAGES
#define CONFIG_DESCRIPTION
#define CONFIG_SOURCEDIRS
#define CONFIG_CODEINDENT
#define CONFIG_INTERNALFILEPATTERNS
#define CONFIG_WARNABOUTMISSINGIMAGES
#define CONFIG_INCLUDEPRIVATE
#define CONFIG_OUTPUTFORMATS
#define CONFIG_LOCATIONINFO
#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