49struct DLHTMLFileFilter : files::FFilter {
52 DLHTMLFileFilter(
String &ext) : extension(ext) {}
55 return file.Name().EndsWith<CHK, lang::Case::Ignore>(extension);
59struct DLSrcFileFilter : files::FFilter {
60 DoxygenINIFile &doxyfile;
62 DLSrcFileFilter(DoxygenINIFile &df) : doxyfile(df) {}
65 String64 extension(file.Name().Substring(file.Name().LastIndexOf(
'.')));
66 if (doxyfile.FilePatterns.IndexOf(extension) < 0)
76 if (lhs.CountChildren() == 0 && rhs.CountChildren() != 0)
return false;
77 if (lhs.CountChildren() != 0 && rhs.CountChildren() == 0)
return true;
80 return lhs->MDate() > rhs->MDate();
84String htmlConversionCodes[] = {
96constexpr String htmlConversionChars =
"<>&'[]@$ \"";
107 bool replacementFound=
false;
116 for (; codeIdx<
integer(
sizeof(htmlConversionCodes)/
sizeof(
String)) -1; ++codeIdx) {
117 if ( actBuf.
StartsWith(htmlConversionCodes[codeIdx]) ) {
118 replacement.
_(htmlConversionChars.CharAt(codeIdx));
119 idx+= htmlConversionCodes[codeIdx].
Length();
120 replacementFound=
true;
124 if ( codeIdx ==
sizeof(htmlConversionCodes)/
sizeof(
String) )
128 if (replacementFound)
129 buffer.
Reset(replacement);
136 bool replacementFound=
false;
137 for (
auto c : buffer ) {
138 integer idx= htmlConversionChars.IndexOf(c);
142 replacement.
_(
'&').
_<
NC>(htmlConversionCodes[idx]);
143 replacementFound=
true;
146 if (replacementFound)
147 buffer.
Reset(replacement);
166 if (!
TPool.IsIdle()) {
167 Lox_Warning(
"Destructing DoxygenXLinks while not idle.")
170 Lox_Error(
"DoxygenXLinks not idle after 5s. destructing nevertheless now.")
180 const String& sourceHint ) {
184 for (
auto range= index->entityMap.EqualRange(anchorName)
185 ; range.first!=range.second
188 if (
auto* docAnchor=
static_cast<TGTDocAnchor*
>(index->ImportCursor(range.first->second).Value());
190 docAnchor->Title=
String(index->ma, anchorTitle);
191 Lox_Info(
"XTRA",
"Added title to anchor {!Q} of tag-file {!Q}\n"
192 " Anchor source: {}\n"
193 " Anchor title: {!Q}"
194 , anchorName, index->FileName, sourceHint, anchorTitle )
199 Lox_Info(
"XTRA",
"Title for anchor {!Q} hinted, but anchor not found in tag-files\n"
200 " Anchor source: {}\n"
201 " Anchor title: {!Q}"
202 , anchorName, sourceHint, anchorTitle )
211 Lox_Info(
"Scanning Doxygen's output folder and launching read jobs on HTML input files.\n"
212 " Maximum depth {}, File extension {!Q}, Doxygen output directory {!Q}"
218 ScanParameters::SymbolicLinks::RECURSIVE,
225 if ( scanResult == FInfo::ScanStates::NOT_EXISTENT
226 || resultPaths.empty()
227 || resultPaths.front().IsInvalid() ) {
236 Lox_Info(
"HTML file tree scanned.") {
239 if (cntLoggers > 0) {
247 rlogger->GetFormatMultiLine().Mode=3;)
250 Lox_Prune(rlogger->GetFormatMultiLine().Mode=2;)
257 Lox_Info(
"Scheduling HTMLReplacer jobs")
265 String32 omitSourceHTMLs(
"_source");
266 omitSourceHTMLs <<
Doxyfile.HtmlFileExtension;
269 if ( !treeIt.
Node()->IsDirectory()
270 && !treeIt.
Node().Name().EndsWith(omitSourceHTMLs) ) {
272 if (verbosity >= Verbosity::Info)
273 Lox_Info(
"Scheduling XLink replacement on HTML-file {!Q}",
TPool, treeIt.
Node().Name())
275 Stats.HTMLFiles.fetch_add(1);
281 auto qtyFiles =
Stats.HTMLFiles.load();
297 Lox_Info(
"Scanning Doxygen's input folders (sources).\n"
298 " Maximum depth {}, File extensions {!Q}"
308 for (
auto it:
Doxyfile.InputPaths) {
316 ScanParameters::SymbolicLinks::RECURSIVE,
324 Lox_Info(
"Source file tree scanned.") {
327 if (cntLoggers > 0) {
335 rlogger->GetFormatMultiLine().Mode=3;)
338 Lox_Prune(rlogger->GetFormatMultiLine().Mode=2;)
345 Lox_Info(
"Scheduling source scanner jobs")
356 if ( !treeIt.
Node()->IsDirectory() ) {
358 if (verbosity >= Verbosity::Info)
359 Lox_Info(
"Scheduling XLink search on source-file {!Q}", treeIt.
Node().Name())
361 Stats.SourceFiles.fetch_add(1);
367 auto qtyFiles =
Stats.SourceFiles.load();
383 Path scanPath(folder);
389 Lox_Info(
"Scanning source copies in directory {}", folder )
392 ScanParameters::SymbolicLinks::RECURSIVE,
400 Lox_Info(
"Source copies file tree scanned.") {
403 if (cntLoggers > 0) {
411 rlogger->GetFormatMultiLine().Mode=3;)
414 Lox_Prune(rlogger->GetFormatMultiLine().Mode=2;)
421 Lox_Info(
"Scheduling source replacer jobs")
432 if ( !treeIt.
Node()->IsDirectory() ) {
434 if (verbosity >= Verbosity::Info) {
436 Lox_Info(
"Scheduling XLink-replacement on source-copy {!Q}", p)
439 Stats.ReplSourceFiles.fetch_add(1);
445 auto qtyFiles =
Stats.ReplSourceFiles.load();
449 FormatString(), folder);
463 auto* rlogger =
app.GetRLogger();
474 Lox_Info(
"Number of hardware-threads (machine spec): ", std::thread::hardware_concurrency())
477 ->Actual(AutoSizes::Types::Tabstop, 25, 0);
478 app.printConfigFileInfo(*
app.cOut);
483 Path currentDir(SystemFolders::Current);
490 app.cOut->Add(
"Doxyfile: {!ATab}:1",
app.DoxyfilePath);
505 TPool.Strategy.Mode = ThreadPool::ResizeStrategy::Modes::Fixed;
506 TPool.Strategy.WorkersMax=10;
507 TPool.Strategy.WorkersMax= 1;
512 fTreeHTML .DbgCriticalSections(lang::Switch::Off);
517 app.stopWatch.Sample();
525 fTreeHTML .DbgCriticalSections(lang::Switch::On);
527 for (
auto tfInfoIt=
Doxyfile.TagFiles.begin() ; tfInfoIt !=
Doxyfile.TagFiles.end() ; ++tfInfoIt) {
528 Lox_Info(
"Creating index by loading Doxygen tagfile {!Q}. Target URL: {!Q}",
529 tfInfoIt->TagFilePath, tfInfoIt->BaseURL)
533 auto tfInfoNext= tfInfoIt;
535 isLast= tfInfoNext ==
Doxyfile.TagFiles.end();
539 index =
MA().New<
Index>( tfInfoIt->TagFilePath,
552 Stats.TimeIndexAndSourceLoading=
app.stopWatch.Sample();
558 Stats.TimeHTMLReplacements=
app.stopWatch.Sample();
564 index->DbgCriticalSectionCheck(alib::lang::Switch::Off);
592 (void) restoreSources.
Define();
599 xlinkIt.second->SourceLocations.clear();
604 index->DbgCriticalSectionCheck(alib::lang::Switch::On);
608 Stats.TimeSourceReplacements=
app.stopWatch.Sample();
613 index->DbgCriticalSectionCheck(alib::lang::Switch::Off);
621 #if !defined ENABLE_LIST_OPTION
624 (void) listExpression.
Define();
626 if (listFormat.
Define()) {
627 listFormat.
GetString().
Reset(
"#{LinkString@!Q} -> \\ref {path} {Display@!Q}");
650 auto it =
XLinkMap.Find(searchString);
654 Lox_Verbose(
"New Xlink registered with #\"{}\"", searchString)
655 Stats.UniqueXLinks.fetch_add(1);
668 XLink *xLink =
nullptr;
671 auto it =
XLinkMap.Find(searchString);
675 Lox_Info(
"XLink requested that was not registered, yet: #\"{}\"", searchString)
676 Stats.UniqueXLinks.fetch_add(1);
695 if( !htmlFile.
AsCursor().IsValid() ) {
704 if (!linkAndIsNew.second)
705 return linkAndIsNew.first;
706 xLink= linkAndIsNew.first;
711 Stats.XLinksWithErrors.fetch_add(1);
712 Lox_Info(
"Error {} parsing the XLink {!Q}: {}", xLink->
Error, searchString)
722 if( !htmlFile.
AsCursor().IsValid() ) {
729 xLink= linkAndIsNew.first;
731 Stats.XLinksWithErrors.fetch_add(1);
732 Lox_Info(
"Error {} parsing the XLink {!Q}: {}", xLink->
Error, searchString)
747 index->Search(*xLink);
749 Indices.back()->Search(*xLink);
756 if ( xLink->
Targets.size() > 1 ) {
762 bool hasIndirectMemberTargets=
false;
763 bool hasTypedefTargets =
false;
764 for (
auto& result : xLink->
Targets ) {
765 hasIndirectMemberTargets |= result.IsIndirectByInheritance
766 | result.IsIndirectByTypeDef;
769 if (hasTypedefTargets && !hasIndirectMemberTargets)
770 std::erase_if(xLink->
Targets, [&](
const auto& result) {
771 return !result.Node.IsA(Target::Typedef);
777 bool hasDirectMemberTargets =
false;
778 bool hasIndirectMemberTargets=
false;
779 for (
auto& result : xLink->
Targets )
780 if ( result.IsIndirectByInheritance | result.IsIndirectByTypeDef )
781 hasIndirectMemberTargets=
true;
783 hasDirectMemberTargets=
true;
785 if ( hasDirectMemberTargets && hasIndirectMemberTargets )
786 std::erase_if(xLink->
Targets, [&](
const auto& result) {
787 return result.IsIndirectByInheritance | result.IsIndirectByTypeDef;
794 bool hasNonSpecialized =
false;
795 bool hasSpecializations =
false;
796 for (
auto& result : xLink->
Targets )
797 if (
auto* rec= result.Cast<
TGTRecord>(); rec) {
798 if (rec->SpecializationArgs)
799 hasSpecializations=
true;
801 hasNonSpecialized=
true;
804 if ( hasNonSpecialized && hasSpecializations )
805 std::erase_if(xLink->
Targets, [&](
const auto& result) {
806 auto* rec= result.template Cast<TGTRecord>();
807 return rec && rec->SpecializationArgs;
813 for (
auto& result : xLink->
Targets )
816 std::erase_if(xLink->
Targets, [&](
const auto& toDelete) {
817 auto* f= toDelete.template Cast<TGTFunction>();
818 return f && f->Qualifiers.IndexOf(
"const") >= 0;
845 else if (xLink->
Targets.empty()) {
846 Stats.UnresolvedXLinks.fetch_add(1);
847 Lox_Info(
"Search for {!Q} gave no result", searchString)
853 Stats.AmbiguousXLinks.fetch_add(1);
854 Lox_Info(
"Search for {!Q} gave {} results", searchString, xLink->
Targets.size())
857bool WARNINGS_IGNORE_INDIRECTS=
false;
860 Stats.XLinksWithWarnings.fetch_add(1);
861 Lox_Info(
"XLink {!Q} has warnings", searchString)
874 int lineNo,
int colNo ) {
883 Substring fName= targetFilename.
IsEmpty() ? elLocation.Name() : targetFilename;
914 if (targetFilename.
IsEmpty()) {
918 auto it=
Indices.back()->fileMap.Find(elLocation.Name());
919 if ( it ==
Indices.back()->fileMap.end() ) {
920 if (!isELREFAnchor)
Stats.ELReplacementsUnresolved .fetch_add(1);
921 else Stats.ELREFReplacementsUnresolved.fetch_add(1);
922 Lox_Warning(
"ELDECO",
"File {!Q} not found in main index.", elLocation.Name())
928 Lox_Info(
"ELDECO",
"Found file {!Q} in main index.", elLocation.Name())
929 node=
Indices.back()->ImportCursor(it->second);
934 auto it=
Indices.back()->anchorMap.Find({elLocation.Name(), targetAnchor});
935 if ( it ==
Indices.back()->anchorMap.end() ) {
937 Lox_Warning(
"ELDECO",
"EL-Anchor of HTML file main index. Target: {}/{}#{} "
938 "HTML-Location: {0}/{}:{}:{}",
939 Indices.back()->BaseURL, elLocation.Name(), targetAnchor,
940 elLocation.Name(), lineNo, colNo )
941 if (!isELREFAnchor)
Stats.ELReplacementsUnresolved .fetch_add(1);
942 else Stats.ELREFReplacementsUnresolved.fetch_add(1);
946 node=
Indices.back()->ImportCursor(it->second);
952 size_t indexIdx= size_t(-1);
953 for (
size_t idx= 0 ; idx <
Indices.size() - (isELREFAnchor? 1 : 0) ; ++idx) {
955 if ( targetFilename.
StartsWith(index->BaseURL) ) {
957 targetFilename= targetFilename.
Substring(index->BaseURL.Length());
959 targetFilename= targetFilename.
Substring(1);
965 if ( targetAnchor.
IsEmpty() ) {
967 for (
size_t idx= 0 ; idx <
Indices.size() - (isELREFAnchor? 1 : 0) ; ++idx) {
968 if (indexIdx !=
size_t(-1) && idx != indexIdx)
972 auto it= index->fileMap.Find(targetFilename);
973 if ( it != index->fileMap.end() ) {
974 node= index->ImportCursor(it->second);
980 Lox_Warning(
"ELDECO",
"File {!Q} not found in any index.", targetFilename)
981 if (!isELREFAnchor)
Stats.ELReplacementsUnresolved .fetch_add(1);
982 else Stats.ELREFReplacementsUnresolved.fetch_add(1);
987 Lox_Info(
"ELDECO",
"Found file {!Q} in index {}:{}.", targetFilename,
993 for (
size_t idx= 0 ; idx <
Indices.size() ; ++idx) {
994 if (indexIdx !=
size_t(-1) && idx != indexIdx)
998 auto it= index->anchorMap.Find({targetFilename, targetAnchor});
999 if ( it != index->anchorMap.end() ) {
1000 node= index->ImportCursor(it->second);
1008 "EL-Anchor of HTML file not found in any index. Target: {} # {} "
1009 "HTML-Location: {}/{}:{}:{}",
1010 targetFilename, targetAnchor,
1011 Indices.back()->BaseURL, elLocation.Name(), lineNo, colNo )
1012 if (!isELREFAnchor)
Stats.ELReplacementsUnresolved .fetch_add(1);
1013 else Stats.ELREFReplacementsUnresolved.fetch_add(1);
1019 Lox_Info(
"ELDECO",
"Found file/anchor {}/{}#{} in index. HTML-Location {0}/{}:{}.",
1021 elLocation.Name(), lineNo, colNo)
1026 styles.
Set( node,
false,
false );
1033 Lox_Info(
"Writing non-resolved or ambiguous XLinks. (The main output)")
1039 xLinkIt.second->WasPrinted=
false;
1044 RecentlyModifiedFirst sorter;
1049 int cntLocations = 0;
1057 Lox_Verbose(
"No unresolved XLinks found with file {}:1", treeIt.
Path())
1063 Lox_Info(
"Found {} (unique) XLinks with file {}:1",
1064 linksInSrc.size(), treeIt.
Path())
1066 bool SUPPRESS_WARNINGS=
false;
1069 for (
auto &linkInSrc: linksInSrc) {
1070 if ( !linkInSrc.XL->IsParsed() ) {
1071 Lox_Info(
"Found {} XLink #{!Q} in sources which was not evaluated yet, "
1072 "hence not found in HTML files." , linkInSrc.XL->LinkString)
1073 linkInSrc.XL->NotFoundInHTML=
true;
1076 if (linkInSrc.XL->NotFoundInHTML)
1080 XLink* xlOrCopy= linkInSrc.XL;
1088 if ( xlOrCopy->
IsGood( SUPPRESS_WARNINGS ) ) {
1089 while ((xlOrCopy= xlOrCopy->
NextLocal) !=
nullptr )
1095 Lox_Info(
"{} XLink {!ATab!Q} @ {}:{}:{}",
1096 xlOrCopy->
Targets.size() > 1 ?
"Ambiguous"
1097 : xlOrCopy->
Targets.size() == 0 ?
"Unresolved"
1100 xlOrCopy->
LinkString, treeIt.
Path(), linkInSrc.Line, linkInSrc.Column)
1106 app.cErr->PushIndent(2);
1118 for (
auto &srcLoc: linkInSrc.XL->SourceLocations)
1119 if (innerTrIt.
Node() == srcLoc.File.AsCursor()) {
1122 Lox_Info(
" @ {}:{}:{}", locationPath, srcLoc.Line, srcLoc.Column)
1123 app.cErr->Add(
"@ {}:{}:{}", locationPath, srcLoc.Line, srcLoc.Column);
1131 app.cErr->Add(
"This local XLink's HTML file: {}",
1136 app.cErr->PopIndent();
1138 while ((xlOrCopy= xlOrCopy->
NextLocal) !=
nullptr )
1150 auto cntErrs=
Stats.UnresolvedXLinks.load()
1151 +
Stats.AmbiguousXLinks.load()
1152 +
Stats.XLinksWithErrors;
1154 app.cErr->Add(
"Error summary: {} erroneous XLinks @ {} locations.", cntErrs, cntLocations
1158 if (
Stats.XLinksWithWarnings.load() > 0) {
1159 app.cErr->Add(
"Warning summary: {} XLinks with warnings."
1160 ,
Stats.XLinksWithWarnings.load() +
Stats.AmbiguousXLinks.load()
1167 if ( expressionString.
IsEmpty())
1172 app.stopWatch.Sample();
1180 app.cErr->Add(
"{}-Expressions need to evaluate to boolean or integer values.\n"
1181 " Given expression string: {!Q}\n"
1182 " Normalized expression string: {!Q}\n"
1192 Lox_Info(
"Expression sucessfully compiled:\n"
1193 " Given expression string: {!Q}\n"
1194 " Normalized expression string: {!Q}\n"
1202 app.cOut->Add(
"Attention: The given expression is constant:\n"
1203 " Given expression string: {!Q}\n"
1204 " Normalized expression string: {!Q}\n"
1205 " Optimized expression string: {!Q}"
1206 ,
app.GetName(), expressionString
1211 xLink.second->WasPrinted =
false;
1216 RecentlyModifiedFirst sorter;
1222 int cntLocations = 0;
1240 for (
auto &linkInSrc: linksInSrc) {
1242 if (linkInSrc.XL->WasPrinted)
1244 linkInSrc.XL->WasPrinted =
true;
1247 if ( !expr.
Includes(linkInSrc.XL) )
1255 dxlScope.
Xlink = linkInSrc.XL;
1258 exprFormatter.
Format(
app.cOut->Buffer, dxlScope ); }
1260 app.cOut->PushIndent(2);
1261 app.cOut->Add(
"@ {}:{}:{}",
1262 path, linkInSrc.Line, linkInSrc.Column);
1265 for (
auto &srcInLink: linkInSrc.XL->SourceLocations) {
1268 if ( srcInLink.File.AsCursor() == treeIt.
Node()
1269 && srcInLink.Line == linkInSrc.Line
1270 && srcInLink.Column == linkInSrc.Column)
1273 srcInLink.File.AssembleSymbolicPath(furtherPath, lang::Inclusion::Include);
1274 app.cOut->Add(
"@ {}:{}:{}", furtherPath, srcInLink.Line, srcInLink.Column);
1276 app.cOut->PopIndent();
1285 app.cOut->Add(
"List summery: Found {} XLinks @ {} locations that match expression {}.\n"
1286 "Query generation time: {}"
1291 ,
app.stopWatch.Sample()
1297 app.cErr->Add(
"Error parsing expression {!Q}:", expressionString);
1300 e.
Format(exceptionMsg); }
1302 app.cErr->Add(exceptionMsg);
1310 int cntSrcOnlyLinks= 0;
1312 if ( it.second->HTMLLocations.empty()
1313 || (it.second->IsLocal && !it.second->HTMLFileOfLocalLink.IsValid()) )
1316 if ( cntSrcOnlyLinks == 0)
1320 app.cErr->Add(
"Found {} unique XLinks in sources, which are not in HTML files.\n"
1321 " Note: This usually happens if the DoxygenXLinks was run twice. In other\n"
1322 " words, when doxygen was not run before running the DoxygenXLinks.\n"
1323 " Another option is that XLinks appeared in code that was not\n"
1324 " used by doxygen to write output. For example, due to preprocessor \n"
1325 " switches or because the XLink was (accidentially) located in a standard\n"
1328 " Printing the first 5:\n",
1331 app.cErr->PushIndent(2);
1333 if ( !it.second->HTMLLocations.empty()
1334 && !(it.second->IsLocal && !it.second->HTMLFileOfLocalLink.IsValid()) )
1338 app.cErr->Add(
"XLink #{!Q}", it.first );
1339 app.cErr->PushIndent(2);
1340 for (
auto& loc : it.second->SourceLocations ) {
1343 loc.File.AssembleSymbolicPath(path, lang::Inclusion::Include); }
1344 app.cErr->Add(
"@ {}:{}:{}", path, loc.Line, loc.Column );
1346 app.cErr->PopIndent();
1348 app.cErr->PopIndent();
1354 int cntHTMLOnlyLinks= 0;
1356 if ( it.second->SourceLocations.empty() )
1359 if ( cntHTMLOnlyLinks == 0)
1363 app.cErr->Add(
"Found {} unique XLinks in HTML files, which were not found in the sources.\n"
1364 " Note: This should not happen. It might indicate that {} does not read\n"
1365 " the sources rightfully. Maybe it misinterprets the doxygen INI-file.\n"
1366 " It is not allowed to create XLinks using Doxygen macros. Use the \\\\ref syntax there!\n"
1367 " In case you cannot find the reason, please report it as a bug.\n"
1368 " (If so, please include a short sample. Thank you!)\n"
1370 "Printing the first 5:\n"
1371 ,cntHTMLOnlyLinks,
app.GetName() );
1374 app.cErr->PushIndent(2);
1376 if ( !it.second->SourceLocations.empty() )
1380 app.cErr->Add(
"XLink #{!Q}" ,it.first );
1381 app.cErr->PushIndent(2);
1382 for (
auto& loc : it.second->HTMLLocations ) {
1385 loc.File.AssembleSymbolicPath(path, lang::Inclusion::Include); }
1386 app.cErr->Add(
"@ {}:{}:{}", path ,loc.Line ,loc.Column );
1388 app.cErr->PopIndent();
1390 app.cErr->PopIndent();
1398 int srcLocationsGood = 0;
1399 int htmlLocationsGood = 0;
1400 int srcLocationsWithErrors = 0;
1401 int htmlLocationsWithErrors = 0;
1402 int srcLocationsUnresolved = 0;
1403 int htmlLocationsUnresolved = 0;
1404 int srcLocationsAmbiguous = 0;
1405 int htmlLocationsAmbiguous = 0;
1406 int srcLocationsWithWarnings = 0;
1407 int htmlLocationsWithWarnings= 0;
1410 XLink& xLink= *it.second;
1411 Lox_Info(
"Dump",
"XLink found: {} {!ATab}", it.first, it.second->IsResolved())
1425 if( getStatistics.
Define() )
1426 getStatistics=
false;
1429 app.stopWatch.Sample();
1431 if (!getStatistics.
GetBool()) {
1432 app.cOut->Add(
"{} finished: {!ATab:,} XLinks replaced in {:,} html files. "
1433 "Identified {:,} locations in {:,} source files.\n"
1434 "Execution time: {}"
1437 ,
Stats.HTMLFiles.load()
1440 ,
Stats.SourceFiles.load()
1442 ,
app.stopWatch.GetCumulated()
1450 for (
int i= 1; i <
ARG_C; ++i )
1451 parameters <<
ARG_VN[i] <<
' ';
1452 app.cOut->AddMarked(
"\nStatistics of command: {} {}\n@HL= ",
app.GetName(), parameters );
1456 app.cOut->Add(
"Tag-files:\n============");
1457 app.cOut->PushIndent(2);
1458 unsigned ctdTagFiles= 0;
1461 app.cOut->Add(
"No {}: {:,6} lines read, file {!Q}, URL: {}, load time {}",
1463 index->StatCtdLines, index->FilePath, index->BaseURL, index->LoadTime);
1464 maxTagFileNameLen= std::max(maxTagFileNameLen, index->FileName.Length());
1467 std::vector<int> kindSums;
1468 kindSums.reserve(ctdTagFiles);
1471 auto& fmt=
app.cOut->Formatter;
1472 auto& buf=
app.cOut->Buffer;
1476 for (
unsigned i= 0; i< ctdTagFiles ; ++i)
1477 fmt->Format(buf,
String64(
"|{:>")._(maxTagFileNameLen)._(
"} "),
Indices.at(i)->FileName);
1479 buf <<
" ----------------";
1480 for (
unsigned tf= 0; tf< ctdTagFiles ; ++tf) {
1481 fmt->Format(buf,
"|-{!FillC-}", maxTagFileNameLen);
1482 kindSums.push_back(0);
1491 fmt->Format(buf,
" {:14} ", kind);
1492 for (
unsigned tf= 0; tf< ctdTagFiles ; ++tf) {
1493 fmt->Format(buf,
String64(
"|{:,")._(maxTagFileNameLen)._(
"} ")
1494 ,
Indices[tf]->KindStats.GetByIdx(kindIdx) );
1495 kindSums[tf]+=
Indices[tf]->KindStats.GetByIdx(kindIdx);
1500 buf <<
" ----------------";
1501 for (
unsigned tf= 0; tf< ctdTagFiles ; ++tf)
1502 fmt->Format(buf,
"|-{!FillC-}", maxTagFileNameLen);
1505 for (
unsigned i= 0; i< ctdTagFiles ; ++i)
1506 fmt->Format(buf,
String64(
"|{:,")._(maxTagFileNameLen)._(
"} "), kindSums[i]);
1509 app.cOut->PopIndent();
1513 app.cOut->Add(
"XLinks:\n============");
1514 app.cOut->PushIndent(2);
1515 app.cOut->Add(
" | Sources | HTML | Unique/Total \n"
1516 "---------------|----------|----------|--------------" );
1517 app.cOut->Add(
"XLinks |{:9,} |{:9,} |{:9,}\n"
1518 , srcLocationsGood + srcLocationsUnresolved + srcLocationsAmbiguous
1519 + srcLocationsWithErrors + srcLocationsWithWarnings
1520 , htmlLocationsGood + htmlLocationsUnresolved + htmlLocationsAmbiguous
1521 + htmlLocationsWithErrors + htmlLocationsWithWarnings
1522 ,
Stats.UniqueXLinks.load() );
1524 app.cOut->Add(
" Unresolved |{:9,} |{:9,} |{:9,}\n" , srcLocationsUnresolved,
1525 htmlLocationsUnresolved,
Stats.UnresolvedXLinks.load() );
1527 app.cOut->Add(
" Ambiguous |{:9,} |{:9,} |{:9,}\n" , srcLocationsAmbiguous,
1528 htmlLocationsAmbiguous,
Stats.AmbiguousXLinks.load() );
1530 app.cOut->Add(
" Erroneous |{:9,} |{:9,} |{:9,}\n", srcLocationsWithErrors,
1531 htmlLocationsWithErrors,
Stats.XLinksWithErrors.load() );
1533 app.cOut->Add(
" Warnings |{:9,} |{:9,} |{:9,}\n", srcLocationsWithWarnings,
1534 htmlLocationsWithWarnings,
Stats.XLinksWithWarnings.load() );
1536 app.cOut->Add(
"EL-Anchors | -/- |{:9,} |{0:9,}\n",
Stats.ELReplacements.load() );
1537 app.cOut->Add(
" Unresolved | -/- |{:9,} |{0:9,}\n",
Stats.ELReplacementsUnresolved.load());
1538 app.cOut->Add(
"ELREF-Anchors | -/- |{:9,} |{0:9,}\n",
Stats.ELREFReplacements.load() );
1539 app.cOut->Add(
" Unresolved | -/- |{:9,} |{0:9,}\n",
Stats.ELREFReplacementsUnresolved.load());
1540 app.cOut->Add(
"---------------|----------|----------|--------------\n");
1541 app.cOut->Add(
" Files |{:9,} |{:9,} |{:9,}\n",
Stats.SourceFiles.load(),
1542 Stats.HTMLFiles.load(),
Stats.SourceFiles.load() +
Stats.HTMLFiles.load() );
1543 app.cOut->Add(
" Lines |{:9,} |{:9,} |{:9,}\n",
Stats.SourceFileLines.load()
1544 ,
Stats.HTMLFileLines.load(),
Stats.SourceFileLines.load() +
Stats.HTMLFileLines.load() );
1545 app.cOut->Add(
" Size |{:>9} |{:>9} |{:>9}\n"
1550 app.cOut->Add(
" Time |{:>9} |{:>9} |{:>9}\n",
Stats.TimeIndexAndSourceLoading
1551 ,
Stats.TimeHTMLReplacements,
Stats.TimeIndexAndSourceLoading +
Stats.TimeHTMLReplacements );
1553 app.cOut->PopIndent();
1557 app.cOut->Add(
"Total Time: {}",
app.stopWatch.GetCumulated());
1563 "XLink must be of kind 'File' to be resolved from HTML file")
1565 "This method must only be called if on unresolved links")
1574 for(
auto c : name )
switch(c) {
1575 case '_': dxNameNormal <<
"__";
break;
1576 case '-': dxNameNormal <<
"_0";
break;
1577 case '.': dxNameNormal <<
"_8";
break;
1578 case ':': dxNameNormal <<
"_1";
break;
1579 case '/': dxNameNormal <<
"_2";
break;
1580 case '<': dxNameNormal <<
"_3";
break;
1581 case '>': dxNameNormal <<
"_4";
break;
1582 case '*': dxNameNormal <<
"_5";
break;
1583 case '&': dxNameNormal <<
"_6";
break;
1584 case '|': dxNameNormal <<
"_7";
break;
1585 case '!': dxNameNormal <<
"_9";
break;
1586 case ',': dxNameNormal <<
"_a";
break;
1587 default: dxNameNormal << c;
break;
1590 dxNameSource << dxNameNormal <<
"_source";
1591 dxNameNormal <<
Doxyfile.HtmlFileExtension;
1592 dxNameSource <<
Doxyfile.HtmlFileExtension;
1603 foundNormal= treeIt.
Node();
1605 foundSource= treeIt.
Node();
1610 if ( foundNormal.
AsCursor().IsInvalid() && foundSource.
AsCursor().IsInvalid() )
1620 for (
int i= 0; i < xLink.
ScopeSize(); ++i)
1622 path << xLink.
Name();
1623 if ( foundSource.
AsCursor().IsValid() )
1629 bool created= node.
AsCursor().GoToCreatedPathIfNotExistent(path, &filePathComponentTag) != 0;
1632 (foundNormal.
AsCursor().IsValid() ? foundNormal
1633 : foundSource).Name()
1639 xLink.
Targets.push_back({ node
1643 ,
false,
false,
false,
false, false
#define ALIB_LOCK_SHARED_WITH(lock)
#define ALIB_CALLER_NULLED
#define ALIB_ASSERT(cond, domain)
#define ALIB_LOCK_RECURSIVE_WITH(lock)
#define ALIB_ASSERT_ERROR(cond, domain,...)
#define ALIB_LOCK_WITH(lock)
#define Lox_Exception(...)
#define Lox_SetVerbosity(...)
#define Lox_SetDomain(...)
#define Lox_GetVerbosity(result,...)
#define Lox_IsActive(result,...)
void Initialize(CursorType startNode, lang::Inclusion includeStartNode)
void SetSorting(Sorter *sorter)
const TStringTree::NameType Path() const
void SetPathGeneration(lang::Switch pathGeneration)
constexpr CharacterType Separator() const noexcept
TCursor< true > ConstCursor
TCustom & GetCustomData()
bool HasCustomData() const
strings::TAString< system::PathCharType > & AssembleSymbolicPath(strings::TAString< system::PathCharType > &target, lang::Inclusion includeFilename) const
TAString & InsertAt(const TString< TChar > &src, integer pos)
void DbgDisableBufferReplacementWarning()
constexpr integer Length() const
constexpr bool IsEmpty() const
bool EndsWith(const TString &needle) const
TChar CharAt(integer idx) const
constexpr bool IsNotEmpty() const
integer IndexOf(const TString &needle, integer startIdx=0, integer endIdx=strings::MAX_LEN) const
integer LastIndexOf(TChar needle, integer startIndex=MAX_LEN) const
TString< TChar > Substring(integer regionStart, integer regionLength=MAX_LEN) const
bool StartsWith(const TString &needle) const
static int IsAbsolute(const PathString &path)
bool Define(Priority requestedPriority=Priority::Standard)
alib::String GetExpressionString()
bool Includes(XLink *xLink)
alib::String GetOptimizedString()
Statistics Stats
Statistics collected during the execution and printed when verbose output is requested.
alib::FTree & GetHTMLTree()
alib::SharedFTree fTreeSources
The file tree used for reading the source files.
void scanHTMLFiles()
Scans the HTML input file tree.
ExclamationFile Exclamations
void scanReplSrcFiles(const alib::String &folder)
alib::SharedFTree fTreeHTML
The file tree used for reading the html files.
void Run()
The main method of this main class of project DoxygenXLinks.
void listLinks(const alib::String &expressionString, const alib::String &format)
void AddAnchorTitle(const alib::String &anchorName, const alib::String &anchorTitle, const alib::String &sourceHint)
alib::CString ExclamationsPath
The path to this file. Todo: make configurable and auto-generated from app-name.
XLink * GetXLink(alib::String &searchString, const alib::files::File &htmlFile)
alib::SharedLock & GetHTMLTreeLock()
void writeXLinksInHTMLNotInSource()
void scheduleSrcScanners()
Launches the #"SourceLocationFinder" jobs on the #".fTreeSources;source-file tree".
void writeErrors()
Writes the non-resolved and ambiguous src links in an ordered fashion.
void schduleHTMLReplacers()
Launches the #"HTMLReplacer" jobs on the #".fTreeHTML;HTML-file tree".
alib::Verbosity verbosityGetELDecoration
Used to optimize logging speed in critical code section.
alib::StdVectorMA< Index * > Indices
~DoxygenXLinks()
Virtual destructor.
void tryResolveHTMLTargetFile(XLink &xLink)
DoxygenXLinks()
Constructor.
void GetELDecoration(Styles &styles, bool isELREFAnchor, alib::File &elLocation, alib::String targetFilename, alib::String targetAnchor, int lineNo, int colNo)
alib::MonoAllocator MA
Our mono allocator.
alib::HashMap< alib::MonoAllocator, alib::String, XLink *, std::hash< alib::String >, std::equal_to< alib::String >, alib::lang::Caching::Enabled, alib::Recycling::None > XLinkMap
The set of unique XLinks found in the source and HTML files.
DoxygenINIFile Doxyfile
The Doxyfile to process.
DXLThreadPool TPool
The thread pool used to load and search the HMTL files.
alib::SharedLock & GetSourceTreeLock()
XLink * RegisterXLink(alib::String &searchString)
void writeXLinksInSourceNotInHTML()
void schduleSourceReplacers(const alib::String &folder)
alib::system::PathString FilePath
The path to the doxygenTagFile.
alib::MonoAllocator ma
The allocator used for the parent #"StringTree" and for the hashtable in the field map.
const alib::String & BaseURL
The URL of the HTML-output created with this tag-file.
void Load()
Loads the tag-file and creates the index.
static constexpr alib::String SrcFileLine
CSS class name. See user manual chapter #"dxl_styling".
bool isFile
This set when a file is targeted by the XLink.
static constexpr alib::String Dir
CSS class name. See user manual chapter #"dxl_styling".
static constexpr alib::String SrcFile
todo: only set with EL/ELRef today.
static constexpr alib::String FileOrDir
CSS class name. See user manual chapter #"dxl_styling".
bool isDir
This set when a dir is targeted by the XLink.
static constexpr alib::String ELUnknown
CSS class name. See user manual chapter #"dxl_styling".
static constexpr alib::String XLEL
CSS class name. See user manual chapter #"dxl_styling".
void Set(const Index::Node &node, bool hasDisplayText, bool isIndirect)
void Add(const alib::String &style)
Kinds
Enumerates the kinds of compounds found in a the Doxygen tagfile.
@ MAX_KIND
The highest bit defining a kind.
@ Typedef
Denotes a type definition.
@ File
Denotes a source file.
@ FILEPATH_COMPONENT
A node of a file path (not a doxygen kind).
@ RECORD
Mask to identify records types.
alib::String LinkString
The original source string.
alib::Lock Lock
The lock protecting the creation phase and as well allocator access.
alib::String & Name() const
Index::SearchResult & Result()
bool IsGood(bool ignoreIndirects)
void Parse()
Parses the given searchString and allocates the fields in the MA.
alib::StdVectorMA< Location > HTMLLocations
const alib::String & Scope(int n) const
void PrintError(alib::Paragraphs &out, const alib::String &linkString, bool suppressHints=false)
alib::files::FTree::ConstCursorHandle HTMLFileOfLocalLink
The tree node of the HTML file which created this copy of the originally given local XLink.
alib::StdVectorMA< Index::SearchResult > Targets
@ RestoringUnusedLocalLink
@ RestoringAmbiguousLocalLink
static Index::Node ResolveTypeDef(const Index::Node &startCursor, const alib::String &origSearchString)
Index::ConstCursorHandle LocalLinkEntity
alib::StdVectorMA< Location > SourceLocations
Errors Error
Possible errors that occured during parsing the search string given by the user.
Target::Kinds KindSpec
Function arguments provided with the source XLink.
alib::String Qualifiers
Function qualifiers like const, or nothrow provided with the source XLink.
Target::TemplateArguments * SpecializationArgs
bool NoIndirectionWarning
std::pair< XLink *, bool > GetLocalCopy(const alib::files::File &htmlFile)
int Compare(const TChar *lhs, const TChar *rhs, integer cmpLength)
FInfo::ScanStates ScanFiles(FTree &tree, ScanParameters ¶meters, CanonicalPathList *resultPaths=nullptr, Path *remainingStart=nullptr)
AString & DbgDump(AString &target, FTree &tree, EnumBitSet< FInfo::Types > includedTypes=EnumBitSet< FInfo::Types >(true), FTree::Cursor startNode=FTree::Cursor(), unsigned depth=(std::numeric_limits< unsigned int >::max)())
strings::TString< PathCharType > PathString
variables::Variable CampVariable(camp::Camp &camp)
lox::textlogger::TextLogger TextLogger
variables::Variable Variable
LocalString< 64 > String64
constexpr CString NEW_LINE
constexpr const String EMPTY_STRING
LocalString< 4096 > String4K
strings::TString< character > String
app::AppCliCamp APPCLI_CAMP
strings::TSubstring< character > Substring
exceptions::Exception Exception
LocalString< 256 > String256
strings::TAString< character, lang::HeapAllocator > AString
containers::StringTreeIterator< TTree > StringTreeIterator
files::SPFileFilter SPFileFilter
LocalString< 32 > String32
LocalString< 512 > String512
alib::StdVectorMA< ResolvedLocation > XLinkList
void ConvertHTMLEntitiesToAscii(alib::AString &buffer)
void ConvertASCIItoHTMLEntities(alib::AString &buffer)
@ NoSourceCopiesFound
No sources found with the specification given in the Doxyfile.
@ NoSourceFilesFound
No sources found with the specification given in the Doxyfile.
@ NoHTMLFilesFound
HTML files to process not found.
static constexpr unsigned InfiniteRecursion
XLink * Xlink
The link to evaluate.
The cursor type of the #"StringTree".
const alib::String & HTMLFile() const
void ReplaceTarget(class Target *newTarget)
bool IsA(Target::Kinds kind) const
Node Node
The cursor pointing to the result.
bool IsResolvedTypeDef
Set the XLink targets a type-definition and requested to resolve that.
alib::String HTMLAnchor
The HTML anchor hash. Set only with members.
XLink target information for pages.
alib::String Title
The title of the group.
XLink target information for source files.
XLink target information for C++ namespace- and member-functions.
alib::String Qualifiers
Additional qualifiers like const or nothrow.
XLink target information for C++ structs, classes and unions.