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
81
82
83
84
85
86
95
96
97
98
99
100
101
105 QStringLiteral(
"redirectdocumentationtodevnull");
107 QStringLiteral(
"reportmissingalttextforimages");
125
126
127
128
129
130
131
150
151
152
165
166
167
170 next.append(QString());
174
175
176
177
185
186
187
188
199
200
201
209
210
211
212
215 if (ch == QLatin1Char(
'{')) {
218 }
else if (ch == QLatin1Char(
'}')) {
220 location.fatal(QStringLiteral(
"Unexpected '}'"));
223 const QStringList suffixes = pop().accum;
224 const QStringList prefixes = top().next;
227 for (
const auto &prefix : prefixes) {
228 for (
const auto &suffix : suffixes)
229 top().next << prefix + suffix;
231 }
else if (ch == QLatin1Char(
',') && size() > 1) {
235 for (QString &topNext : top().next)
241
242
246 location.fatal(QStringLiteral(
"Missing '}'"));
253bool Config::m_debug =
false;
254bool Config::m_atomsDump =
false;
260QMap<QString, QString>
Config::m_extractedDirs;
261QStack<QString>
Config::m_workingDirs;
262QMap<QString, QStringList>
Config::m_includeFilesMap;
265
266
267
268
271
272
273
274
275
276
277
278
279
282 if (m_name.isEmpty())
283 return defaultString;
286 for (
const auto &value : std::as_const(m_values)) {
287 if (!result.isEmpty() && !result.endsWith(QChar(
'\n')))
288 result.append(QChar(
' '));
289 result.append(value.m_value);
295
296
300 for (
const auto &value : std::as_const(m_values))
301 result << value.m_value;
306
307
310 const auto &stringList = asStringList();
311 return QSet<QString>(stringList.cbegin(), stringList.cend());
315
316
319 return QVariant(asString()).toBool();
323
324
325
326
327
328
329
332 const QStringList strs = asStringList();
337 for (
const auto &str : strs)
343
344
345
348 m_expandVars << other.m_expandVars;
349 QList<ExpandVar>::Iterator it = m_expandVars.end();
350 it -= other.m_expandVars.size();
351 std::for_each(it, m_expandVars.end(), [
this](ExpandVar &v) {
352 v.m_valueIndex += m_values.size();
354 m_values << other.m_values;
355 m_location = other.m_location;
359
360
361
362
363
364
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
386
387
388
389
390void Config::
init(
const QString &programName,
const QStringList &args)
392 m_prog = programName;
393 processCommandLineOptions(args);
403
404
407 m_location = Location();
408 m_configVars.clear();
409 m_includeFilesMap.clear();
410 m_excludedPaths.reset();
411 m_sourceLink.reset();
412 m_internalFilePatterns.reset();
416
417
418
424 load(Location(), u":/qdoc/config/defaults.qdocconf"_s);
427 const auto setListFlag = [
this](
const QString &key,
bool test) {
428 setStringList(key, QStringList(test ? QStringLiteral(
"true") : QStringLiteral(
"false")));
430#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test))
437 m_parser.isSet(m_parser.showInternalOption)
438 || qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL"));
441 m_parser.isSet(m_parser.noLinkErrorsOption)
442 || qEnvironmentVariableIsSet(
"QDOC_NOLINKERRORS"));
448
449
450
451
452
459 load(Location(), fileName);
460 if (m_location.isEmpty())
461 m_location = Location(fileName);
463 m_location.setEtc(
true);
467 setStringList(varName, getCanonicalPathList(varName, Validate));
480 m_reportMissingAltTextForImages =
483 if (!m_parser.isSet(m_parser.showInternalOption) && !qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL"))
498
499
500void Config::expandVariables()
502 for (
auto &configVar : m_configVars) {
503 for (
auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) {
504 Q_ASSERT(it->m_valueIndex < configVar.m_values.size());
505 const QString &key = it->m_var;
506 const auto &refVar = m_configVars.value(key);
507 if (refVar.m_name.isEmpty()) {
508 configVar.m_location.fatal(
509 QStringLiteral(
"Environment or configuration variable '%1' undefined")
511 }
else if (!refVar.m_expandVars.empty()) {
512 configVar.m_location.fatal(
513 QStringLiteral(
"Nested variable expansion not allowed"),
514 QStringLiteral(
"When expanding '%1' at %2:%3")
515 .arg(refVar.m_name, refVar.m_location.filePath(),
516 QString::number(refVar.m_location.lineNo())));
519 if (it->m_delim.isNull())
520 expanded = m_configVars.value(key).asStringList().join(QString());
522 expanded = m_configVars.value(key).asStringList().join(it->m_delim);
523 configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded);
525 configVar.m_expandVars.clear();
530
531
534 m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath()));
538
539
540
543 m_configVars[var].append(ConfigVar(var, values, QDir::currentPath()));
547
548
549void Config::processCommandLineOptions(
const QStringList &args)
551 m_parser.process(args);
553 m_defines = m_parser.values(m_parser.defineOption);
554 m_dependModules = m_parser.values(m_parser.dependsOption);
559 if (m_parser.isSet(m_parser.installDirOption))
560 installDir = m_parser.value(m_parser.installDirOption);
561 if (m_parser.isSet(m_parser.outputDirOption))
562 overrideOutputDir = QDir(m_parser.value(m_parser.outputDirOption)).absolutePath();
564 const auto outputFormats = m_parser.values(m_parser.outputFormatOption);
565 for (
const auto &format : outputFormats)
566 overrideOutputFormats.insert(format);
567 m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet(
"QDOC_DEBUG");
568 m_atomsDump = m_parser.isSet(m_parser.atomsDumpOption);
569 m_showInternal = m_parser.isSet(m_parser.showInternalOption)
570 || qEnvironmentVariableIsSet(
"QDOC_SHOW_INTERNAL");
572 if (m_parser.isSet(m_parser.prepareOption))
574 if (m_parser.isSet(m_parser.generateOption))
576 if (m_debug || m_parser.isSet(m_parser.logProgressOption))
578 if (m_parser.isSet(m_parser.timestampsOption))
580 if (m_parser.isSet(m_parser.useDocBookExtensions))
584void Config::setIncludePaths()
586 QDir currentDir = QDir::current();
587 const auto addIncludePaths = [
this, currentDir](
const char *flag,
const QStringList &paths) {
588 for (
const auto &path : paths)
589 m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag);
592 addIncludePaths(
"-I", m_parser.values(m_parser.includePathOption));
593#ifdef QDOC_PASS_ISYSTEM
594 addIncludePaths(
"-isystem", m_parser.values(m_parser.includePathSystemOption));
596 addIncludePaths(
"-F", m_parser.values(m_parser.frameworkOption));
600
601
602void Config::setIndexDirs()
604 m_indexDirs = m_parser.values(m_parser.indexDirOption);
605 auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(),
606 [](
const QString &s) {
return !QFile::exists(s); });
608 std::for_each(it, m_indexDirs.end(), [](
const QString &s) {
609 qCWarning(lcQdoc) <<
"Cannot find index directory: " << s;
611 m_indexDirs.erase(it, m_indexDirs.end());
615
616
617
618
619
623 if (overrideOutputDir.isNull())
626 t = overrideOutputDir;
629 t += QLatin1Char(
'/') + project.toLower();
631 if (m_configVars.value(format + Config::dot +
"nosubdirs").asBool()) {
632 QString singleOutputSubdir = m_configVars.value(format + Config::dot +
"outputsubdir").asString();
633 if (singleOutputSubdir.isEmpty())
634 singleOutputSubdir =
"html";
635 t += QLatin1Char(
'/') + singleOutputSubdir;
637 return QDir::cleanPath(t);
641
642
643
644
645
646
647
648
649
650
653
654
655
656
657
658
659
660
663
664
665
666
669 if (overrideOutputFormats.isEmpty())
672 return overrideOutputFormats;
690
691
692
693
694
695
699 const auto &configVar = m_configVars.value(var);
701 for (
const auto &value : configVar.m_values) {
702 const QString ¤tPath = value.m_path;
703 QString rawValue = value.m_value.simplified();
706 if (flags & IncludePaths) {
707 const QStringList prefixes = QStringList()
708 << QLatin1String(
"-I")
709 << QLatin1String(
"-F")
710 << QLatin1String(
"-isystem");
711 const auto end = std::end(prefixes);
713 std::find_if(std::begin(prefixes), end,
714 [&rawValue](
const QString &p) {
715 return rawValue.startsWith(p);
719 rawValue.remove(0, it->size());
720 if (rawValue.isEmpty())
723 prefix = prefixes[0];
727 QDir dir(rawValue.trimmed());
728 const QString path = dir.path();
730 if (dir.isRelative())
731 dir.setPath(currentPath + QLatin1Char(
'/') + path);
732 if ((flags & Validate) && !QFileInfo::exists(dir.path()))
733 configVar.m_location.warning(QStringLiteral(
"Cannot find file or directory: %1").arg(path));
735 const QString canonicalPath = dir.canonicalPath();
736 if (!canonicalPath.isEmpty())
737 result.append(prefix + canonicalPath);
738 else if (path.contains(QLatin1Char(
'*')) || path.contains(QLatin1Char(
'?')))
742 qUtf8Printable(QStringLiteral(
"%1: Ignored nonexistent path \'%2\'")
743 .arg(configVar.m_location.toString(), rawValue));
750
751
752
753
754
755
756
760 const auto subRegExps = getRegExpList(var);
762 for (
const auto ®Exp : subRegExps) {
763 if (!regExp.isValid())
765 if (!pattern.isEmpty())
766 pattern += QLatin1Char(
'|');
767 pattern += QLatin1String(
"(?:") + regExp.pattern() + QLatin1Char(
')');
769 if (pattern.isEmpty())
770 pattern = QLatin1String(
"$x");
771 return QRegularExpression(pattern);
775
776
777
778
781 const QStringList strs = m_configVars.value(var).asStringList();
782 QList<QRegularExpression> regExps;
783 for (
const auto &str : strs)
784 regExps += QRegularExpression(str);
789
790
791
792
793
796 QSet<QString> result;
797 QString varDot = var + QLatin1Char(
'.');
798 for (
auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) {
799 if (it.key().startsWith(varDot)) {
800 QString subVar = it.key().mid(varDot.size());
801 int dot = subVar.indexOf(QLatin1Char(
'.'));
803 subVar.truncate(dot);
804 result.insert(subVar);
811
812
813
814
817 QString ext = QFileInfo(fileName).suffix();
819 if (!m_includeFilesMap.contains(ext)) {
821 result.erase(std::remove_if(result.begin(), result.end(),
822 [&](
const QString &s) {
return !s.endsWith(ext); }),
824 const QStringList dirs =
828 for (
const auto &dir : dirs)
829 result += getFilesHere(dir,
"*." + ext, location());
830 result.removeDuplicates();
831 m_includeFilesMap.insert(ext, result);
833 const QStringList &paths = (*m_includeFilesMap.find(ext));
834 QString match = fileName;
835 if (!match.startsWith(
'/'))
837 for (
const auto &path : paths) {
838 if (path.endsWith(match))
845
846
847
848
849
850
851
852
854 const QSet<QString> &excludedDirs,
855 const QSet<QString> &excludedFiles)
857 QStringList result = getCanonicalPathList(filesVar, Validate);
858 const QStringList dirs = getCanonicalPathList(dirsVar, Validate);
862 for (
const auto &dir : dirs)
863 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
868 const QSet<QString> &excludedFiles)
871 const QStringList dirs = getCanonicalPathList(
"exampledirs");
872 const QString nameFilter =
" *.qdoc";
874 for (
const auto &dir : dirs)
875 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
880 const QSet<QString> &excludedFiles)
883 const QStringList dirs = getCanonicalPathList(
"exampledirs");
886 for (
const auto &dir : dirs)
887 result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles);
899
900
901
904 QFileInfo fileInfo(examplePath);
905 QStringList validNames;
906 validNames << QLatin1String(
"CMakeLists.txt")
907 << fileInfo.fileName() + QLatin1String(
".pro")
908 << fileInfo.fileName() + QLatin1String(
".qmlproject")
909 << fileInfo.fileName() + QLatin1String(
".pyproject")
910 << QLatin1String(
"qbuild.pro");
914 for (
const auto &name : std::as_const(validNames)) {
915 projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs,
916 examplePath + QLatin1Char(
'/') + name);
917 if (!projectFile.isEmpty())
943
944
945
946
947
948
949
950
952 const QStringList &dirs,
const QString &fileName,
953 QString *userFriendlyFilePath)
955 if (fileName.isEmpty() || fileName.startsWith(QLatin1Char(
'/'))) {
956 if (userFriendlyFilePath)
957 *userFriendlyFilePath = fileName;
962 QStringList components = fileName.split(QLatin1Char(
'?'));
963 QString firstComponent = components.first();
965 for (
const auto &file : files) {
966 if (file == firstComponent || file.endsWith(QLatin1Char(
'/') + firstComponent)) {
967 fileInfo.setFile(file);
968 if (!fileInfo.exists())
969 location.fatal(QStringLiteral(
"File '%1' does not exist").arg(file));
974 if (fileInfo.fileName().isEmpty()) {
975 for (
const auto &dir : dirs) {
976 fileInfo.setFile(QDir(dir), firstComponent);
977 if (fileInfo.exists())
982 if (userFriendlyFilePath)
983 userFriendlyFilePath->clear();
984 if (!fileInfo.exists())
994 if (userFriendlyFilePath) {
995 for (
auto c = components.constBegin();;) {
996 bool isArchive = (c != components.constEnd() - 1);
997 userFriendlyFilePath->append(*c);
1000 QString extracted = m_extractedDirs[fileInfo.filePath()];
1003 fileInfo.setFile(QDir(extracted), *c);
1008 userFriendlyFilePath->append(QLatin1Char(
'?'));
1013 return fileInfo.filePath();
1029
1030
1031
1032
1033
1034
1036 const QString &userFriendlySourceFilePath,
const QString &targetDirPath)
1047 QFile inFile(sourceFilePath);
1048 if (!inFile.open(QFile::ReadOnly)) {
1049 location.warning(QStringLiteral(
"Cannot open input file for copy: '%1': %2")
1050 .arg(sourceFilePath, inFile.errorString()));
1088 QString outFileName{userFriendlySourceFilePath};
1089 QFileInfo outFileNameInfo{userFriendlySourceFilePath};
1090 if (outFileNameInfo.isAbsolute())
1091 outFileName = outFileNameInfo.fileName();
1093 outFileName = targetDirPath +
"/" + outFileName;
1094 QDir targetDir(targetDirPath);
1095 if (!targetDir.exists())
1096 targetDir.mkpath(
".");
1098 QFile outFile(outFileName);
1099 if (!outFile.open(QFile::WriteOnly)) {
1101 location.warning(QStringLiteral(
"Cannot open output file for copy: '%1': %2")
1102 .arg(outFileName, outFile.errorString()));
1114 while ((len = inFile.read(buffer,
sizeof(buffer))) > 0)
1115 outFile.write(buffer, len);
1120
1121
1122
1126 for (
int i = 0; i != value.size(); ++i) {
1127 uint c = value[i].unicode();
1129 max = qMax(max,
static_cast<
int>(c));
1135
1136
1137
1138bool Config::isMetaKeyChar(QChar ch)
1140 return ch.isLetterOrNumber() || ch == QLatin1Char(
'_') || ch == QLatin1Char(
'.')
1141 || ch == QLatin1Char(
'{') || ch == QLatin1Char(
'}') || ch == QLatin1Char(
',');
1145
1146
1147
1148QStringList
Config::loadMaster(
const QString &fileName)
1151 QFile fin(fileName);
1152 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1153 if (!Config::installDir.isEmpty()) {
1154 qsizetype prefix = location.filePath().size() - location.fileName().size();
1155 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1156 + fileName.right(fileName.size() - prefix));
1158 if (!fin.open(QFile::ReadOnly | QFile::Text))
1159 location.fatal(QStringLiteral(
"Cannot open master qdocconf file '%1': %2")
1160 .arg(fileName, fin.errorString()));
1162 QTextStream stream(&fin);
1163 QStringList qdocFiles;
1164 QDir configDir(QFileInfo(fileName).canonicalPath());
1165 QString line = stream.readLine();
1166 while (!line.isNull()) {
1167 if (!line.isEmpty())
1168 qdocFiles.append(QFileInfo(configDir, line).filePath());
1169 line = stream.readLine();
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1189 QFileInfo fileInfo(fileName);
1190 const bool isResource = fileName.startsWith(u':');
1192 pushWorkingDir(fileInfo.canonicalPath());
1193 static const QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String(
"\\w+(?:\\.\\w+)*")));
1197 location.advance(c);
1203#define SKIP_SPACES()
1204 while (c.isSpace() && cc != '\n')
1212 location.fatal(QStringLiteral(
"Too many nested includes"));
1214 QFile fin(isResource ? fileInfo.filePath() : fileInfo.fileName());
1215 if (!fin.open(QFile::ReadOnly | QFile::Text)) {
1216 if (!Config::installDir.isEmpty()) {
1217 qsizetype prefix = location.filePath().size() - location.fileName().size();
1218 fin.setFileName(Config::installDir + QLatin1Char(
'/')
1219 + fileName.right(fileName.size() - prefix));
1221 if (!fin.open(QFile::ReadOnly | QFile::Text))
1223 QStringLiteral(
"Cannot open file '%1': %2").arg(fileName, fin.errorString()));
1226 QTextStream stream(&fin);
1227 QString text = stream.readAll();
1228 text += QLatin1String(
"\n\n");
1229 text += QLatin1Char(
'\0');
1232 location.push(fileName);
1236 QChar c = text.at(0);
1237 uint cc = c.unicode();
1238 while (i < text.size()) {
1241 }
else if (c.isSpace()) {
1243 }
else if (cc ==
'#') {
1246 }
while (cc !=
'\n');
1247 }
else if (isMetaKeyChar(c)) {
1250 QStringList rhsValues;
1251 QList<ExpandVar> expandVars;
1253 bool inQuote =
false;
1254 bool needsExpansion =
false;
1258 stack.process(c, location);
1260 }
while (isMetaKeyChar(c));
1262 const QStringList keys = stack.getExpanded(location);
1265 if (keys.size() == 1 && keys.first() == QLatin1String(
"include")) {
1266 QString includeFile;
1269 location.fatal(QStringLiteral(
"Bad include syntax"));
1273 while (!c.isSpace() && cc !=
'#' && cc !=
')') {
1278 while (c.isLetterOrNumber() || cc ==
'_') {
1282 if (!var.isEmpty()) {
1283 const QByteArray val = qgetenv(var.toLatin1().data());
1285 location.fatal(QStringLiteral(
"Environment variable '%1' undefined")
1288 includeFile += QString::fromLatin1(val);
1298 location.fatal(QStringLiteral(
"Bad include syntax"));
1301 if (cc !=
'#' && cc !=
'\n')
1302 location.fatal(QStringLiteral(
"Trailing garbage"));
1305
1306
1308 load(location, includeFile);
1310 load(location, QFileInfo(QDir(m_workingDirs.top()), includeFile).filePath());
1313
1314
1315
1321 location.fatal(QStringLiteral(
"Expected '=' or '+=' after key"));
1327 qsizetype metaCharPos;
1332 }
else if (cc >
'0' && cc <
'8') {
1333 word += QChar(c.digitValue());
1335 }
else if ((metaCharPos = QString::fromLatin1(
"abfnrtv").indexOf(c))
1337 word += QLatin1Char(
"\a\b\f\n\r\t\v"[metaCharPos]);
1342 }
else if (c.isSpace() || cc ==
'#') {
1345 location.fatal(QStringLiteral(
"Unterminated string"));
1348 if (!word.isEmpty() || needsExpansion) {
1351 needsExpansion =
false;
1353 if (cc ==
'\n' || cc ==
'#')
1357 }
else if (cc ==
'"') {
1359 if (!word.isEmpty() || needsExpansion)
1362 needsExpansion =
false;
1366 }
else if (cc ==
'$') {
1369 bool braces =
false;
1375 while (c.isLetterOrNumber() || cc ==
'_') {
1387 else if (delim ==
'}')
1390 location.fatal(QStringLiteral(
"Missing '}'"));
1392 if (!var.isEmpty()) {
1393 const QByteArray val = qgetenv(var.toLatin1().constData());
1395 expandVars <<
ExpandVar(rhsValues.size(), word.size(),
std::move(var), delim);
1396 needsExpansion =
true;
1397 }
else if (braces) {
1398 text.insert(i, QString::fromLatin1(val));
1402 word += QString::fromLatin1(val);
1406 if (!inQuote && cc ==
'=')
1407 location.fatal(QStringLiteral(
"Unexpected '='"));
1411 for (
const auto &key : keys) {
1412 if (!keySyntax.match(key).hasMatch())
1413 keyLoc.fatal(QStringLiteral(
"Invalid key '%1'").arg(key));
1415 ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars);
1416 if (plus && m_configVars.contains(key)) {
1417 m_configVars[key].append(configVar);
1419 m_configVars.insert(key, configVar);
1424 location.fatal(QStringLiteral(
"Unexpected character '%1' at beginning of line").arg(c));
1435bool Config::isFileExcluded(
const QString &fileName,
const QSet<QString> &excludedFiles)
1437 for (
const QString &entry : excludedFiles) {
1438 if (entry.contains(QLatin1Char(
'*')) || entry.contains(QLatin1Char(
'?'))) {
1439 QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry,
1440 QRegularExpression::UnanchoredWildcardConversion));
1441 if (re.match(fileName).hasMatch())
1445 return excludedFiles.contains(fileName);
1448QStringList
Config::getFilesHere(
const QString &uncleanDir,
const QString &nameFilter,
1449 const Location &location,
const QSet<QString> &excludedDirs,
1450 const QSet<QString> &excludedFiles)
1455 location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath();
1457 if (excludedDirs.contains(dir))
1462 dirInfo.setNameFilters(nameFilter.split(QLatin1Char(
' ')));
1463 dirInfo.setSorting(QDir::Name);
1464 dirInfo.setFilter(QDir::Files);
1465 QStringList fileNames = dirInfo.entryList();
1466 for (
const auto &file : std::as_const(fileNames)) {
1469 if (!file.startsWith(QLatin1Char(
'~'))) {
1470 QString s = dirInfo.filePath(file);
1471 QString c = QDir::cleanPath(s);
1472 if (!isFileExcluded(c, excludedFiles))
1477 dirInfo.setNameFilters(QStringList(QLatin1String(
"*")));
1478 dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1479 fileNames = dirInfo.entryList();
1480 for (
const auto &file : fileNames)
1481 result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs,
1487
1488
1489
1490void Config::pushWorkingDir(
const QString &dir)
1492 m_workingDirs.push(dir);
1493 QDir::setCurrent(dir);
1497
1498
1499
1500
1503 Q_ASSERT(!m_workingDirs.isEmpty());
1504 m_workingDirs.pop();
1505 if (!m_workingDirs.isEmpty())
1506 QDir::setCurrent(m_workingDirs.top());
1510 if (m_excludedPaths)
1511 return *m_excludedPaths;
1516 QSet<QString> excludedDirs = QSet<QString>(excludedDirList.cbegin(), excludedDirList.cend());
1517 QSet<QString> excludedFiles = QSet<QString>(excludedFilesList.cbegin(), excludedFilesList.cend());
1519 m_excludedPaths.emplace(ExcludedPaths{std::move(excludedDirs), std::move(excludedFiles)});
1521 return *m_excludedPaths;
1525
1526
1527
1528
1529
1530
1531
1535 return QSet<QString>(patterns.cbegin(), patterns.cend());
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1553 if (m_internalFilePatterns)
1554 return *m_internalFilePatterns;
1559 for (
const QString &pattern : patterns) {
1560 static const QRegularExpression regexMetaChars(
1561 uR"(\.\*|\.\+|\.\{|\\[\.\*\?]|[\^\$\[\]{}()|+])"_s);
1562 bool isRawRegex = regexMetaChars.match(pattern).hasMatch();
1565 QRegularExpression re(pattern);
1566 if (!re.isValid()) {
1567 qWarning() <<
"Invalid regex pattern in internalfilepatterns:" << pattern
1568 <<
"-" << re.errorString();
1572 compiled.regexPatterns.append(re);
1573 }
else if (pattern.contains(u'*') || pattern.contains(u'?')) {
1574 QString regexPattern = QRegularExpression::wildcardToRegularExpression(pattern);
1575 QRegularExpression re(regexPattern);
1577 compiled.globPatterns.append(re);
1579 compiled.exactMatches.insert(pattern);
1583 m_internalFilePatterns.emplace(std::move(compiled));
1584 return *m_internalFilePatterns;
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602bool Config::matchesInternalFilePattern(
const QString &filePath,
1605 if (patterns.exactMatches.isEmpty() && patterns.globPatterns.isEmpty()
1606 && patterns.regexPatterns.isEmpty())
1609 QString norm = filePath;
1610 norm.replace(QChar(
'\\'), QChar(
'/'));
1612 if (patterns.exactMatches.contains(norm))
1615 const QString fileName = QFileInfo(norm).fileName();
1616 for (
const QRegularExpression &re : patterns.globPatterns) {
1617 if (re.match(fileName).hasMatch())
1621 for (
const QRegularExpression &re : patterns.regexPatterns) {
1622 if (re.match(norm).hasMatch())
1630
1631
1632
1636 return *m_sourceLink;
1640 const auto baseUrl = m_configVars.value(srcUrl).asString();
1641 const auto rootPath = m_configVars.value(srcUrl + dot +
CONFIG_ROOTDIR).asString();
1642 const auto linkText = m_configVars.value(srcUrl + dot +
"linktext").asString();
1643 const auto enabled = m_configVars.value(srcUrl + dot +
"enabled").asBool();
1645 m_sourceLink.emplace(SourceLink{baseUrl, rootPath, linkText, enabled});
1646 return *m_sourceLink;
1650 static QStringList accepted_header_file_extensions{
1651 "ch",
"h",
"h++",
"hh",
"hpp",
"hxx"
1656 QStringList headerList =
1659 std::set<HeaderFilePath> headers{};
1661 for (
const auto& header : headerList) {
1662 if (header.contains(
"doc/snippets"))
continue;
1664 if (!accepted_header_file_extensions.contains(QFileInfo{header}.suffix()))
1667 headers.insert(HeaderFilePath{QFileInfo{header}.canonicalPath(), QFileInfo{header}.fileName()});
1680 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 TEMPLATEPACKAGE
\variable ConfigStrings::TEMPLATEPACKAGE
static QString MODULEHEADER
static QString CPPCLASSESPAGE
static QString PRODUCTNAME
static QString BUILDVERSION
static QString DOCBOOKEXTENSIONS
static QString VERSIONSYM
static QString IMAGEEXTENSIONS
static QString PUBLICATIONLAYOUT
\variable ConfigStrings::PUBLICATIONLAYOUT
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 PIPELINE
\variable ConfigStrings::PIPELINE
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