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;
80 QStringLiteral(
"redirectdocumentationtodevnull");
82 QStringLiteral(
"reportmissingalttextforimages");
113
114
115
128
129
130
133 next.append(QString());
137
138
139
140
148
149
150
151
162
163
164
172
173
174
175
178 if (ch == QLatin1Char(
'{')) {
181 }
else if (ch == QLatin1Char(
'}')) {
183 location.fatal(QStringLiteral(
"Unexpected '}'"));
186 const QStringList suffixes = pop().accum;
187 const QStringList prefixes = top().next;
190 for (
const auto &prefix : prefixes) {
191 for (
const auto &suffix : suffixes)
192 top().next << prefix + suffix;
194 }
else if (ch == QLatin1Char(
',') && size() > 1) {
198 for (QString &topNext : top().next)
204
205
209 location.fatal(QStringLiteral(
"Missing '}'"));
216bool Config::m_debug =
false;
217bool Config::m_atomsDump =
false;
222QMap<QString, QString>
Config::m_extractedDirs;
223QStack<QString>
Config::m_workingDirs;
224QMap<QString, QStringList>
Config::m_includeFilesMap;
227
228
229
230
233
234
235
236
237
238
239
240
241
244 if (m_name.isEmpty())
245 return defaultString;
248 for (
const auto &value : std::as_const(m_values)) {
249 if (!result.isEmpty() && !result.endsWith(QChar(
'\n')))
250 result.append(QChar(
' '));
251 result.append(value.m_value);
257
258
262 for (
const auto &value : std::as_const(m_values))
263 result << value.m_value;
268
269
272 const auto &stringList = asStringList();
273 return QSet<QString>(stringList.cbegin(), stringList.cend());
277
278
281 return QVariant(asString()).toBool();
285
286
287
288
289
290
291
294 const QStringList strs = asStringList();
299 for (
const auto &str : strs)
305
306
307
310 m_expandVars << other.m_expandVars;
311 QList<ExpandVar>::Iterator it = m_expandVars.end();
312 it -= other.m_expandVars.size();
313 std::for_each(it, m_expandVars.end(), [
this](ExpandVar &v) {
314 v.m_valueIndex += m_values.size();
316 m_values << other.m_values;
317 m_location = other.m_location;
321
322
323
324
325
326
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
348
349
350
351
352void Config::
init(
const QString &programName,
const QStringList &args)
354 m_prog = programName;
355 processCommandLineOptions(args);
365
366
369 m_location = Location();
370 m_configVars.clear();
371 m_includeFilesMap.clear();
372 m_excludedPaths.reset();
373 m_sourceLink.reset();
374 m_internalFilePatterns.reset();
378
379
398 const auto setListFlag = [
this](
const QString &key,
bool test) {
399 setStringList(key, QStringList(test ? QStringLiteral(
"true") : QStringLiteral(
"false")));
401#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
410 m_parser.isSet(m_parser.noLinkErrorsOption)
411 || qEnvironmentVariableIsSet(
"QDOC_NOLINKERRORS"));
417
418
419
420
421
428 load(Location(), fileName);
429 if (m_location.isEmpty())
430 m_location = Location(fileName);
432 m_location.setEtc(
true);
436 setStringList(varName, getCanonicalPathList(varName, Validate));
449 m_reportMissingAltTextForImages =
452 if (!m_parser.isSet(m_parser.showInternalOption) && !qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL"))
457
458
459void Config::expandVariables()
461 for (
auto &configVar : m_configVars) {
462 for (
auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) {
463 Q_ASSERT(it->m_valueIndex < configVar.m_values.size());
464 const QString &key = it->m_var;
465 const auto &refVar = m_configVars.value(key);
466 if (refVar.m_name.isEmpty()) {
467 configVar.m_location.fatal(
468 QStringLiteral(
"Environment or configuration variable '%1' undefined")
470 }
else if (!refVar.m_expandVars.empty()) {
471 configVar.m_location.fatal(
472 QStringLiteral(
"Nested variable expansion not allowed"),
473 QStringLiteral(
"When expanding '%1' at %2:%3")
474 .arg(refVar.m_name, refVar.m_location.filePath(),
475 QString::number(refVar.m_location.lineNo())));
478 if (it->m_delim.isNull())
479 expanded = m_configVars.value(key).asStringList().join(QString());
481 expanded = m_configVars.value(key).asStringList().join(it->m_delim);
482 configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded);
484 configVar.m_expandVars.clear();
489
490
493 m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath()));
497
498
499
502 m_configVars[var].append(ConfigVar(var, values, QDir::currentPath()));
506
507
508void Config::processCommandLineOptions(
const QStringList &args)
510 m_parser.process(args);
512 m_defines = m_parser.values(m_parser.defineOption);
513 m_dependModules = m_parser.values(m_parser.dependsOption);
517 generateExamples = !m_parser.isSet(m_parser.noExamplesOption);
518 if (m_parser.isSet(m_parser.installDirOption))
519 installDir = m_parser.value(m_parser.installDirOption);
520 if (m_parser.isSet(m_parser.outputDirOption))
521 overrideOutputDir = QDir(m_parser.value(m_parser.outputDirOption)).absolutePath();
523 const auto outputFormats = m_parser.values(m_parser.outputFormatOption);
524 for (
const auto &format : outputFormats)
525 overrideOutputFormats.insert(format);
526 m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet(
"QDOC_DEBUG");
527 m_atomsDump = m_parser.isSet(m_parser.atomsDumpOption);
528 m_showInternal = m_parser.isSet(m_parser.showInternalOption)
529 || qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL");
531 if (m_parser.isSet(m_parser.prepareOption))
533 if (m_parser.isSet(m_parser.generateOption))
535 if (m_debug || m_parser.isSet(m_parser.logProgressOption))
537 if (m_parser.isSet(m_parser.timestampsOption))
539 if (m_parser.isSet(m_parser.useDocBookExtensions))
543void Config::setIncludePaths()
545 QDir currentDir = QDir::current();
546 const auto addIncludePaths = [
this, currentDir](
const char *flag,
const QStringList &paths) {
547 for (
const auto &path : paths)
548 m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag);
551 addIncludePaths(
"-I", m_parser.values(m_parser.includePathOption));
552#ifdef QDOC_PASS_ISYSTEM
553 addIncludePaths(
"-isystem", m_parser.values(m_parser.includePathSystemOption));
555 addIncludePaths(
"-F", m_parser.values(m_parser.frameworkOption));
559
560
561void Config::setIndexDirs()
563 m_indexDirs = m_parser.values(m_parser.indexDirOption);
564 auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(),
565 [](
const QString &s) {
return !QFile::exists(s); });
567 std::for_each(it, m_indexDirs.end(), [](
const QString &s) {
568 qCWarning(lcQdoc) <<
"Cannot find index directory: " << s;
570 m_indexDirs.erase(it, m_indexDirs.end());
574
575
576
577
578
582 if (overrideOutputDir.isNull())
585 t = overrideOutputDir;
588 t += QLatin1Char(
'/') + project.toLower();
590 if (m_configVars.value(format + Config::dot +
"nosubdirs").asBool()) {
591 QString singleOutputSubdir = m_configVars.value(format + Config::dot +
"outputsubdir").asString();
592 if (singleOutputSubdir.isEmpty())
593 singleOutputSubdir =
"html";
594 t += QLatin1Char(
'/') + singleOutputSubdir;
596 return QDir::cleanPath(t);
600
601
602
603
606 if (overrideOutputFormats.isEmpty())
609 return overrideOutputFormats;
627
628
629
630
631
632
636 const auto &configVar = m_configVars.value(var);
638 for (
const auto &value : configVar.m_values) {
639 const QString ¤tPath = value.m_path;
640 QString rawValue = value.m_value.simplified();
643 if (flags & IncludePaths) {
644 const QStringList prefixes = QStringList()
645 << QLatin1String(
"-I")
646 << QLatin1String(
"-F")
647 << QLatin1String(
"-isystem");
648 const auto end = std::end(prefixes);
650 std::find_if(std::begin(prefixes), end,
651 [&rawValue](
const QString &p) {
652 return rawValue.startsWith(p);
656 rawValue.remove(0, it->size());
657 if (rawValue.isEmpty())
660 prefix = prefixes[0];
664 QDir dir(rawValue.trimmed());
665 const QString path = dir.path();
667 if (dir.isRelative())
668 dir.setPath(currentPath + QLatin1Char(
'/') + path);
669 if ((flags & Validate) && !QFileInfo::exists(dir.path()))
670 configVar.m_location.warning(QStringLiteral(
"Cannot find file or directory: %1").arg(path));
672 const QString canonicalPath = dir.canonicalPath();
673 if (!canonicalPath.isEmpty())
674 result.append(prefix + canonicalPath);
675 else if (path.contains(QLatin1Char(
'*')) || path.contains(QLatin1Char(
'?')))
679 qUtf8Printable(QStringLiteral(
"%1: Ignored nonexistent path \'%2\'")
680 .arg(configVar.m_location.toString(), rawValue));
687
688
689
690
691
692
693
697 const auto subRegExps = getRegExpList(var);
699 for (
const auto ®Exp : subRegExps) {
700 if (!regExp.isValid())
702 if (!pattern.isEmpty())
703 pattern += QLatin1Char(
'|');
704 pattern += QLatin1String(
"(?:") + regExp.pattern() + QLatin1Char(
')');
706 if (pattern.isEmpty())
707 pattern = QLatin1String(
"$x");
708 return QRegularExpression(pattern);
712
713
714
715
718 const QStringList strs = m_configVars.value(var).asStringList();
719 QList<QRegularExpression> regExps;
720 for (
const auto &str : strs)
721 regExps += QRegularExpression(str);
726
727
728
729
730
733 QSet<QString> result;
734 QString varDot = var + QLatin1Char(
'.');
735 for (
auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) {
736 if (it.key().startsWith(varDot)) {
737 QString subVar = it.key().mid(varDot.size());
738 int dot = subVar.indexOf(QLatin1Char(
'.'));
740 subVar.truncate(dot);
741 result.insert(subVar);
748
749
750
751
754 QString ext = QFileInfo(fileName).suffix();
756 if (!m_includeFilesMap.contains(ext)) {
758 result.erase(std::remove_if(result.begin(), result.end(),
759 [&](
const QString &s) {
return !s.endsWith(ext); }),
761 const QStringList dirs =
765 for (
const auto &dir : dirs)
766 result += getFilesHere(dir,
"*." + ext, location());
767 result.removeDuplicates();
768 m_includeFilesMap.insert(ext, result);
770 const QStringList &paths = (*m_includeFilesMap.find(ext));
771 QString match = fileName;
772 if (!match.startsWith(
'/'))
774 for (
const auto &path : paths) {
775 if (path.endsWith(match))
782
783
784
785
786
787
788
789
791 const QSet<QString> &excludedDirs,
792 const QSet<QString> &excludedFiles)
794 QStringList result = getCanonicalPathList(filesVar, Validate);
795 const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
799 for (
const auto &dir : dirs)
800 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
805 const QSet<QString> &excludedFiles)
808 const QStringList dirs = getCanonicalPathList(
"exampledirs");
809 const QString nameFilter =
" *.qdoc";
811 for (
const auto &dir : dirs)
812 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
817 const QSet<QString> &excludedFiles)
820 const QStringList dirs = getCanonicalPathList(
"exampledirs");
823 for (
const auto &dir : dirs)
824 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
836
837
838
841 QFileInfo fileInfo(examplePath);
842 QStringList validNames;
843 validNames << QLatin1String(
"CMakeLists.txt")
844 << fileInfo.fileName() + QLatin1String(
".pro")
845 << fileInfo.fileName() + QLatin1String(
".qmlproject")
846 << fileInfo.fileName() + QLatin1String(
".pyproject")
847 << QLatin1String(
"qbuild.pro");
851 for (
const auto &name : std::as_const(validNames)) {
852 projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs,
853 examplePath + QLatin1Char(
'/') + name);
854 if (!projectFile.isEmpty())
880
881
882
883
884
885
886
887
889 const QStringList &dirs,
const QString &fileName,
890 QString *userFriendlyFilePath)
892 if (fileName.isEmpty() || fileName.startsWith(QLatin1Char(
'/'))) {
893 if (userFriendlyFilePath)
894 *userFriendlyFilePath = fileName;
899 QStringList components = fileName.split(QLatin1Char(
'?'));
900 QString firstComponent = components.first();
902 for (
const auto &file : files) {
903 if (file == firstComponent || file.endsWith(QLatin1Char(
'/') + firstComponent)) {
904 fileInfo.setFile(file);
905 if (!fileInfo.exists())
906 location.fatal(QStringLiteral(
"File '%1' does not exist").arg(file));
911 if (fileInfo.fileName().isEmpty()) {
912 for (
const auto &dir : dirs) {
913 fileInfo.setFile(QDir(dir), firstComponent);
914 if (fileInfo.exists())
919 if (userFriendlyFilePath)
920 userFriendlyFilePath->clear();
921 if (!fileInfo.exists())
931 if (userFriendlyFilePath) {
932 for (
auto c = components.constBegin();;) {
933 bool isArchive = (c != components.constEnd() - 1);
934 userFriendlyFilePath->append(*c);
937 QString extracted = m_extractedDirs[fileInfo.filePath()];
940 fileInfo.setFile(QDir(extracted), *c);
945 userFriendlyFilePath->append(QLatin1Char(
'?'));
950 return fileInfo.filePath();
966
967
968
969
970
971
973 const QString &userFriendlySourceFilePath,
const QString &targetDirPath)
984 QFile inFile(sourceFilePath);
985 if (!inFile.open(QFile::ReadOnly)) {
986 location.warning(QStringLiteral(
"Cannot open input file for copy: '%1': %2")
987 .arg(sourceFilePath, inFile.errorString()));
1025 QString outFileName{userFriendlySourceFilePath};
1026 QFileInfo outFileNameInfo{userFriendlySourceFilePath};
1027 if (outFileNameInfo.isAbsolute())
1028 outFileName = outFileNameInfo.fileName();
1030 outFileName = targetDirPath +
"/" + outFileName;
1031 QDir targetDir(targetDirPath);
1032 if (!targetDir.exists())
1033 targetDir.mkpath(
".");
1035 QFile outFile(outFileName);
1036 if (!outFile.open(QFile::WriteOnly)) {
1038 location.warning(QStringLiteral(
"Cannot open output file for copy: '%1': %2")
1039 .arg(outFileName, outFile.errorString()));
1051 while ((len = inFile.read(buffer,
sizeof(buffer))) > 0)
1052 outFile.write(buffer, len);
1057
1058
1059
1063 for (
int i = 0; i != value.size(); ++i) {
1064 uint c = value[i].unicode();
1066 max = qMax(max,
static_cast<
int>(c));
1072
1073
1074
1075bool Config::isMetaKeyChar(QChar ch)
1077 return ch.isLetterOrNumber() || ch == QLatin1Char(
'_') || ch == QLatin1Char(
'.')
1078 || ch == QLatin1Char(
'{') || ch == QLatin1Char(
'}') || ch == QLatin1Char(
',');
1082
1083
1084
1085QStringList
Config::loadMaster(
const QString &fileName)
1088 QFile fin(fileName);
1089 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1090 if (!Config::installDir.isEmpty()) {
1091 qsizetype prefix = location.filePath().size() - location.fileName().size();
1092 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1093 + fileName.right(fileName.size() - prefix));
1095 if (!fin.open(QFile::ReadOnly | QFile::Text))
1096 location.fatal(QStringLiteral(
"Cannot open master qdocconf file '%1': %2")
1097 .arg(fileName, fin.errorString()));
1099 QTextStream stream(&fin);
1100 QStringList qdocFiles;
1101 QDir configDir(QFileInfo(fileName).canonicalPath());
1102 QString line = stream.readLine();
1103 while (!line.isNull()) {
1104 if (!line.isEmpty())
1105 qdocFiles.append(QFileInfo(configDir, line).filePath());
1106 line = stream.readLine();
1113
1114
1115
1116
1117
1120 QFileInfo fileInfo(fileName);
1121 pushWorkingDir(fileInfo.canonicalPath());
1122 static const QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String(
"\\w+(?:\\.\\w+)*")));
1126 location.advance(c);
1132#define SKIP_SPACES()
1133 while (c.isSpace() && cc != '\n')
1141 location.fatal(QStringLiteral(
"Too many nested includes"));
1143 QFile fin(fileInfo.fileName());
1144 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1145 if (!Config::installDir.isEmpty()) {
1146 qsizetype prefix = location.filePath().size() - location.fileName().size();
1147 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1148 + fileName.right(fileName.size() - prefix));
1150 if (!fin.open(QFile::ReadOnly | QFile::Text))
1152 QStringLiteral(
"Cannot open file '%1': %2").arg(fileName, fin.errorString()));
1155 QTextStream stream(&fin);
1156 QString text = stream.readAll();
1157 text += QLatin1String(
"\n\n");
1158 text += QLatin1Char(
'\0');
1161 location.push(fileName);
1165 QChar c = text.at(0);
1166 uint cc = c.unicode();
1167 while (i < text.size()) {
1170 }
else if (c.isSpace()) {
1172 }
else if (cc ==
'#') {
1175 }
while (cc !=
'\n');
1176 }
else if (isMetaKeyChar(c)) {
1179 QStringList rhsValues;
1180 QList<ExpandVar> expandVars;
1182 bool inQuote =
false;
1183 bool needsExpansion =
false;
1187 stack.process(c, location);
1189 }
while (isMetaKeyChar(c));
1191 const QStringList keys = stack.getExpanded(location);
1194 if (keys.size() == 1 && keys.first() == QLatin1String(
"include")) {
1195 QString includeFile;
1198 location.fatal(QStringLiteral(
"Bad include syntax"));
1202 while (!c.isSpace() && cc !=
'#' && cc !=
')') {
1207 while (c.isLetterOrNumber() || cc ==
'_') {
1211 if (!var.isEmpty()) {
1212 const QByteArray val = qgetenv(var.toLatin1().data());
1214 location.fatal(QStringLiteral(
"Environment variable '%1' undefined")
1217 includeFile += QString::fromLatin1(val);
1227 location.fatal(QStringLiteral(
"Bad include syntax"));
1230 if (cc !=
'#' && cc !=
'\n')
1231 location.fatal(QStringLiteral(
"Trailing garbage"));
1234
1235
1236 load(location, QFileInfo(QDir(m_workingDirs.top()), includeFile).filePath());
1239
1240
1241
1247 location.fatal(QStringLiteral(
"Expected '=' or '+=' after key"));
1253 qsizetype metaCharPos;
1258 }
else if (cc >
'0' && cc <
'8') {
1259 word += QChar(c.digitValue());
1261 }
else if ((metaCharPos = QString::fromLatin1(
"abfnrtv").indexOf(c))
1263 word += QLatin1Char(
"\a\b\f\n\r\t\v"[metaCharPos]);
1268 }
else if (c.isSpace() || cc ==
'#') {
1271 location.fatal(QStringLiteral(
"Unterminated string"));
1274 if (!word.isEmpty() || needsExpansion) {
1277 needsExpansion =
false;
1279 if (cc ==
'\n' || cc ==
'#')
1283 }
else if (cc ==
'"') {
1285 if (!word.isEmpty() || needsExpansion)
1288 needsExpansion =
false;
1292 }
else if (cc ==
'$') {
1295 bool braces =
false;
1301 while (c.isLetterOrNumber() || cc ==
'_') {
1313 else if (delim ==
'}')
1316 location.fatal(QStringLiteral(
"Missing '}'"));
1318 if (!var.isEmpty()) {
1319 const QByteArray val = qgetenv(var.toLatin1().constData());
1321 expandVars <<
ExpandVar(rhsValues.size(), word.size(),
std::move(var), delim);
1322 needsExpansion =
true;
1323 }
else if (braces) {
1324 text.insert(i, QString::fromLatin1(val));
1328 word += QString::fromLatin1(val);
1332 if (!inQuote && cc ==
'=')
1333 location.fatal(QStringLiteral(
"Unexpected '='"));
1337 for (
const auto &key : keys) {
1338 if (!keySyntax.match(key).hasMatch())
1339 keyLoc.fatal(QStringLiteral(
"Invalid key '%1'").arg(key));
1341 ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
1342 if (plus && m_configVars.contains(key)) {
1343 m_configVars[key].append(configVar);
1345 m_configVars.insert(key, configVar);
1350 location.fatal(QStringLiteral(
"Unexpected character '%1' at beginning of line").arg(c));
1360bool Config::isFileExcluded(
const QString &fileName,
const QSet<QString> &excludedFiles)
1362 for (
const QString &entry : excludedFiles) {
1363 if (entry.contains(QLatin1Char(
'*')) || entry.contains(QLatin1Char(
'?'))) {
1364 QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry));
1365 if (re.match(fileName).hasMatch())
1369 return excludedFiles.contains(fileName);
1372QStringList
Config::getFilesHere(
const QString &uncleanDir,
const QString &nameFilter,
1373 const Location &location,
const QSet<QString> &excludedDirs,
1374 const QSet<QString> &excludedFiles)
1379 location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath();
1381 if (excludedDirs.contains(dir))
1386 dirInfo.setNameFilters(nameFilter.split(QLatin1Char(
' ')));
1387 dirInfo.setSorting(QDir::Name);
1388 dirInfo.setFilter(QDir::Files);
1389 QStringList fileNames = dirInfo.entryList();
1390 for (
const auto &file : std::as_const(fileNames)) {
1393 if (!file.startsWith(QLatin1Char(
'~'))) {
1394 QString s = dirInfo.filePath(file);
1395 QString c = QDir::cleanPath(s);
1396 if (!isFileExcluded(c, excludedFiles))
1401 dirInfo.setNameFilters(QStringList(QLatin1String(
"*")));
1402 dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1403 fileNames = dirInfo.entryList();
1404 for (
const auto &file : fileNames)
1405 result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs,
1411
1412
1413
1414void Config::pushWorkingDir(
const QString &dir)
1416 m_workingDirs.push(dir);
1417 QDir::setCurrent(dir);
1421
1422
1423
1424
1427 Q_ASSERT(!m_workingDirs.isEmpty());
1428 m_workingDirs.pop();
1429 if (!m_workingDirs.isEmpty())
1430 QDir::setCurrent(m_workingDirs.top());
1434 if (m_excludedPaths)
1435 return *m_excludedPaths;
1440 QSet<QString> excludedDirs = QSet<QString>(excludedDirList.cbegin(), excludedDirList.cend());
1441 QSet<QString> excludedFiles = QSet<QString>(excludedFilesList.cbegin(), excludedFilesList.cend());
1443 m_excludedPaths.emplace(ExcludedPaths{std::move(excludedDirs), std::move(excludedFiles)});
1445 return *m_excludedPaths;
1449
1450
1451
1452
1453
1454
1455
1459 return QSet<QString>(patterns.cbegin(), patterns.cend());
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1477 if (m_internalFilePatterns)
1478 return *m_internalFilePatterns;
1483 for (
const QString &pattern : patterns) {
1484 static const QRegularExpression regexMetaChars(
1485 uR"(\.\*|\.\+|\.\{|\\[\.\*\?]|[\^\$\[\]{}()|+])"_s);
1486 bool isRawRegex = regexMetaChars.match(pattern).hasMatch();
1489 QRegularExpression re(pattern);
1490 if (!re.isValid()) {
1491 qWarning() <<
"Invalid regex pattern in internalfilepatterns:" << pattern
1492 <<
"-" << re.errorString();
1496 compiled.regexPatterns.append(re);
1497 }
else if (pattern.contains(u'*') || pattern.contains(u'?')) {
1498 QString regexPattern = QRegularExpression::wildcardToRegularExpression(pattern);
1499 QRegularExpression re(regexPattern);
1501 compiled.globPatterns.append(re);
1503 compiled.exactMatches.insert(pattern);
1507 m_internalFilePatterns.emplace(std::move(compiled));
1508 return *m_internalFilePatterns;
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526bool Config::matchesInternalFilePattern(
const QString &filePath,
1529 if (patterns.exactMatches.isEmpty() && patterns.globPatterns.isEmpty()
1530 && patterns.regexPatterns.isEmpty())
1533 QString norm = filePath;
1534 norm.replace(QChar(
'\\'), QChar(
'/'));
1536 if (patterns.exactMatches.contains(norm))
1539 const QString fileName = QFileInfo(norm).fileName();
1540 for (
const QRegularExpression &re : patterns.globPatterns) {
1541 if (re.match(fileName).hasMatch())
1545 for (
const QRegularExpression &re : patterns.regexPatterns) {
1546 if (re.match(norm).hasMatch())
1554
1555
1556
1560 return *m_sourceLink;
1564 const auto baseUrl = m_configVars.value(srcUrl).asString();
1565 const auto rootPath = m_configVars.value(srcUrl + dot +
CONFIG_ROOTDIR).asString();
1566 const auto linkText = m_configVars.value(srcUrl + dot +
"linktext").asString();
1567 const auto enabled = m_configVars.value(srcUrl + dot +
"enabled").asBool();
1569 m_sourceLink.emplace(SourceLink{baseUrl, rootPath, linkText, enabled});
1570 return *m_sourceLink;
1574 static QStringList accepted_header_file_extensions{
1575 "ch",
"h",
"h++",
"hh",
"hpp",
"hxx"
1580 QStringList headerList =
1583 std::set<HeaderFilePath> headers{};
1585 for (
const auto& header : headerList) {
1586 if (header.contains(
"doc/snippets"))
continue;
1588 if (!accepted_header_file_extensions.contains(QFileInfo{header}.suffix()))
1591 headers.insert(HeaderFilePath{QFileInfo{header}.canonicalPath(), QFileInfo{header}.fileName()});
1599 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.
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.
bool includePrivate() const
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_DOCBOOKEXTENSIONS
#define CONFIG_SINGLEEXEC
#define CONFIG_FALSEHOODS
#define CONFIG_EXAMPLEDIRS
#define CONFIG_WARNABOUTMISSINGPROJECTFILES
#define CONFIG_SYNTAXHIGHLIGHTING
#define CONFIG_TIMESTAMPS
#define CONFIG_NOLINKERRORS
#define CONFIG_LOGPROGRESS
#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 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 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