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;
83 QStringLiteral(
"redirectdocumentationtodevnull");
85 QStringLiteral(
"reportmissingalttextforimages");
117
118
119
132
133
134
137 next.append(QString());
141
142
143
144
152
153
154
155
166
167
168
176
177
178
179
182 if (ch == QLatin1Char(
'{')) {
185 }
else if (ch == QLatin1Char(
'}')) {
187 location.fatal(QStringLiteral(
"Unexpected '}'"));
190 const QStringList suffixes = pop().accum;
191 const QStringList prefixes = top().next;
194 for (
const auto &prefix : prefixes) {
195 for (
const auto &suffix : suffixes)
196 top().next << prefix + suffix;
198 }
else if (ch == QLatin1Char(
',') && size() > 1) {
202 for (QString &topNext : top().next)
208
209
213 location.fatal(QStringLiteral(
"Missing '}'"));
220bool Config::m_debug =
false;
221bool Config::m_atomsDump =
false;
227QMap<QString, QString>
Config::m_extractedDirs;
228QStack<QString>
Config::m_workingDirs;
229QMap<QString, QStringList>
Config::m_includeFilesMap;
232
233
234
235
238
239
240
241
242
243
244
245
246
249 if (m_name.isEmpty())
250 return defaultString;
253 for (
const auto &value : std::as_const(m_values)) {
254 if (!result.isEmpty() && !result.endsWith(QChar(
'\n')))
255 result.append(QChar(
' '));
256 result.append(value.m_value);
262
263
267 for (
const auto &value : std::as_const(m_values))
268 result << value.m_value;
273
274
277 const auto &stringList = asStringList();
278 return QSet<QString>(stringList.cbegin(), stringList.cend());
282
283
286 return QVariant(asString()).toBool();
290
291
292
293
294
295
296
299 const QStringList strs = asStringList();
304 for (
const auto &str : strs)
310
311
312
315 m_expandVars << other.m_expandVars;
316 QList<ExpandVar>::Iterator it = m_expandVars.end();
317 it -= other.m_expandVars.size();
318 std::for_each(it, m_expandVars.end(), [
this](ExpandVar &v) {
319 v.m_valueIndex += m_values.size();
321 m_values << other.m_values;
322 m_location = other.m_location;
326
327
328
329
330
331
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
353
354
355
356
357void Config::
init(
const QString &programName,
const QStringList &args)
359 m_prog = programName;
360 processCommandLineOptions(args);
370
371
374 m_location = Location();
375 m_configVars.clear();
376 m_includeFilesMap.clear();
377 m_excludedPaths.reset();
378 m_sourceLink.reset();
379 m_internalFilePatterns.reset();
383
384
385
391 load(Location(), u":/qdoc/config/defaults.qdocconf"_s);
394 const auto setListFlag = [
this](
const QString &key,
bool test) {
395 setStringList(key, QStringList(test ? QStringLiteral(
"true") : QStringLiteral(
"false")));
397#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
406 m_parser.isSet(m_parser.noLinkErrorsOption)
407 || qEnvironmentVariableIsSet(
"QDOC_NOLINKERRORS"));
413
414
415
416
417
424 load(Location(), fileName);
425 if (m_location.isEmpty())
426 m_location = Location(fileName);
428 m_location.setEtc(
true);
432 setStringList(varName, getCanonicalPathList(varName, Validate));
445 m_reportMissingAltTextForImages =
448 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
1124
1125
1126
1127
1128
1129
1132 QFileInfo fileInfo(fileName);
1133 const bool isResource = fileName.startsWith(u':');
1135 pushWorkingDir(fileInfo.canonicalPath());
1136 static const QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String(
"\\w+(?:\\.\\w+)*")));
1140 location.advance(c);
1146#define SKIP_SPACES()
1147 while (c.isSpace() && cc != '\n')
1155 location.fatal(QStringLiteral(
"Too many nested includes"));
1157 QFile fin(isResource ? fileInfo.filePath() : fileInfo.fileName());
1158 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1159 if (!Config::installDir.isEmpty()) {
1160 qsizetype prefix = location.filePath().size() - location.fileName().size();
1161 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1162 + fileName.right(fileName.size() - prefix));
1164 if (!fin.open(QFile::ReadOnly | QFile::Text))
1166 QStringLiteral(
"Cannot open file '%1': %2").arg(fileName, fin.errorString()));
1169 QTextStream stream(&fin);
1170 QString text = stream.readAll();
1171 text += QLatin1String(
"\n\n");
1172 text += QLatin1Char(
'\0');
1175 location.push(fileName);
1179 QChar c = text.at(0);
1180 uint cc = c.unicode();
1181 while (i < text.size()) {
1184 }
else if (c.isSpace()) {
1186 }
else if (cc ==
'#') {
1189 }
while (cc !=
'\n');
1190 }
else if (isMetaKeyChar(c)) {
1193 QStringList rhsValues;
1194 QList<ExpandVar> expandVars;
1196 bool inQuote =
false;
1197 bool needsExpansion =
false;
1201 stack.process(c, location);
1203 }
while (isMetaKeyChar(c));
1205 const QStringList keys = stack.getExpanded(location);
1208 if (keys.size() == 1 && keys.first() == QLatin1String(
"include")) {
1209 QString includeFile;
1212 location.fatal(QStringLiteral(
"Bad include syntax"));
1216 while (!c.isSpace() && cc !=
'#' && cc !=
')') {
1221 while (c.isLetterOrNumber() || cc ==
'_') {
1225 if (!var.isEmpty()) {
1226 const QByteArray val = qgetenv(var.toLatin1().data());
1228 location.fatal(QStringLiteral(
"Environment variable '%1' undefined")
1231 includeFile += QString::fromLatin1(val);
1241 location.fatal(QStringLiteral(
"Bad include syntax"));
1244 if (cc !=
'#' && cc !=
'\n')
1245 location.fatal(QStringLiteral(
"Trailing garbage"));
1248
1249
1251 load(location, includeFile);
1253 load(location, QFileInfo(QDir(m_workingDirs.top()), includeFile).filePath());
1256
1257
1258
1264 location.fatal(QStringLiteral(
"Expected '=' or '+=' after key"));
1270 qsizetype metaCharPos;
1275 }
else if (cc >
'0' && cc <
'8') {
1276 word += QChar(c.digitValue());
1278 }
else if ((metaCharPos = QString::fromLatin1(
"abfnrtv").indexOf(c))
1280 word += QLatin1Char(
"\a\b\f\n\r\t\v"[metaCharPos]);
1285 }
else if (c.isSpace() || cc ==
'#') {
1288 location.fatal(QStringLiteral(
"Unterminated string"));
1291 if (!word.isEmpty() || needsExpansion) {
1294 needsExpansion =
false;
1296 if (cc ==
'\n' || cc ==
'#')
1300 }
else if (cc ==
'"') {
1302 if (!word.isEmpty() || needsExpansion)
1305 needsExpansion =
false;
1309 }
else if (cc ==
'$') {
1312 bool braces =
false;
1318 while (c.isLetterOrNumber() || cc ==
'_') {
1330 else if (delim ==
'}')
1333 location.fatal(QStringLiteral(
"Missing '}'"));
1335 if (!var.isEmpty()) {
1336 const QByteArray val = qgetenv(var.toLatin1().constData());
1338 expandVars <<
ExpandVar(rhsValues.size(), word.size(),
std::move(var), delim);
1339 needsExpansion =
true;
1340 }
else if (braces) {
1341 text.insert(i, QString::fromLatin1(val));
1345 word += QString::fromLatin1(val);
1349 if (!inQuote && cc ==
'=')
1350 location.fatal(QStringLiteral(
"Unexpected '='"));
1354 for (
const auto &key : keys) {
1355 if (!keySyntax.match(key).hasMatch())
1356 keyLoc.fatal(QStringLiteral(
"Invalid key '%1'").arg(key));
1358 ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
1359 if (plus && m_configVars.contains(key)) {
1360 m_configVars[key].append(configVar);
1362 m_configVars.insert(key, configVar);
1367 location.fatal(QStringLiteral(
"Unexpected character '%1' at beginning of line").arg(c));
1378bool Config::isFileExcluded(
const QString &fileName,
const QSet<QString> &excludedFiles)
1380 for (
const QString &entry : excludedFiles) {
1381 if (entry.contains(QLatin1Char(
'*')) || entry.contains(QLatin1Char(
'?'))) {
1382 QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry,
1383 QRegularExpression::UnanchoredWildcardConversion));
1384 if (re.match(fileName).hasMatch())
1388 return excludedFiles.contains(fileName);
1391QStringList
Config::getFilesHere(
const QString &uncleanDir,
const QString &nameFilter,
1392 const Location &location,
const QSet<QString> &excludedDirs,
1393 const QSet<QString> &excludedFiles)
1398 location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath();
1400 if (excludedDirs.contains(dir))
1405 dirInfo.setNameFilters(nameFilter.split(QLatin1Char(
' ')));
1406 dirInfo.setSorting(QDir::Name);
1407 dirInfo.setFilter(QDir::Files);
1408 QStringList fileNames = dirInfo.entryList();
1409 for (
const auto &file : std::as_const(fileNames)) {
1412 if (!file.startsWith(QLatin1Char(
'~'))) {
1413 QString s = dirInfo.filePath(file);
1414 QString c = QDir::cleanPath(s);
1415 if (!isFileExcluded(c, excludedFiles))
1420 dirInfo.setNameFilters(QStringList(QLatin1String(
"*")));
1421 dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1422 fileNames = dirInfo.entryList();
1423 for (
const auto &file : fileNames)
1424 result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs,
1430
1431
1432
1433void Config::pushWorkingDir(
const QString &dir)
1435 m_workingDirs.push(dir);
1436 QDir::setCurrent(dir);
1440
1441
1442
1443
1446 Q_ASSERT(!m_workingDirs.isEmpty());
1447 m_workingDirs.pop();
1448 if (!m_workingDirs.isEmpty())
1449 QDir::setCurrent(m_workingDirs.top());
1453 if (m_excludedPaths)
1454 return *m_excludedPaths;
1459 QSet<QString> excludedDirs = QSet<QString>(excludedDirList.cbegin(), excludedDirList.cend());
1460 QSet<QString> excludedFiles = QSet<QString>(excludedFilesList.cbegin(), excludedFilesList.cend());
1462 m_excludedPaths.emplace(ExcludedPaths{std::move(excludedDirs), std::move(excludedFiles)});
1464 return *m_excludedPaths;
1468
1469
1470
1471
1472
1473
1474
1478 return QSet<QString>(patterns.cbegin(), patterns.cend());
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1496 if (m_internalFilePatterns)
1497 return *m_internalFilePatterns;
1502 for (
const QString &pattern : patterns) {
1503 static const QRegularExpression regexMetaChars(
1504 uR"(\.\*|\.\+|\.\{|\\[\.\*\?]|[\^\$\[\]{}()|+])"_s);
1505 bool isRawRegex = regexMetaChars.match(pattern).hasMatch();
1508 QRegularExpression re(pattern);
1509 if (!re.isValid()) {
1510 qWarning() <<
"Invalid regex pattern in internalfilepatterns:" << pattern
1511 <<
"-" << re.errorString();
1515 compiled.regexPatterns.append(re);
1516 }
else if (pattern.contains(u'*') || pattern.contains(u'?')) {
1517 QString regexPattern = QRegularExpression::wildcardToRegularExpression(pattern);
1518 QRegularExpression re(regexPattern);
1520 compiled.globPatterns.append(re);
1522 compiled.exactMatches.insert(pattern);
1526 m_internalFilePatterns.emplace(std::move(compiled));
1527 return *m_internalFilePatterns;
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545bool Config::matchesInternalFilePattern(
const QString &filePath,
1548 if (patterns.exactMatches.isEmpty() && patterns.globPatterns.isEmpty()
1549 && patterns.regexPatterns.isEmpty())
1552 QString norm = filePath;
1553 norm.replace(QChar(
'\\'), QChar(
'/'));
1555 if (patterns.exactMatches.contains(norm))
1558 const QString fileName = QFileInfo(norm).fileName();
1559 for (
const QRegularExpression &re : patterns.globPatterns) {
1560 if (re.match(fileName).hasMatch())
1564 for (
const QRegularExpression &re : patterns.regexPatterns) {
1565 if (re.match(norm).hasMatch())
1573
1574
1575
1579 return *m_sourceLink;
1583 const auto baseUrl = m_configVars.value(srcUrl).asString();
1584 const auto rootPath = m_configVars.value(srcUrl + dot +
CONFIG_ROOTDIR).asString();
1585 const auto linkText = m_configVars.value(srcUrl + dot +
"linktext").asString();
1586 const auto enabled = m_configVars.value(srcUrl + dot +
"enabled").asBool();
1588 m_sourceLink.emplace(SourceLink{baseUrl, rootPath, linkText, enabled});
1589 return *m_sourceLink;
1593 static QStringList accepted_header_file_extensions{
1594 "ch",
"h",
"h++",
"hh",
"hpp",
"hxx"
1599 QStringList headerList =
1602 std::set<HeaderFilePath> headers{};
1604 for (
const auto& header : headerList) {
1605 if (header.contains(
"doc/snippets"))
continue;
1607 if (!accepted_header_file_extensions.contains(QFileInfo{header}.suffix()))
1610 headers.insert(HeaderFilePath{QFileInfo{header}.canonicalPath(), QFileInfo{header}.fileName()});
1623 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.
static bool parseCppComments
void reset()
Resets the Config instance and loads the default values.
InclusionPolicy createInclusionPolicy() const
void setStringList(const QString &var, const QStringList &values)
Sets the values of a configuration variable var from a string list.
void clear()
Clears the location and internal maps for config variables.
QSet< QString > subVars(const QString &var) const
This function is slower than it could be.
bool includePrivateType() const
PathFlags
Flags used for retrieving canonicalized paths from Config.
bool includePrivateVariable() const
const ExcludedPaths & getExcludedPaths()
QSet< QString > getOutputFormats() const
Function to return the correct outputformats.
static void popWorkingDir()
Pop the top entry from the stack of working directories.
bool showAutoGeneratedDocs() const
QRegularExpression getRegExp(const QString &var) const
Calls getRegExpList() with the control variable var and iterates through the resulting list of regula...
QString getExampleProjectFile(const QString &examplePath)
Returns the path to the project file for examplePath, or an empty string if no project file was found...
bool includePrivateFunction() const
static QSet< QString > overrideOutputFormats
static QString overrideOutputDir
QStringList getCanonicalPathList(const QString &var, PathFlags flags=None) const
Returns a path list where all paths from the config variable var are canonicalized.
void load(const QString &fileName)
Loads and parses the qdoc configuration file fileName.
const SourceLink & getSourceLink()
Returns a SourceLink struct with settings required to construct source links to API entities.
bool showInternal() const
QList< QRegularExpression > getRegExpList(const QString &var) const
Looks up the configuration variable var in the string list map, converts the string list to a list of...
QStringList getExampleImageFiles(const QSet< QString > &excludedDirs, const QSet< QString > &excludedFiles)
QStringList getExampleQdocFiles(const QSet< QString > &excludedDirs, const QSet< QString > &excludedFiles)
const InternalFilePatterns & getInternalFilePatternsCompiled()
Returns a reference to the pre-compiled internal file patterns structure.
void init(const QString &programName, const QStringList &args)
Initializes the Config with programName and sets all internal state variables to either default value...
QString getIncludeFilePath(const QString &fileName) const
Searches for a path to fileName in 'sources', 'sourcedirs', and 'exampledirs' config variables and re...
The Location class provides a way to mark a location in a file.
void start()
If the file position on top of the stack has a line number less than 1, set its line number to 1 and ...
An entry in a stack, where each entry is a list of string values.
void close()
Stop accumulating values and append the list of accumulated values to the complete list of accumulate...
void open()
Start accumulating values in a list by appending an empty string to the list.
Q_DECLARE_TYPEINFO(MetaStackEntry, Q_RELOCATABLE_TYPE)
#define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL
#define CONFIG_FILEEXTENSIONS
#define CONFIG_AUTOLINKERRORS
#define CONFIG_SHOWINTERNAL
#define CONFIG_SHOWAUTOGENERATEDDOCS
#define CONFIG_DOCBOOKEXTENSIONS
#define CONFIG_SINGLEEXEC
#define CONFIG_EXAMPLEDIRS
#define CONFIG_SYNTAXHIGHLIGHTING
#define CONFIG_TIMESTAMPS
#define CONFIG_NOLINKERRORS
#define CONFIG_LOGPROGRESS
#define CONFIG_PARSECPPCOMMENTS
#define CONFIG_SOURCEDIRS
#define CONFIG_INTERNALFILEPATTERNS
#define CONFIG_OUTPUTFORMATS
#define CONFIG_IMAGEEXTENSIONS
#define CONFIG_EXCLUDEFILES
#define CONFIG_MODULEHEADER
#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 PARSECPPCOMMENTS
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