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;
81 QStringLiteral(
"redirectdocumentationtodevnull");
83 QStringLiteral(
"reportmissingalttextforimages");
115
116
117
130
131
132
135 next.append(QString());
139
140
141
142
150
151
152
153
164
165
166
174
175
176
177
180 if (ch == QLatin1Char(
'{')) {
183 }
else if (ch == QLatin1Char(
'}')) {
185 location.fatal(QStringLiteral(
"Unexpected '}'"));
188 const QStringList suffixes = pop().accum;
189 const QStringList prefixes = top().next;
192 for (
const auto &prefix : prefixes) {
193 for (
const auto &suffix : suffixes)
194 top().next << prefix + suffix;
196 }
else if (ch == QLatin1Char(
',') && size() > 1) {
200 for (QString &topNext : top().next)
206
207
211 location.fatal(QStringLiteral(
"Missing '}'"));
218bool Config::m_debug =
false;
219bool Config::m_atomsDump =
false;
224QMap<QString, QString>
Config::m_extractedDirs;
225QStack<QString>
Config::m_workingDirs;
226QMap<QString, QStringList>
Config::m_includeFilesMap;
229
230
231
232
235
236
237
238
239
240
241
242
243
246 if (m_name.isEmpty())
247 return defaultString;
250 for (
const auto &value : std::as_const(m_values)) {
251 if (!result.isEmpty() && !result.endsWith(QChar(
'\n')))
252 result.append(QChar(
' '));
253 result.append(value.m_value);
259
260
264 for (
const auto &value : std::as_const(m_values))
265 result << value.m_value;
270
271
274 const auto &stringList = asStringList();
275 return QSet<QString>(stringList.cbegin(), stringList.cend());
279
280
283 return QVariant(asString()).toBool();
287
288
289
290
291
292
293
296 const QStringList strs = asStringList();
301 for (
const auto &str : strs)
307
308
309
312 m_expandVars << other.m_expandVars;
313 QList<ExpandVar>::Iterator it = m_expandVars.end();
314 it -= other.m_expandVars.size();
315 std::for_each(it, m_expandVars.end(), [
this](ExpandVar &v) {
316 v.m_valueIndex += m_values.size();
318 m_values << other.m_values;
319 m_location = other.m_location;
323
324
325
326
327
328
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
350
351
352
353
354void Config::
init(
const QString &programName,
const QStringList &args)
356 m_prog = programName;
357 processCommandLineOptions(args);
367
368
371 m_location = Location();
372 m_configVars.clear();
373 m_includeFilesMap.clear();
374 m_excludedPaths.reset();
375 m_sourceLink.reset();
376 m_internalFilePatterns.reset();
380
381
401 QStringList(
"This \1 is under development and is subject to change."));
404 const auto setListFlag = [
this](
const QString &key,
bool test) {
405 setStringList(key, QStringList(test ? QStringLiteral(
"true") : QStringLiteral(
"false")));
407#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
416 m_parser.isSet(m_parser.noLinkErrorsOption)
417 || qEnvironmentVariableIsSet(
"QDOC_NOLINKERRORS"));
423
424
425
426
427
434 load(Location(), fileName);
435 if (m_location.isEmpty())
436 m_location = Location(fileName);
438 m_location.setEtc(
true);
442 setStringList(varName, getCanonicalPathList(varName, Validate));
455 m_reportMissingAltTextForImages =
458 if (!m_parser.isSet(m_parser.showInternalOption) && !qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL"))
463
464
465void Config::expandVariables()
467 for (
auto &configVar : m_configVars) {
468 for (
auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) {
469 Q_ASSERT(it->m_valueIndex < configVar.m_values.size());
470 const QString &key = it->m_var;
471 const auto &refVar = m_configVars.value(key);
472 if (refVar.m_name.isEmpty()) {
473 configVar.m_location.fatal(
474 QStringLiteral(
"Environment or configuration variable '%1' undefined")
476 }
else if (!refVar.m_expandVars.empty()) {
477 configVar.m_location.fatal(
478 QStringLiteral(
"Nested variable expansion not allowed"),
479 QStringLiteral(
"When expanding '%1' at %2:%3")
480 .arg(refVar.m_name, refVar.m_location.filePath(),
481 QString::number(refVar.m_location.lineNo())));
484 if (it->m_delim.isNull())
485 expanded = m_configVars.value(key).asStringList().join(QString());
487 expanded = m_configVars.value(key).asStringList().join(it->m_delim);
488 configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded);
490 configVar.m_expandVars.clear();
495
496
499 m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath()));
503
504
505
508 m_configVars[var].append(ConfigVar(var, values, QDir::currentPath()));
512
513
514void Config::processCommandLineOptions(
const QStringList &args)
516 m_parser.process(args);
518 m_defines = m_parser.values(m_parser.defineOption);
519 m_dependModules = m_parser.values(m_parser.dependsOption);
523 generateExamples = !m_parser.isSet(m_parser.noExamplesOption);
524 if (m_parser.isSet(m_parser.installDirOption))
525 installDir = m_parser.value(m_parser.installDirOption);
526 if (m_parser.isSet(m_parser.outputDirOption))
527 overrideOutputDir = QDir(m_parser.value(m_parser.outputDirOption)).absolutePath();
529 const auto outputFormats = m_parser.values(m_parser.outputFormatOption);
530 for (
const auto &format : outputFormats)
531 overrideOutputFormats.insert(format);
532 m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet(
"QDOC_DEBUG");
533 m_atomsDump = m_parser.isSet(m_parser.atomsDumpOption);
534 m_showInternal = m_parser.isSet(m_parser.showInternalOption)
535 || qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL");
537 if (m_parser.isSet(m_parser.prepareOption))
539 if (m_parser.isSet(m_parser.generateOption))
541 if (m_debug || m_parser.isSet(m_parser.logProgressOption))
543 if (m_parser.isSet(m_parser.timestampsOption))
545 if (m_parser.isSet(m_parser.useDocBookExtensions))
549void Config::setIncludePaths()
551 QDir currentDir = QDir::current();
552 const auto addIncludePaths = [
this, currentDir](
const char *flag,
const QStringList &paths) {
553 for (
const auto &path : paths)
554 m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag);
557 addIncludePaths(
"-I", m_parser.values(m_parser.includePathOption));
558#ifdef QDOC_PASS_ISYSTEM
559 addIncludePaths(
"-isystem", m_parser.values(m_parser.includePathSystemOption));
561 addIncludePaths(
"-F", m_parser.values(m_parser.frameworkOption));
565
566
567void Config::setIndexDirs()
569 m_indexDirs = m_parser.values(m_parser.indexDirOption);
570 auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(),
571 [](
const QString &s) {
return !QFile::exists(s); });
573 std::for_each(it, m_indexDirs.end(), [](
const QString &s) {
574 qCWarning(lcQdoc) <<
"Cannot find index directory: " << s;
576 m_indexDirs.erase(it, m_indexDirs.end());
580
581
582
583
584
588 if (overrideOutputDir.isNull())
591 t = overrideOutputDir;
594 t += QLatin1Char(
'/') + project.toLower();
596 if (m_configVars.value(format + Config::dot +
"nosubdirs").asBool()) {
597 QString singleOutputSubdir = m_configVars.value(format + Config::dot +
"outputsubdir").asString();
598 if (singleOutputSubdir.isEmpty())
599 singleOutputSubdir =
"html";
600 t += QLatin1Char(
'/') + singleOutputSubdir;
602 return QDir::cleanPath(t);
606
607
608
609
612 if (overrideOutputFormats.isEmpty())
615 return overrideOutputFormats;
633
634
635
636
637
638
642 const auto &configVar = m_configVars.value(var);
644 for (
const auto &value : configVar.m_values) {
645 const QString ¤tPath = value.m_path;
646 QString rawValue = value.m_value.simplified();
649 if (flags & IncludePaths) {
650 const QStringList prefixes = QStringList()
651 << QLatin1String(
"-I")
652 << QLatin1String(
"-F")
653 << QLatin1String(
"-isystem");
654 const auto end = std::end(prefixes);
656 std::find_if(std::begin(prefixes), end,
657 [&rawValue](
const QString &p) {
658 return rawValue.startsWith(p);
662 rawValue.remove(0, it->size());
663 if (rawValue.isEmpty())
666 prefix = prefixes[0];
670 QDir dir(rawValue.trimmed());
671 const QString path = dir.path();
673 if (dir.isRelative())
674 dir.setPath(currentPath + QLatin1Char(
'/') + path);
675 if ((flags & Validate) && !QFileInfo::exists(dir.path()))
676 configVar.m_location.warning(QStringLiteral(
"Cannot find file or directory: %1").arg(path));
678 const QString canonicalPath = dir.canonicalPath();
679 if (!canonicalPath.isEmpty())
680 result.append(prefix + canonicalPath);
681 else if (path.contains(QLatin1Char(
'*')) || path.contains(QLatin1Char(
'?')))
685 qUtf8Printable(QStringLiteral(
"%1: Ignored nonexistent path \'%2\'")
686 .arg(configVar.m_location.toString(), rawValue));
693
694
695
696
697
698
699
703 const auto subRegExps = getRegExpList(var);
705 for (
const auto ®Exp : subRegExps) {
706 if (!regExp.isValid())
708 if (!pattern.isEmpty())
709 pattern += QLatin1Char(
'|');
710 pattern += QLatin1String(
"(?:") + regExp.pattern() + QLatin1Char(
')');
712 if (pattern.isEmpty())
713 pattern = QLatin1String(
"$x");
714 return QRegularExpression(pattern);
718
719
720
721
724 const QStringList strs = m_configVars.value(var).asStringList();
725 QList<QRegularExpression> regExps;
726 for (
const auto &str : strs)
727 regExps += QRegularExpression(str);
732
733
734
735
736
739 QSet<QString> result;
740 QString varDot = var + QLatin1Char(
'.');
741 for (
auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) {
742 if (it.key().startsWith(varDot)) {
743 QString subVar = it.key().mid(varDot.size());
744 int dot = subVar.indexOf(QLatin1Char(
'.'));
746 subVar.truncate(dot);
747 result.insert(subVar);
754
755
756
757
760 QString ext = QFileInfo(fileName).suffix();
762 if (!m_includeFilesMap.contains(ext)) {
764 result.erase(std::remove_if(result.begin(), result.end(),
765 [&](
const QString &s) {
return !s.endsWith(ext); }),
767 const QStringList dirs =
771 for (
const auto &dir : dirs)
772 result += getFilesHere(dir,
"*." + ext, location());
773 result.removeDuplicates();
774 m_includeFilesMap.insert(ext, result);
776 const QStringList &paths = (*m_includeFilesMap.find(ext));
777 QString match = fileName;
778 if (!match.startsWith(
'/'))
780 for (
const auto &path : paths) {
781 if (path.endsWith(match))
788
789
790
791
792
793
794
795
797 const QSet<QString> &excludedDirs,
798 const QSet<QString> &excludedFiles)
800 QStringList result = getCanonicalPathList(filesVar, Validate);
801 const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
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");
815 const QString nameFilter =
" *.qdoc";
817 for (
const auto &dir : dirs)
818 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
823 const QSet<QString> &excludedFiles)
826 const QStringList dirs = getCanonicalPathList(
"exampledirs");
829 for (
const auto &dir : dirs)
830 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
842
843
844
847 QFileInfo fileInfo(examplePath);
848 QStringList validNames;
849 validNames << QLatin1String(
"CMakeLists.txt")
850 << fileInfo.fileName() + QLatin1String(
".pro")
851 << fileInfo.fileName() + QLatin1String(
".qmlproject")
852 << fileInfo.fileName() + QLatin1String(
".pyproject")
853 << QLatin1String(
"qbuild.pro");
857 for (
const auto &name : std::as_const(validNames)) {
858 projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs,
859 examplePath + QLatin1Char(
'/') + name);
860 if (!projectFile.isEmpty())
886
887
888
889
890
891
892
893
895 const QStringList &dirs,
const QString &fileName,
896 QString *userFriendlyFilePath)
898 if (fileName.isEmpty() || fileName.startsWith(QLatin1Char(
'/'))) {
899 if (userFriendlyFilePath)
900 *userFriendlyFilePath = fileName;
905 QStringList components = fileName.split(QLatin1Char(
'?'));
906 QString firstComponent = components.first();
908 for (
const auto &file : files) {
909 if (file == firstComponent || file.endsWith(QLatin1Char(
'/') + firstComponent)) {
910 fileInfo.setFile(file);
911 if (!fileInfo.exists())
912 location.fatal(QStringLiteral(
"File '%1' does not exist").arg(file));
917 if (fileInfo.fileName().isEmpty()) {
918 for (
const auto &dir : dirs) {
919 fileInfo.setFile(QDir(dir), firstComponent);
920 if (fileInfo.exists())
925 if (userFriendlyFilePath)
926 userFriendlyFilePath->clear();
927 if (!fileInfo.exists())
937 if (userFriendlyFilePath) {
938 for (
auto c = components.constBegin();;) {
939 bool isArchive = (c != components.constEnd() - 1);
940 userFriendlyFilePath->append(*c);
943 QString extracted = m_extractedDirs[fileInfo.filePath()];
946 fileInfo.setFile(QDir(extracted), *c);
951 userFriendlyFilePath->append(QLatin1Char(
'?'));
956 return fileInfo.filePath();
972
973
974
975
976
977
979 const QString &userFriendlySourceFilePath,
const QString &targetDirPath)
990 QFile inFile(sourceFilePath);
991 if (!inFile.open(QFile::ReadOnly)) {
992 location.warning(QStringLiteral(
"Cannot open input file for copy: '%1': %2")
993 .arg(sourceFilePath, inFile.errorString()));
1031 QString outFileName{userFriendlySourceFilePath};
1032 QFileInfo outFileNameInfo{userFriendlySourceFilePath};
1033 if (outFileNameInfo.isAbsolute())
1034 outFileName = outFileNameInfo.fileName();
1036 outFileName = targetDirPath +
"/" + outFileName;
1037 QDir targetDir(targetDirPath);
1038 if (!targetDir.exists())
1039 targetDir.mkpath(
".");
1041 QFile outFile(outFileName);
1042 if (!outFile.open(QFile::WriteOnly)) {
1044 location.warning(QStringLiteral(
"Cannot open output file for copy: '%1': %2")
1045 .arg(outFileName, outFile.errorString()));
1057 while ((len = inFile.read(buffer,
sizeof(buffer))) > 0)
1058 outFile.write(buffer, len);
1063
1064
1065
1069 for (
int i = 0; i != value.size(); ++i) {
1070 uint c = value[i].unicode();
1072 max = qMax(max,
static_cast<
int>(c));
1078
1079
1080
1081bool Config::isMetaKeyChar(QChar ch)
1083 return ch.isLetterOrNumber() || ch == QLatin1Char(
'_') || ch == QLatin1Char(
'.')
1084 || ch == QLatin1Char(
'{') || ch == QLatin1Char(
'}') || ch == QLatin1Char(
',');
1088
1089
1090
1091QStringList
Config::loadMaster(
const QString &fileName)
1094 QFile fin(fileName);
1095 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1096 if (!Config::installDir.isEmpty()) {
1097 qsizetype prefix = location.filePath().size() - location.fileName().size();
1098 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1099 + fileName.right(fileName.size() - prefix));
1101 if (!fin.open(QFile::ReadOnly | QFile::Text))
1102 location.fatal(QStringLiteral(
"Cannot open master qdocconf file '%1': %2")
1103 .arg(fileName, fin.errorString()));
1105 QTextStream stream(&fin);
1106 QStringList qdocFiles;
1107 QDir configDir(QFileInfo(fileName).canonicalPath());
1108 QString line = stream.readLine();
1109 while (!line.isNull()) {
1110 if (!line.isEmpty())
1111 qdocFiles.append(QFileInfo(configDir, line).filePath());
1112 line = stream.readLine();
1119
1120
1121
1122
1123
1126 QFileInfo fileInfo(fileName);
1127 pushWorkingDir(fileInfo.canonicalPath());
1128 static const QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String(
"\\w+(?:\\.\\w+)*")));
1132 location.advance(c);
1138#define SKIP_SPACES()
1139 while (c.isSpace() && cc != '\n')
1147 location.fatal(QStringLiteral(
"Too many nested includes"));
1149 QFile fin(fileInfo.fileName());
1150 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1151 if (!Config::installDir.isEmpty()) {
1152 qsizetype prefix = location.filePath().size() - location.fileName().size();
1153 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1154 + fileName.right(fileName.size() - prefix));
1156 if (!fin.open(QFile::ReadOnly | QFile::Text))
1158 QStringLiteral(
"Cannot open file '%1': %2").arg(fileName, fin.errorString()));
1161 QTextStream stream(&fin);
1162 QString text = stream.readAll();
1163 text += QLatin1String(
"\n\n");
1164 text += QLatin1Char(
'\0');
1167 location.push(fileName);
1171 QChar c = text.at(0);
1172 uint cc = c.unicode();
1173 while (i < text.size()) {
1176 }
else if (c.isSpace()) {
1178 }
else if (cc ==
'#') {
1181 }
while (cc !=
'\n');
1182 }
else if (isMetaKeyChar(c)) {
1185 QStringList rhsValues;
1186 QList<ExpandVar> expandVars;
1188 bool inQuote =
false;
1189 bool needsExpansion =
false;
1193 stack.process(c, location);
1195 }
while (isMetaKeyChar(c));
1197 const QStringList keys = stack.getExpanded(location);
1200 if (keys.size() == 1 && keys.first() == QLatin1String(
"include")) {
1201 QString includeFile;
1204 location.fatal(QStringLiteral(
"Bad include syntax"));
1208 while (!c.isSpace() && cc !=
'#' && cc !=
')') {
1213 while (c.isLetterOrNumber() || cc ==
'_') {
1217 if (!var.isEmpty()) {
1218 const QByteArray val = qgetenv(var.toLatin1().data());
1220 location.fatal(QStringLiteral(
"Environment variable '%1' undefined")
1223 includeFile += QString::fromLatin1(val);
1233 location.fatal(QStringLiteral(
"Bad include syntax"));
1236 if (cc !=
'#' && cc !=
'\n')
1237 location.fatal(QStringLiteral(
"Trailing garbage"));
1240
1241
1242 load(location, QFileInfo(QDir(m_workingDirs.top()), includeFile).filePath());
1245
1246
1247
1253 location.fatal(QStringLiteral(
"Expected '=' or '+=' after key"));
1259 qsizetype metaCharPos;
1264 }
else if (cc >
'0' && cc <
'8') {
1265 word += QChar(c.digitValue());
1267 }
else if ((metaCharPos = QString::fromLatin1(
"abfnrtv").indexOf(c))
1269 word += QLatin1Char(
"\a\b\f\n\r\t\v"[metaCharPos]);
1274 }
else if (c.isSpace() || cc ==
'#') {
1277 location.fatal(QStringLiteral(
"Unterminated string"));
1280 if (!word.isEmpty() || needsExpansion) {
1283 needsExpansion =
false;
1285 if (cc ==
'\n' || cc ==
'#')
1289 }
else if (cc ==
'"') {
1291 if (!word.isEmpty() || needsExpansion)
1294 needsExpansion =
false;
1298 }
else if (cc ==
'$') {
1301 bool braces =
false;
1307 while (c.isLetterOrNumber() || cc ==
'_') {
1319 else if (delim ==
'}')
1322 location.fatal(QStringLiteral(
"Missing '}'"));
1324 if (!var.isEmpty()) {
1325 const QByteArray val = qgetenv(var.toLatin1().constData());
1327 expandVars <<
ExpandVar(rhsValues.size(), word.size(),
std::move(var), delim);
1328 needsExpansion =
true;
1329 }
else if (braces) {
1330 text.insert(i, QString::fromLatin1(val));
1334 word += QString::fromLatin1(val);
1338 if (!inQuote && cc ==
'=')
1339 location.fatal(QStringLiteral(
"Unexpected '='"));
1343 for (
const auto &key : keys) {
1344 if (!keySyntax.match(key).hasMatch())
1345 keyLoc.fatal(QStringLiteral(
"Invalid key '%1'").arg(key));
1347 ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
1348 if (plus && m_configVars.contains(key)) {
1349 m_configVars[key].append(configVar);
1351 m_configVars.insert(key, configVar);
1356 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 - 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_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 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