Doxygen XLinks
by
V: 2511R0
Website: doxygen
Loading...
Searching...
No Matches
dxl.cpp
1//==================================================================================================
2// This implementation-file is part of DoxygenXLinks - A doxygen post-processor that allows to
3// define smarter <b>Doxygen</b>-links.
4//
5// \emoji :copyright: 2025-2026 A-Worx GmbH, Germany.
6// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#include "dxl.hpp"
9#include "index.hpp"
10#include "jobs.hpp"
11#include "dxlapp.hpp"
12#include "doxyfile.hpp"
13#include "expressions.hpp"
14#include "ALib.ALox.Impl.H"
15#include "ALib.App.CLI.H"
16#include "ALib.Files.H"
17#include "ALib.System.H"
19
20using namespace alib;
21
22namespace dxl {
23// todo: beim matchen später, wenn er nix findet, die filenames durchsuchen, ob es hier
24// einen treffer per substring gibt. Dann als link display den vollen filenamen
25// einsetzen. Dies würde die \implude rauswerfen und man könnte komplett verkürzte
26// filenamen benutzen.
27// todo: Alle stellen suchen wo fixe Werte zur optimierung stehen: Stack size, String length
28// number of arguments, etc. und
29// [ ] mit konstanten ersetzen
30// [ ] Exceptions einbauen: ArgumentOverflow, CompoundNestingOverflow, etc.
31// todo: Das doxygen macro alibcppfile linked direkt in das HTML eines cpp file. Wieso ist das so?
32// Was hab ich da gemacht? Wenn es doch von doxygen als HTML angelegt wird, sollte es doch
33// auch im tag-file auftauchen. Tut es aber (glaube ich) nicht.
34// todo: in der ALib Doku tauchen noch "/home/dev/A-Worx/ALib", z.B. in Snippets, auf. Also muss es hier noch
35// eine Möglichkeit geben in den HTML Datein search & replace zu machen. Als Nebentätigkeit
36// dieses tools.
37// todo: Im Tagfile steht im Typ of "ALIB_DLL". Das müsste eigentlich mit anpassen des Doxyfiles
38// Bzgl. der Macros rauszubekommen sein. Ansonsten auch hier ein Search/Replace anbieten.
39
40#if ALIB_DEBUG
41extern void DbgUnitTests(DoxygenXLinks*);
42#endif
43// #################################################################################################
44// Tools
45// #################################################################################################
47
48namespace {
49struct DLHTMLFileFilter : files::FFilter {
50 String &extension;
51
52 DLHTMLFileFilter(String &ext) : extension(ext) {}
53
54 bool Includes(const File &file, const system::PathString &) override {
55 return file.Name().EndsWith<CHK, lang::Case::Ignore>(extension);
56 }
57};
58
59struct DLSrcFileFilter : files::FFilter {
60 DoxygenINIFile &doxyfile;
61
62 DLSrcFileFilter(DoxygenINIFile &df) : doxyfile(df) {}
63
64 bool Includes(const File &file, const system::PathString &) override {
65 String64 extension(file.Name().Substring(file.Name().LastIndexOf('.')));
66 if (doxyfile.FilePatterns.IndexOf(extension) < 0)
67 return false;
68
69 return true;
70 }
71};
72
73struct RecentlyModifiedFirst : StringTreeIterator<FTree>::Sorter {
74 bool Compare(const FTree::ConstCursor &lhs, const FTree::ConstCursor &rhs) override {
75 // Prefer directories over files.
76 if (lhs.CountChildren() == 0 && rhs.CountChildren() != 0) return false;
77 if (lhs.CountChildren() != 0 && rhs.CountChildren() == 0) return true;
78
79 // Sort by modification date.
80 return lhs->MDate() > rhs->MDate();
81 }
82};
83
84String htmlConversionCodes[] = {
85 "lt;" ,
86 "gt;" ,
87 "amp;" ,
88 "apos;" ,
89 "lsqb;" ,
90 "rsqb;" ,
91 "commat;" ,
92 "dollar;" ,
93 "nbsp;" ,
94 "quot;" // // We keep "&quot;" in when converting html -> ASCII
95};
96constexpr String htmlConversionChars ="<>&'[]@$ \"";
97
98
99}
100
101#include "ALib.Lang.CIMethods.H"
102
103
105 String4K replacement;
106 //replacement.DbgDisableBufferReplacementWarning()
107 bool replacementFound= false;
108 for (integer idx= 0; idx < buffer.Length() ; ++idx ) {
109 nchar c= buffer.CharAt(idx);
110 if ( c != '&' )
111 replacement._(c);
112 else {
113 String actBuf= buffer.Substring(idx+1);
114 integer codeIdx= 0;
115 // loop over code table, except the last one "quot;". That's kept in
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;
121 break;
122 }
123 }
124 if ( codeIdx == sizeof(htmlConversionCodes)/sizeof(String) )
125 replacement._('&');
126 }
127 }
128 if (replacementFound)
129 buffer.Reset(replacement);
130
131}
132
134 String4K replacement;
135 //replacement.DbgDisableBufferReplacementWarning()
136 bool replacementFound= false;
137 for (auto c : buffer ) {
138 integer idx= htmlConversionChars.IndexOf(c);
139 if ( idx < 0 )
140 replacement._(c);
141 else {
142 replacement._('&')._<NC>(htmlConversionCodes[idx]);
143 replacementFound= true;
144 }
145 }
146 if (replacementFound)
147 buffer.Reset(replacement);
148}
149
150// #############################################################################################
151// DoxygenXLinks
152// #################################################################################################
154: fTreeSources(16)
155, fTreeHTML(16)
156, MA(ALIB_DBG("DLMain",) 1024)
157, Doxyfile{MA}
158, XLinkMap{MA}
159, Indices{MA}
160{
161 ALIB_DBG(DLLock.Dbg.Name= "DL::MALock";)
162}
163
164
166 if (!TPool.IsIdle()) {
167 Lox_Warning("Destructing DoxygenXLinks while not idle.")
168 TPool.WaitForAllIdle(5s ALIB_DBG(, 1s));
169 if (!TPool.IsIdle())
170 Lox_Error("DoxygenXLinks not idle after 5s. destructing nevertheless now.")
171 } else
172 Lox_Verbose("{} is idle, shutting it down.", TPool)
173
174 TPool.Shutdown();
175 for (auto* index: Indices)
176 lang::Destruct(*index);
177}
178
179void DoxygenXLinks::AddAnchorTitle( const String& anchorName, const String& anchorTitle,
180 const String& sourceHint ) {
181 // search anchor in indices
182 for (auto* index: Indices)
183 {ALIB_LOCK_SHARED_WITH(index->SLock)
184 for ( auto range= index->entityMap.EqualRange(anchorName)
185 ; range.first!=range.second
186 ; ++range.first) {
187
188 if ( auto* docAnchor= static_cast<TGTDocAnchor*>(index->ImportCursor(range.first->second).Value());
189 docAnchor && docAnchor->Title.IsEmpty() ) {
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 )
195 return;
196 }
197 }
198 }
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 )
203}
204
206 Lox_SetDomain("/DXL/SCAN/HTML", Scope::Method)
207 Lox_Info("Scanning HTML-files...")
208
209 /// Scan parameters used when scanning the HTML-input-files, as well as the source files.
210
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}"
213 , Doxyfile.HtmlSubfolderDepth
214 , Doxyfile.HtmlFileExtension
215 , Doxyfile.HTMLFilePath)
216
217 files::ScanParameters htmlScanParams(Doxyfile.HTMLFilePath,
218 ScanParameters::SymbolicLinks::RECURSIVE,
219 Doxyfile.HtmlSubfolderDepth + 1,
220 true, // crossFileSystems
221 true); // IncludeArtificialFS
222 htmlScanParams.FileFilter = SPFileFilter(new DLHTMLFileFilter(Doxyfile.HtmlFileExtension));
223 files::CanonicalPathList resultPaths;
224 auto scanResult= alib::files::ScanFiles(*fTreeHTML, htmlScanParams, &resultPaths);
225 if ( scanResult == FInfo::ScanStates::NOT_EXISTENT
226 || resultPaths.empty()
227 || resultPaths.front().IsInvalid() ) {
229 app.cErr->Add(app.cli.ExitCodeDecls.Find(ExitCodes::NoHTMLFilesFound).Mapped()->
230 FormatString(),
231 Doxyfile.HtmlFileExtension, Doxyfile.HTMLFilePath);
232 app.machine.SetExitCode(ExitCodes::NoHTMLFilesFound);
233 throw Exception(ALIB_CALLER_NULLED, app::App::Exceptions::ControlledEarlyExit);
234 }
235
236 Lox_Info("HTML file tree scanned.") {
237 int cntLoggers;
238 Lox_IsActive(cntLoggers, Verbosity::Verbose)
239 if (cntLoggers > 0) {
240 String64 buf;
244 // todo: this method is not available in release builds, hence, .
245 } // it has to be done here on our own
246 Lox_Prune(TextLogger* rlogger= app::Get().GetRLogger();
247 rlogger->GetFormatMultiLine().Mode=3;)
248 Lox_Verbose("File tree:")
249 Lox_Verbose(buf)
250 Lox_Prune(rlogger->GetFormatMultiLine().Mode=2;)
251 }
252 }
253}
254
256 Lox_SetDomain("/DXL/SCAN/HTML", Scope::Method)
257 Lox_Info("Scheduling HTMLReplacer jobs")
258 // we want maximum speed and even spare the fast log calls in the loop.
259 Verbosity verbosity;
260 Lox_GetVerbosity(verbosity)
261
264 treeIt.Initialize(fTreeHTML->Root().AsCursor(), lang::Inclusion::Exclude);
265 String32 omitSourceHTMLs("_source");
266 omitSourceHTMLs << Doxyfile.HtmlFileExtension;
267
268 while (treeIt.IsValid()) {
269 if ( !treeIt.Node()->IsDirectory()
270 && !treeIt.Node().Name().EndsWith(omitSourceHTMLs) ) {
271
272 if (verbosity >= Verbosity::Info)
273 Lox_Info("Scheduling XLink replacement on HTML-file {!Q}", TPool, treeIt.Node().Name())
274 TPool.ScheduleVoid<HTMLReplacer>(*this, treeIt.Node());
275 Stats.HTMLFiles.fetch_add(1);
276 }
277
278 treeIt.Next();
279 }
280
281 auto qtyFiles = Stats.HTMLFiles.load();
282 if (qtyFiles == 0) {
284 app.cErr->Add(app.cli.ExitCodeDecls.Find(ExitCodes::NoHTMLFilesFound).Mapped()->
285 FormatString(),
286 Doxyfile.HtmlFileExtension, Doxyfile.HTMLFilePath);
287 app.machine.SetExitCode(ExitCodes::NoHTMLFilesFound);
288 throw Exception(ALIB_CALLER_NULLED, app::App::Exceptions::ControlledEarlyExit);
289 }
290
291
292}
293
295 Lox_SetDomain("/DXL/SCAN/SRC", Scope::Method)
296
297 Lox_Info("Scanning Doxygen's input folders (sources).\n"
298 " Maximum depth {}, File extensions {!Q}"
299 , Doxyfile.RecursiveInputScan ? ScanParameters::InfiniteRecursion : 1
300 , Doxyfile.FilePatterns)
301 for (auto it: Doxyfile.InputPaths) Lox_Info(" Input path {}", it)
302 for (auto it: Doxyfile.ExcludePaths) Lox_Info(" Exclude path {}", it)
303 for (auto it: Doxyfile.ExcludePatterns) Lox_Info(" Exclude pattern {}", it)
304
305 SPFileFilter FileFilter(new DLSrcFileFilter(Doxyfile));
306
307 files::CanonicalPathList resultPaths;
308 for (auto it: Doxyfile.InputPaths) {
309 Path scanPath(it);
310 if(!scanPath.IsAbsolute()) {
311 scanPath.InsertAt("/", 0);
312 scanPath.InsertAt(app::Get<DXLApp>().PWD, 0);
313 }
314
315 files::ScanParameters srcScanParams(scanPath,
316 ScanParameters::SymbolicLinks::RECURSIVE,
317 Doxyfile.RecursiveInputScan ? ScanParameters::InfiniteRecursion : 1,
318 true, // crossFileSystems
319 true); // IncludeArtificialFS
320 srcScanParams.FileFilter = FileFilter;
321 alib::files::ScanFiles(*fTreeSources, srcScanParams, &resultPaths);
322 }
323
324 Lox_Info("Source file tree scanned.") {
325 int cntLoggers;
326 Lox_IsActive(cntLoggers, Verbosity::Verbose)
327 if (cntLoggers > 0) {
328 String64 buf;
332 // todo: this method is not available in release builds, hence, .
333 } // it has to be done here on our own
334 Lox_Prune(TextLogger* rlogger= app::Get().GetRLogger();
335 rlogger->GetFormatMultiLine().Mode=3;)
336 Lox_Verbose("File tree:")
337 Lox_Verbose(buf)
338 Lox_Prune(rlogger->GetFormatMultiLine().Mode=2;)
339 }
340 }
341}
342
344 Lox_SetDomain("/DXL/SCAN/SRC", Scope::Method)
345 Lox_Info("Scheduling source scanner jobs")
346
347 // we want maximum speed and even spare the fast log calls in the loop.
348 Verbosity verbosity;
349 Lox_GetVerbosity(verbosity)
350
353 treeIt.Initialize(fTreeSources->Root().AsCursor(), lang::Inclusion::Exclude);
354
355 while (treeIt.IsValid()) {
356 if ( !treeIt.Node()->IsDirectory() ) {
357
358 if (verbosity >= Verbosity::Info)
359 Lox_Info("Scheduling XLink search on source-file {!Q}", treeIt.Node().Name())
360 TPool.ScheduleVoid<SourceLocationFinder>(*this, treeIt.Node());
361 Stats.SourceFiles.fetch_add(1);
362 }
363
364 treeIt.Next();
365 }
366
367 auto qtyFiles = Stats.SourceFiles.load();
368 if (qtyFiles == 0) {
370 app.cErr->Add(app.cli.ExitCodeDecls.Find(ExitCodes::NoSourceFilesFound).Mapped()->
371 FormatString());
372 app.machine.SetExitCode(ExitCodes::NoSourceFilesFound);
373 throw Exception(ALIB_CALLER_NULLED, app::App::Exceptions::ControlledEarlyExit);
374 }
375}
376
377
379 Lox_SetDomain("/DXL/SCAN/SRCREPL", Scope::Method)
380 {ALIB_LOCK_WITH(GetSourceTreeLock()) fTreeSources->DeleteAllCustomData<XLinkList>();
381 fTreeSources.Reset(); }
382
383 Path scanPath(folder);
384 if(!scanPath.IsAbsolute()) {
385 scanPath.InsertAt("/", 0);
386 scanPath.InsertAt(app::Get<DXLApp>().PWD, 0);
387 }
388
389 Lox_Info("Scanning source copies in directory {}", folder )
390 files::CanonicalPathList resultPaths;
391 files::ScanParameters srcScanParams( scanPath,
392 ScanParameters::SymbolicLinks::RECURSIVE,
394 true, // crossFileSystems
395 true); // IncludeArtificialFS
396 {ALIB_LOCK_WITH(fTreeSources.GetLock())
397 alib::files::ScanFiles(*fTreeSources, srcScanParams, &resultPaths); }
398
399
400 Lox_Info("Source copies file tree scanned.") {
401 int cntLoggers;
402 Lox_IsActive(cntLoggers, Verbosity::Verbose)
403 if (cntLoggers > 0) {
404 String64 buf;
408 // todo: this method is not available in release builds, hence, .
409 } // it has to be done here on our own
410 Lox_Prune(TextLogger* rlogger= app::Get().GetRLogger();
411 rlogger->GetFormatMultiLine().Mode=3;)
412 Lox_Verbose("File tree:")
413 Lox_Verbose(buf)
414 Lox_Prune(rlogger->GetFormatMultiLine().Mode=2;)
415 }
416 }
417}
418
420 Lox_SetDomain("/DXL/SCAN/SRCREPL", Scope::Method)
421 Lox_Info("Scheduling source replacer jobs")
422
423 // we want maximum speed and even spare the fast log calls in the loop.
424 Verbosity verbosity;
425 Lox_GetVerbosity(verbosity)
426
429 treeIt.Initialize(fTreeSources->Root().AsCursor(), lang::Inclusion::Exclude);
430
431 while (treeIt.IsValid()) {
432 if ( !treeIt.Node()->IsDirectory() ) {
433
434 if (verbosity >= Verbosity::Info) {
435 Path p; File(treeIt.Node()).AssembleSymbolicPath(p, lang::Inclusion::Include);
436 Lox_Info("Scheduling XLink-replacement on source-copy {!Q}", p)
437 }
438 TPool.ScheduleVoid<SourceReplacer>(*this, treeIt.Node());
439 Stats.ReplSourceFiles.fetch_add(1);
440 }
441
442 treeIt.Next();
443 }
444
445 auto qtyFiles = Stats.ReplSourceFiles.load();
446 if (qtyFiles == 0) {
448 app.cErr->Add(app.cli.ExitCodeDecls.Find(ExitCodes::NoSourceCopiesFound).Mapped()->
449 FormatString(), folder);
450 app.machine.SetExitCode(ExitCodes::NoSourceCopiesFound);
451 throw Exception(ALIB_CALLER_NULLED, app::App::Exceptions::ControlledEarlyExit);
452 }
453}
454
455//==================================================================================================
456// Run
457//==================================================================================================
459
460
462 Lox_SetDomain("DXL", Scope::Filename)
463 auto* rlogger = app.GetRLogger();
464 Lox_SetVerbosity(rlogger, Verbosity::Info, "/")
465 Lox_SetVerbosity(rlogger, Verbosity::Warning, "/ALIB/FILES")
466 Lox_SetVerbosity(rlogger, Verbosity::Warning, "/ALIB/TMOD")
467 Lox_SetVerbosity(rlogger, Verbosity::Warning, "/ALIB/TMOD")
468 Lox_SetVerbosity(rlogger, Verbosity::Warning, "$/")
469 Lox_SetVerbosity(rlogger, Verbosity::Warning, "$/V")
470
471 Lox_Info("{} {}: Started", app.GetName(), app.GetVersion())
472 Lox_Verbose(app.GetInfo())
473
474 Lox_Info("Number of hardware-threads (machine spec): ", std::thread::hardware_concurrency())
475
476 dynamic_cast<format::FormatterPythonStyle&>(*app.cOut->Formatter).Sizes
477 ->Actual(AutoSizes::Types::Tabstop, 25, 0);
478 app.printConfigFileInfo(*app.cOut);
479
480 // read current directory, if given. Otherwise detect
482 if(pwd.Define()) {
483 Path currentDir(SystemFolders::Current);
484 pwd.GetString().Reset(currentDir);
485 Lox_Warning("Current directory detected as: ", pwd.GetString())
486 }
487 else Lox_Warning("Current directory provided with parameter --PWD={}", pwd.GetString())
488 app.PWD= pwd.GetString();
489
490 app.cOut->Add("Doxyfile: {!ATab}:1", app.DoxyfilePath);
491 Doxyfile.Load(app.DoxyfilePath);
492 // todo: This should be a command or option. If command, exit afterwards.
493 // If option, continue processing.
494 // todo: The Dump function has to be checked to be up to date.
495 //Doxyfile.Dump();
496
497 // read exclamation file
498 app.cOut->Add("Exclamations-file: {!ATab}:1", ExclamationsPath);
499 app.onSdOutput();
501
502 // configure the thread pool
503 // todo: make configurable. Probably a general App-Variable which allows to specifiy the
504 // most important settings of class ThreadPool?
505 TPool.Strategy.Mode = ThreadPool::ResizeStrategy::Modes::Fixed;
506 TPool.Strategy.WorkersMax=10;
507 TPool.Strategy.WorkersMax= 1;
508 Lox_Info("Schedule file scan...")
509
510 // scan source- and html-files
511 fTreeSources.DbgCriticalSections(lang::Switch::Off);
512 fTreeHTML .DbgCriticalSections(lang::Switch::Off);
513 scanSrcFiles(); // This launches the SourceLocationFinder jobs
514 scanHTMLFiles(); // This does NOT launch the HTMLReplacer jobs.
515
516 // read Doxygen tag-file and create index
517 app.stopWatch.Sample();
518
520 Indices.reserve(size_t(Doxyfile.TagFiles.size())); }
521
522 /// ----- multithreading starts here ----
523 ALIB_DBG( MA.DbgCriticalSectionsPH->DCSLock= &DLLock; )
524 fTreeSources.DbgCriticalSections(lang::Switch::On);
525 fTreeHTML .DbgCriticalSections(lang::Switch::On);
526
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)
530
531 // the last one gets is marked as the main file
532 bool isLast; {
533 auto tfInfoNext= tfInfoIt;
534 ++tfInfoNext;
535 isLast= tfInfoNext == Doxyfile.TagFiles.end();
536 }
537 Index *index;
539 index = MA().New<Index>( tfInfoIt->TagFilePath,
540 tfInfoIt->BaseURL,
541 isLast ); }
542 Indices.push_back(index);
543 if ( !isLast )
544 TPool.ScheduleVoid<IndexLoader>(*index);
545 else
546 index->Load();
547 }
548
549 // wait for source readers to be idle (the index loader(s) might still be active)
551 TPool.WaitForAllIdle(10min ALIB_DBG(, 5s));
552 Stats.TimeIndexAndSourceLoading= app.stopWatch.Sample();
553
554
555 // now launch the HTMLReplacer jobs
557 TPool.WaitForAllIdle(10min ALIB_DBG(, 5s));
558 Stats.TimeHTMLReplacements= app.stopWatch.Sample();
559
560
561 #if ALIB_DEBUG
562 // in debug-builds we can now switch off critical section checks
563 for (auto* index: Indices)
564 index->DbgCriticalSectionCheck(alib::lang::Switch::Off);
565
566 // in debug-builds and if running on the DXL doc itself, unit tests are performed
567 DbgUnitTests(this);
568 #endif
569
570 // write stats
572 app.onSdOutput();
573
574 // write error output
575 writeErrors();
576 app.onSdOutput();
577
578 // write links in source not in HTML (This happens when Doxygen was not run)
580 app.onSdOutput();
581
582 // write links in HTML not in source (This should never happen. Indicates that the parsers
583 // work differently)
585 app.onSdOutput();
586
587 // todo: Option to list all non-used exclamations
588
589 // process --doxyfy option
590 {
591 Variable restoreSources= variables::CampVariable(alib::APPCLI_CAMP, A_CHAR("DOXYFY"), A_CHAR("S") );
592 (void) restoreSources.Define();
593 if ( restoreSources.GetString().IsNotEmpty() ) {
594 Lox_Info("Restoring sources in copy folder {!Q}", restoreSources.GetString())
595 scanReplSrcFiles(restoreSources.GetString());
596
597 // delete source-locations on XLinks
598 for(auto xlinkIt : XLinkMap)
599 xlinkIt.second->SourceLocations.clear();
600
601 #if ALIB_DEBUG
602 // in debug-builds we have to re-enable critical section checks
603 for (auto* index: Indices)
604 index->DbgCriticalSectionCheck(alib::lang::Switch::On);
605 #endif
606 schduleSourceReplacers(restoreSources.GetString());
607 TPool.WaitForAllIdle(10min ALIB_DBG(, 5s));
608 Stats.TimeSourceReplacements= app.stopWatch.Sample();
609
610 #if ALIB_DEBUG
611 // in debug-builds we can now switch off critical section checks
612 for (auto* index: Indices)
613 index->DbgCriticalSectionCheck(alib::lang::Switch::Off);
614 #endif
615 writeErrors();
616 app.onSdOutput();
617 }
618
619 }
620 // process list option
621 #if !defined ENABLE_LIST_OPTION
622 {
623 Variable listExpression= variables::CampVariable(alib::APPCLI_CAMP, A_CHAR("LIST"), A_CHAR("S") );
624 (void) listExpression.Define();
625 Variable listFormat= variables::CampVariable(alib::APPCLI_CAMP, A_CHAR("FORMAT"), A_CHAR("S") );
626 if (listFormat.Define()) {
627 listFormat.GetString().Reset("#{LinkString@!Q} -> \\ref {path} {Display@!Q}");
628 }
629 if ( listExpression.GetString().IsNotEmpty() ) {
630 Lox_Error("listing links({!Q<>}, {!Q'})", listExpression.GetString(), listFormat.GetString())
631 listLinks(listExpression.GetString(), listFormat.GetString());
632 app.onSdOutput();
633 }
634 }
635 #endif
636
637
638 // ---------------------------------------- finalize -------------------------------
639 {ALIB_LOCK_WITH(GetSourceTreeLock()) fTreeSources->DeleteAllCustomData<XLinkList>();}
640}
641
642//--------------------------------------------------------------------------------------------------
643//------------------------------- RegisterLink/GetLink -----------------------------------------
644//--------------------------------------------------------------------------------------------------
646 //searchString= "^;DXLApp::bsConfigureCLI;2"; // todo remove
647
649 // Get XLink from hash-map
650 auto it = XLinkMap.Find(searchString);
651 if (it != XLinkMap.end())
652 return it->second;
653
654 Lox_Verbose("New Xlink registered with #\"{}\"", searchString)
655 Stats.UniqueXLinks.fetch_add(1);
656 XLink * xLink = MA().New<XLink>();
657 xLink->LinkString= String(MA, searchString);
658 XLinkMap.EmplaceUnique(xLink->LinkString, xLink);
659 return xLink;
660}
661
662XLink *DoxygenXLinks::GetXLink(String &searchString, const File &htmlFile) {
663//searchString= "xyz .HasWarnings"; // todo remove
664//if (searchString == ">")
665// int todo= 5;
666
667 //--------------- search the XLink in the hash-map ---------------
668 XLink *xLink = nullptr;
670 // Get XLink from hash-map
671 auto it = XLinkMap.Find(searchString);
672 if (it != XLinkMap.end())
673 xLink= it->second;
674 else {
675 Lox_Info("XLink requested that was not registered, yet: #\"{}\"", searchString)
676 Stats.UniqueXLinks.fetch_add(1);
677 xLink = MA().New<XLink>();
678 xLink->LinkString= String(MA, searchString);
679 XLinkMap.EmplaceUnique(xLink->LinkString, xLink);
680 }
681 }
682
683 //--------------- evaluate the link (if not done, yet) ---------------
684 {ALIB_LOCK_WITH(xLink->Lock)
685 if ( xLink->IsParsed() ) {
686 // if not a local XL, then we're done
687 if ( !xLink->IsLocal || xLink->HasErrors())
688 return xLink;
689
690 // if the given file is invalid, then this is a call from the source-replacer
691 // (--doxyfy command). We have a problem now: Only if this link resides in only one
692 // html file (and thus was resolved locally only once, we can be sure to give the
693 // right answer. If it was used multiple times, we return the first, but we mark
694 // this link as erroneous now!
695 if( !htmlFile.AsCursor().IsValid() ) {
696 int cntLocalCopies= xLink->CountLocalCopies();
697 if( cntLocalCopies == 0 ) xLink->Error= XLink::Errors::RestoringUnusedLocalLink;
698 if( cntLocalCopies > 1 ) xLink->Error= XLink::Errors::RestoringAmbiguousLocalLink;
699 return xLink;
700 }
701
702 // get a localized version
703 auto linkAndIsNew= xLink->GetLocalCopy(htmlFile);
704 if (!linkAndIsNew.second)
705 return linkAndIsNew.first;
706 xLink= linkAndIsNew.first;
707 xLink->LocalLinkEntity= Indices.back()->GetHTMLFileEntity(htmlFile);
708 } else {
709 xLink->Parse();
710 if (xLink->HasErrors()) {
711 Stats.XLinksWithErrors.fetch_add(1);
712 Lox_Info("Error {} parsing the XLink {!Q}: {}", xLink->Error, searchString)
713 return xLink;
714 }
715
716 // local link?
717 if ( xLink->IsLocal ) {
718 // if the given file is invalid, then this is a call from the source-replacer
719 // (--doxyfy command). We have an ever bigger problem now than some lines above:
720 // The link was never found in HTML files. So something really went wrong.
721 // This will be displayed and explained to the user in the later output
722 if( !htmlFile.AsCursor().IsValid() ) {
724 return xLink;
725 }
726
727 auto linkAndIsNew= xLink->GetLocalCopy(htmlFile);
728 ALIB_ASSERT(linkAndIsNew.second, "DXL")
729 xLink= linkAndIsNew.first;
730 if (xLink->HasErrors()) {
731 Stats.XLinksWithErrors.fetch_add(1);
732 Lox_Info("Error {} parsing the XLink {!Q}: {}", xLink->Error, searchString)
733 return xLink;
734 }
735 xLink->LocalLinkEntity= Indices.back()->GetHTMLFileEntity(htmlFile);
736 }
737 }
738
739 // todo: Parsing has to be checked that no buffer overruns happen. and errors have to be
740 // set and checked above.
741 // Nevertheless, these assertions have to be kept, but changed to error messages
742 ALIB_ASSERT(xLink->Name().Length() > 0, "DXL")
743
744 // collect results from indices. For local links just check the actual tag file.
745 if (!xLink->IsLocal)
746 for (auto* index: Indices)
747 index->Search(*xLink);
748 else
749 Indices.back()->Search(*xLink);
750
751 //------------- No results: check for files found in HTML file tree -------------
752 if ( xLink->Targets.size() == 0 && xLink->KindSpec == Target::File )
754
755 //------------- apply further disambiguation rules -------------
756 if ( xLink->Targets.size() > 1 ) {
757
758 // rule: If typedef resolver '^' is given and this is not an indirection warning prefix
759 // instead, then type definitions are preferred
760 if ( xLink->NoIndirectionWarning)
761 {
762 bool hasIndirectMemberTargets= false;
763 bool hasTypedefTargets = false;
764 for ( auto& result : xLink->Targets ) {
765 hasIndirectMemberTargets |= result.IsIndirectByInheritance
766 | result.IsIndirectByTypeDef;
767 hasTypedefTargets |= result.Node.IsA(Target::Typedef);
768 }
769 if (hasTypedefTargets && !hasIndirectMemberTargets)
770 std::erase_if(xLink->Targets, [&](const auto& result) {
771 return !result.Node.IsA(Target::Typedef);
772 });
773 }
774
775 // rule: remove indirect results if directs exists
776 {
777 bool hasDirectMemberTargets = false;
778 bool hasIndirectMemberTargets= false;
779 for ( auto& result : xLink->Targets )
780 if ( result.IsIndirectByInheritance | result.IsIndirectByTypeDef )
781 hasIndirectMemberTargets= true;
782 else
783 hasDirectMemberTargets= true;
784
785 if ( hasDirectMemberTargets && hasIndirectMemberTargets )
786 std::erase_if(xLink->Targets, [&](const auto& result) {
787 return result.IsIndirectByInheritance | result.IsIndirectByTypeDef;
788 });
789 }
790
791 // rule: remove template specializations if non-specialized exists
792 if ( !xLink->SpecializationArgs)
793 {
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;
800 else
801 hasNonSpecialized= true;
802 }
803
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;
808 });
809 }
810
811 // rule: remove const-version of functions (with the same parent)
812 if ( xLink->Qualifiers.IsEmpty())
813 for ( auto& result : xLink->Targets )
814 if ( auto* t= result.Cast<TGTFunction>();
815 t && t->Qualifiers.IndexOf("const") < 0)
816 std::erase_if(xLink->Targets, [&](const auto& toDelete) {
817 auto* f= toDelete.template Cast<TGTFunction>();
818 return f && f->Qualifiers.IndexOf("const") >= 0;
819 });
820 }
821
822 // exactly one match: check if we need to resolve a type definition
823 if ( xLink->IsResolved()
824 && xLink->NoIndirectionWarning
825 && xLink->Result().Node.IsA(Target::Typedef)) {
826 xLink->NoIndirectionWarning = false;
827 xLink->IsUnderlyingTypeDef = true;
828 xLink->Result().Node= XLink::ResolveTypeDef(xLink->Result().Node, searchString);
829 if ( xLink->Result().Node.IsRoot() || !xLink->Result().Node.IsA(Target::RECORD)) {
831 xLink->Targets.clear();
832 } else {
833 xLink->Result().HTMLFile = xLink->Result().Node.HTMLFile();
834 xLink->Result().HTMLAnchor = nullptr;
835 xLink->Result().IsResolvedTypeDef= true;
836 }
837 }
838
839 // (still) exactly one match (success!).
840 if (xLink->IsResolved()) {
841 xLink->AssembleDisplay();
842 }
843
844 // XLink isn't resolved. Collect error output for later display sorted by link or by file
845 else if (xLink->Targets.empty()) {
846 Stats.UnresolvedXLinks.fetch_add(1);
847 Lox_Info("Search for {!Q} gave no result", searchString)
848 }
849
850 // Ambiguous XLink.
851 else {
852 // Collect error output for later display sorted by link or by file
853 Stats.AmbiguousXLinks.fetch_add(1);
854 Lox_Info("Search for {!Q} gave {} results", searchString, xLink->Targets.size())
855 }
856
857bool WARNINGS_IGNORE_INDIRECTS= false; // todo: make variable
858
859 if ( xLink->IsResolved() && !xLink->IsGood(WARNINGS_IGNORE_INDIRECTS)) {
860 Stats.XLinksWithWarnings.fetch_add(1);
861 Lox_Info("XLink {!Q} has warnings", searchString)
862 }
863
864 return xLink;
865 }
866}
867
868//================================= GetELDecoration ============================
870 bool isELREFAnchor,
871 File& elLocation,
872 String targetFilename,
873 String targetAnchor,
874 int lineNo, int colNo ) {
875
878
879 //---------------------- Special cases ----------------------
880
881 // check if it links to a "_source"-file
882 {
883 Substring fName= targetFilename.IsEmpty() ? elLocation.Name() : targetFilename;
884 integer pos= fName.LastIndexOf('.');
885 if (pos >= 0) {
886 String stem= fName.Substring(0, pos);
887 if (stem.EndsWith("_source") ) {
888 styles.Add(Styles::SrcFile);
889 if (targetAnchor.IsNotEmpty()){
890 ALIB_ASSERT(targetAnchor.StartsWith("l0"), "DXL/ELDECO")
891 styles.Add(Styles::SrcFileLine);
892 }
893 styles.Add(Styles::FileOrDir);
894 styles.isFile= true;
895 return;
896 }
897 }
898 }
899
900 // check if it links to a "dir_"-file
901 if (targetFilename.StartsWith("dir_") ) {
902 ALIB_ASSERT(targetAnchor.IsEmpty(), "DXL/ELDECO")
903 styles.Add(Styles::Dir);
904 styles.Add(Styles::FileOrDir);
905 styles.isDir= true;
906 return;
907 }
908
909 //---------------------- standard cases ----------------------
910 Index::Node node;
911
912 // if no file name is given, this is a local anchor in the HTML file.
913 // Thus it has to be in the main index
914 if (targetFilename.IsEmpty()) {
915 // search in file-map
916 if (targetAnchor.IsEmpty()) {
917 ALIB_LOCK_SHARED_WITH(Indices.back()->SLock)
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())
923 styles.Add(Styles::ELUnknown);
924 return;
925 }
926
927 if ( verbosityGetELDecoration >= Verbosity::Info)
928 Lox_Info("ELDECO", "Found file {!Q} in main index.", elLocation.Name())
929 node= Indices.back()->ImportCursor(it->second);
930
931 // search in anchor-map
932 } else {
933 ALIB_LOCK_SHARED_WITH(Indices.back()->SLock)
934 auto it= Indices.back()->anchorMap.Find({elLocation.Name(), targetAnchor});
935 if ( it == Indices.back()->anchorMap.end() ) {
936 if ( verbosityGetELDecoration > Verbosity::Warning)
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);
943 styles.Add(Styles::ELUnknown);
944 return;
945 }
946 node= Indices.back()->ImportCursor(it->second);
947 }
948
949 // a file name is given: can be any of the indices (also the main index, if not an ELREF anchor)
950 } else {
951 // remove the base URL from the file name
952 size_t indexIdx= size_t(-1);
953 for (size_t idx= 0 ; idx < Indices.size() - (isELREFAnchor? 1 : 0) ; ++idx) {
954 auto* index= Indices[idx];
955 if ( targetFilename.StartsWith(index->BaseURL) ) {
956 indexIdx= idx;
957 targetFilename= targetFilename.Substring(index->BaseURL.Length());
958 if (targetFilename.StartsWith("/") || targetFilename.StartsWith("\\"))
959 targetFilename= targetFilename.Substring(1);
960 break;
961 }
962 }
963
964 // search in file-map
965 if ( targetAnchor.IsEmpty() ) {
966 bool found= false;
967 for (size_t idx= 0 ; idx < Indices.size() - (isELREFAnchor? 1 : 0) ; ++idx) {
968 if (indexIdx != size_t(-1) && idx != indexIdx)
969 continue;
970 auto* index= Indices[idx];
971 ALIB_LOCK_SHARED_WITH(index->SLock)
972 auto it= index->fileMap.Find(targetFilename);
973 if ( it != index->fileMap.end() ) {
974 node= index->ImportCursor(it->second);
975 found= true;
976 break;
977 }
978 }
979 if (!found) {
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);
983 styles.Add(Styles::ELUnknown);
984 return;
985 }
986 if ( verbosityGetELDecoration >= Verbosity::Info)
987 Lox_Info("ELDECO", "Found file {!Q} in index {}:{}.", targetFilename,
988 node.Index().FilePath, node.LineNo())
989
990 // search in anchor-map
991 } else {
992 bool found= false;
993 for (size_t idx= 0 ; idx < Indices.size() ; ++idx) {
994 if (indexIdx != size_t(-1) && idx != indexIdx)
995 continue;
996 auto* index= Indices[idx];
997 ALIB_LOCK_SHARED_WITH(index->SLock)
998 auto it= index->anchorMap.Find({targetFilename, targetAnchor});
999 if ( it != index->anchorMap.end() ) {
1000 node= index->ImportCursor(it->second);
1001 found= true;
1002 break;
1003 }
1004 }
1005 if (!found) {
1006 if ( verbosityGetELDecoration >= Verbosity::Warning)
1007 Lox_Warning("ELDECO",
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);
1014 styles.Add(Styles::ELUnknown);
1015 return;
1016 }
1017
1018 if ( verbosityGetELDecoration >= Verbosity::Info)
1019 Lox_Info("ELDECO", "Found file/anchor {}/{}#{} in index. HTML-Location {0}/{}:{}.",
1020 node.Index().BaseURL, targetFilename, targetAnchor,
1021 elLocation.Name(), lineNo, colNo)
1022 }
1023 }
1024
1025 ALIB_ASSERT(node.IsValid(), "DXL/ELDECO")
1026 styles.Set( node, false, false );
1027 styles.Add(Styles::XLEL);
1028}
1029
1030//================================= writeErrors ============================
1032 Lox_SetDomain("RESULT", Scope::Method)
1033 Lox_Info("Writing non-resolved or ambiguous XLinks. (The main output)")
1034
1036
1037 // reset all xlink in respect to print information.
1038 for(auto xLinkIt : XLinkMap )
1039 xLinkIt.second->WasPrinted= false;
1040
1041 // ReSharper disable CppDFAUnreachableCode
1044 RecentlyModifiedFirst sorter;
1045 treeIt.SetPathGeneration(lang::Switch::On);
1046 treeIt.SetSorting(&sorter);
1047 treeIt.Initialize(fTreeSources->Root().AsCursor(), lang::Inclusion::Exclude);
1048
1049 int cntLocations = 0;
1050
1051 // main loop over all source files
1052 while (treeIt.IsValid()) {
1053 File actFile(treeIt.Node());
1054
1055 // no links attached to that source file?
1056 if (!actFile.HasCustomData()) {
1057 Lox_Verbose("No unresolved XLinks found with file {}:1", treeIt.Path())
1058 treeIt.Next();
1059 continue;
1060 }
1061
1062 auto &linksInSrc = actFile.GetCustomData<XLinkList>();
1063 Lox_Info("Found {} (unique) XLinks with file {}:1",
1064 linksInSrc.size(), treeIt.Path())
1065
1066 bool SUPPRESS_WARNINGS= false; // todo: make variable
1067
1068 // loop over all links in the source file
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;
1074 continue;
1075 }
1076 if (linkInSrc.XL->NotFoundInHTML)
1077 continue;
1078
1079 // loop over a) just the XLink, or b) all local versions of it
1080 XLink* xlOrCopy= linkInSrc.XL;
1081 while (xlOrCopy) {
1082 // check if written
1083 if (xlOrCopy->WasPrinted) {
1084 break;
1085 }
1086 xlOrCopy->WasPrinted = true;
1087
1088 if ( xlOrCopy->IsGood( SUPPRESS_WARNINGS ) ) {
1089 while ((xlOrCopy= xlOrCopy->NextLocal) != nullptr )
1090 if ( !xlOrCopy->IsResolved() )
1091 break;
1092 continue;
1093 }
1094
1095 Lox_Info("{} XLink {!ATab!Q} @ {}:{}:{}",
1096 xlOrCopy->Targets.size() > 1 ? "Ambiguous"
1097 : xlOrCopy->Targets.size() == 0 ? "Unresolved"
1098 : xlOrCopy->HasErrors() ? "Error in"
1099 : "Warning in",
1100 xlOrCopy->LinkString, treeIt.Path(), linkInSrc.Line, linkInSrc.Column)
1101
1102 String256 path(treeIt.Path());
1104 xlOrCopy->PrintError(*app.cErr, xlOrCopy->LinkString); }
1105 cntLocations+= xlOrCopy->SourceLocations.size();
1106 app.cErr->PushIndent(2);
1107
1108 // loop over all occurrences of this XLink in sources.
1109 // We do our sorting of source files once more, only then it is rightfully sorted
1110 StringTreeIterator<FTree> innerTrIt;
1111 innerTrIt.SetPathGeneration(lang::Switch::On);
1112 innerTrIt.SetSorting(&sorter);
1113 innerTrIt.Initialize(fTreeSources->Root().AsCursor(), lang::Inclusion::Exclude);
1114
1115 // inner loop over all source files
1116 while (innerTrIt.IsValid()) {
1117 system::Path locationPath;
1118 for (auto &srcLoc: linkInSrc.XL->SourceLocations)
1119 if (innerTrIt.Node() == srcLoc.File.AsCursor()) {
1120 if (locationPath.IsEmpty())
1121 File(innerTrIt.Node()).AssembleSymbolicPath(locationPath, lang::Inclusion::Include);
1122 Lox_Info(" @ {}:{}:{}", locationPath, srcLoc.Line, srcLoc.Column)
1123 app.cErr->Add( "@ {}:{}:{}", locationPath, srcLoc.Line, srcLoc.Column);
1124 }
1125 innerTrIt.Next();
1126
1127 }
1128
1129 // This is a copy of the local link
1130 if ( xlOrCopy->IsLocal && xlOrCopy->HTMLFileOfLocalLink.IsValid() ) {
1131 app.cErr->Add( "This local XLink's HTML file: {}", // Todo Hier muss dann das target scope hinkommen, wenn das gemacht ist
1132 GetHTMLTree().ImportCursor(xlOrCopy->HTMLFileOfLocalLink).Name() );
1133 }
1134
1135 app.cErr->Add(NEW_LINE);
1136 app.cErr->PopIndent();
1137
1138 while ((xlOrCopy= xlOrCopy->NextLocal) != nullptr )
1139 if ( !xlOrCopy->IsResolved() )
1140 break;
1141 } // loop over all xLinks
1142 }
1143
1144 // next file
1145 treeIt.Next();
1146 } // loop over all source files
1147
1148
1149 // ReSharper restore CppDFAUnreachableCode
1150 auto cntErrs= Stats.UnresolvedXLinks.load()
1151 + Stats.AmbiguousXLinks.load()
1152 + Stats.XLinksWithErrors;
1153 if ( cntErrs > 0) {
1154 app.cErr->Add("Error summary: {} erroneous XLinks @ {} locations.", cntErrs, cntLocations
1155 );
1156 }
1157
1158 if ( Stats.XLinksWithWarnings.load() > 0) {
1159 app.cErr->Add("Warning summary: {} XLinks with warnings."
1160 , Stats.XLinksWithWarnings.load() + Stats.AmbiguousXLinks.load()
1161 );
1162 }
1163}
1164
1165//================================= listLinks ============================
1166void DoxygenXLinks::listLinks(const String& expressionString, const String& format ) {
1167 if ( expressionString.IsEmpty())
1168 return;
1169
1170 Lox_SetDomain("LIST", Scope::Method)
1172 app.stopWatch.Sample();
1173
1174
1175 //----------------- compile expression -----------------
1176 try {
1177 DXLExpression expr(expressionString);
1178 if(! ( expr.ResultType().IsType<bool>()
1179 || expr.ResultType().IsType<integer>() ) ) {
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"
1183 " Result type: {}"
1184 , app.GetName(), expressionString, expr.GetExpressionString()
1185 , expr.ResultType().IsType<long>() ? "long"
1186 :expr.ResultType().IsType<String>() ? "String"
1187 : "Unknown"
1188 );
1189 return;
1190 }
1191
1192 Lox_Info( "Expression sucessfully compiled:\n"
1193 " Given expression string: {!Q}\n"
1194 " Normalized expression string: {!Q}\n"
1195 " Result type: {}"
1196 , expressionString, expr.GetExpressionString()
1197 , expr.ResultType().IsType<long>() ? "integral"
1198 :expr.ResultType().IsType<String>() ? "String"
1199 : "Unknown" )
1200
1201 if (expr.IsConstant())
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
1207 , expr.GetOptimizedString() );
1208
1209 // Reset printing flag
1210 for (auto& xLink : XLinkMap)
1211 xLink.second->WasPrinted = false;
1212
1213 // ReSharper disable CppDFAUnreachableCode
1216 RecentlyModifiedFirst sorter;
1217 treeIt.SetPathGeneration(lang::Switch::On);
1218 treeIt.SetSorting(&sorter);
1219 treeIt.Initialize(fTreeSources->Root().AsCursor(), lang::Inclusion::Exclude);
1220
1221 int cntXLinks = 0;
1222 int cntLocations = 0;
1223
1224 // create the expression formatter
1225 DXLExpressionFormatter exprFormatter( format );
1226 DXLScope dxlScope;
1227
1228 // main loop over all source files
1229 while (treeIt.IsValid()) {
1230 File actFile(treeIt.Node());
1231
1232 // no links attached to that source file?
1233 if (!actFile.HasCustomData()) {
1234 treeIt.Next();
1235 continue;
1236 }
1237 auto &linksInSrc = actFile.GetCustomData<XLinkList>();
1238
1239 // loop over all links in the source file
1240 for (auto &linkInSrc: linksInSrc) {
1241 // check if written
1242 if (linkInSrc.XL->WasPrinted)
1243 continue;
1244 linkInSrc.XL->WasPrinted = true;
1245
1246 // evaluate expression
1247 if ( !expr.Includes(linkInSrc.XL) )
1248 continue;
1249
1250 ++cntXLinks;
1251
1252 String256 path(treeIt.Path());
1253 app.cOut->Add(NEW_LINE);
1254
1255 dxlScope.Xlink = linkInSrc.XL;
1256
1258 exprFormatter.Format( app.cOut->Buffer, dxlScope ); }
1259
1260 app.cOut->PushIndent(2);
1261 app.cOut->Add("@ {}:{}:{}",
1262 path, linkInSrc.Line, linkInSrc.Column);
1263
1264 // loop over all occurrences of this XLink in other sources
1265 for (auto &srcInLink: linkInSrc.XL->SourceLocations) {
1266 ++cntLocations;
1267 // skip if this the current position
1268 if ( srcInLink.File.AsCursor() == treeIt.Node()
1269 && srcInLink.Line == linkInSrc.Line
1270 && srcInLink.Column == linkInSrc.Column)
1271 continue;
1272 system::Path furtherPath;
1273 srcInLink.File.AssembleSymbolicPath(furtherPath, lang::Inclusion::Include);
1274 app.cOut->Add( "@ {}:{}:{}", furtherPath, srcInLink.Line, srcInLink.Column);
1275 }
1276 app.cOut->PopIndent();
1277 }
1278
1279 // next file
1280 treeIt.Next();
1281 } // loop over all source files
1282
1283
1284 // ReSharper restore CppDFAUnreachableCode
1285 app.cOut->Add("List summery: Found {} XLinks @ {} locations that match expression {}.\n"
1286 "Query generation time: {}"
1287
1288 , cntXLinks
1289 , cntLocations
1290 , expr.GetExpressionString()
1291 , app.stopWatch.Sample()
1292 );
1293
1294 //--------------------- exception handling ----------------
1295 } catch (Exception& e) {
1296 Lox_Exception(e, Verbosity::Error )
1297 app.cErr->Add("Error parsing expression {!Q}:", expressionString);
1298 String512 exceptionMsg;
1300 e.Format(exceptionMsg); }
1301
1302 app.cErr->Add(exceptionMsg);
1303 }
1304}
1305
1306//================================= writeXLinksInSourceNotInHTML ============================
1308 Lox_SetDomain("RESULT", Scope::Method)
1309 // count all links with unresolved HTML file
1310 int cntSrcOnlyLinks= 0;
1311 for (auto& it : XLinkMap)
1312 if ( it.second->HTMLLocations.empty()
1313 || (it.second->IsLocal && !it.second->HTMLFileOfLocalLink.IsValid()) )
1314 ++cntSrcOnlyLinks;
1315
1316 if ( cntSrcOnlyLinks == 0)
1317 return;
1318
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"
1326 " comment.\n"
1327 "\n"
1328 " Printing the first 5:\n",
1329 cntSrcOnlyLinks );
1330 int cnt= 5;
1331 app.cErr->PushIndent(2);
1332 for (auto& it : XLinkMap ) {
1333 if ( !it.second->HTMLLocations.empty()
1334 && !(it.second->IsLocal && !it.second->HTMLFileOfLocalLink.IsValid()) )
1335 continue;
1336 if (--cnt < 0)
1337 break;
1338 app.cErr->Add( "XLink #{!Q}", it.first );
1339 app.cErr->PushIndent(2);
1340 for ( auto& loc : it.second->SourceLocations ) {
1341 system::Path path;
1343 loc.File.AssembleSymbolicPath(path, lang::Inclusion::Include); }
1344 app.cErr->Add( "@ {}:{}:{}", path, loc.Line, loc.Column );
1345 }
1346 app.cErr->PopIndent();
1347 }
1348 app.cErr->PopIndent();
1349}
1350
1352 Lox_SetDomain("RESULT", Scope::Method)
1353 // count all links with unresolved HTML file
1354 int cntHTMLOnlyLinks= 0;
1355 for (auto& it : XLinkMap)
1356 if ( it.second->SourceLocations.empty() )
1357 ++cntHTMLOnlyLinks;
1358
1359 if ( cntHTMLOnlyLinks == 0)
1360 return;
1361
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"
1369 "\n"
1370 "Printing the first 5:\n"
1371 ,cntHTMLOnlyLinks, app.GetName() );
1372 int cnt= 5;
1373
1374 app.cErr->PushIndent(2);
1375 for (auto& it : XLinkMap ) {
1376 if ( !it.second->SourceLocations.empty() )
1377 continue;
1378 if (--cnt < 0)
1379 break;
1380 app.cErr->Add( "XLink #{!Q}" ,it.first );
1381 app.cErr->PushIndent(2);
1382 for ( auto& loc : it.second->HTMLLocations ) {
1383 system::Path path;
1385 loc.File.AssembleSymbolicPath(path, lang::Inclusion::Include); }
1386 app.cErr->Add( "@ {}:{}:{}", path ,loc.Line ,loc.Column );
1387 }
1388 app.cErr->PopIndent();
1389 }
1390 app.cErr->PopIndent();
1391}
1392//================================= writeStatistics ============================
1394 Lox_SetDomain("RESULT", Scope::Method)
1396
1397 // statistics count XLink locations
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;
1408
1409 for (auto &it: XLinkMap) {
1410 XLink& xLink= *it.second;
1411 Lox_Info("Dump", "XLink found: {} {!ATab}", it.first, it.second->IsResolved())
1412 if( xLink.IsGood(false)) { srcLocationsGood += xLink.SourceLocations.size();
1413 htmlLocationsGood += xLink.HTMLLocations .size(); }
1414 else if( xLink.HasErrors()) { srcLocationsWithErrors += xLink.SourceLocations.size();
1415 htmlLocationsWithErrors += xLink.HTMLLocations .size(); }
1416 else if( xLink.Targets.size() ==0 ) { srcLocationsUnresolved += xLink.SourceLocations.size();
1417 htmlLocationsUnresolved += xLink.HTMLLocations .size(); }
1418 else if( xLink.Targets.size() > 1 ) { srcLocationsAmbiguous += xLink.SourceLocations.size();
1419 htmlLocationsAmbiguous += xLink.HTMLLocations .size(); }
1420 else { srcLocationsWithWarnings += xLink.SourceLocations.size();
1421 htmlLocationsWithWarnings+= xLink.HTMLLocations .size(); }
1422 }
1423
1424 Variable getStatistics= variables::CampVariable(alib::APPCLI_CAMP, A_CHAR("STATISTICS"), A_CHAR("B") );
1425 if( getStatistics.Define() )
1426 getStatistics= false;
1427
1428 // short version if option "--STATISTICS" is not set
1429 app.stopWatch.Sample();
1430
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: {}"
1435 , app.GetName()
1436 , htmlLocationsGood
1437 , Stats.HTMLFiles.load()
1438
1439 , srcLocationsGood
1440 , Stats.SourceFiles.load()
1441
1442 , app.stopWatch.GetCumulated()
1443 );
1444 return;
1445 }
1446
1447 //----------------------------------- long version -----------------------------------
1448 {
1449 String512 parameters;
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 );
1453 }
1454
1455 // tag-files
1456 app.cOut->Add("Tag-files:\n============");
1457 app.cOut->PushIndent(2);
1458 unsigned ctdTagFiles= 0;
1459 integer maxTagFileNameLen= 0;
1460 for (auto &index: Indices) {
1461 app.cOut->Add("No {}: {:,6} lines read, file {!Q}, URL: {}, load time {}",
1462 ctdTagFiles + 1,
1463 index->StatCtdLines, index->FilePath, index->BaseURL, index->LoadTime);
1464 maxTagFileNameLen= std::max(maxTagFileNameLen, index->FileName.Length());
1465 ++ctdTagFiles;
1466 }
1467 std::vector<int> kindSums;
1468 kindSums.reserve(ctdTagFiles);
1469
1471 auto& fmt= app.cOut->Formatter;
1472 auto& buf= app.cOut->Buffer;
1473 buf << NEW_LINE;
1474 // headline
1475 buf << " Type ";
1476 for ( unsigned i= 0; i< ctdTagFiles ; ++i)
1477 fmt->Format(buf, String64("|{:>")._(maxTagFileNameLen)._("} "), Indices.at(i)->FileName);
1478 buf << NEW_LINE;
1479 buf << " ----------------";
1480 for ( unsigned tf= 0; tf< ctdTagFiles ; ++tf) {
1481 fmt->Format(buf, "|-{!FillC-}", maxTagFileNameLen);
1482 kindSums.push_back(0);
1483 }
1484 buf << NEW_LINE;
1485
1486 // Kinds
1487 for (int kindIdx= 0 ; kindIdx < int(Target::MAX_KIND) ; ++kindIdx) {
1488 Target::Kinds kind = Target::Kinds(1<<kindIdx);
1489 if ( kind == Target::FILEPATH_COMPONENT )//|| !index->KindStats.Count[i] )
1490 continue;
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);
1496 }
1497 buf << NEW_LINE;
1498 }
1499 // Sums
1500 buf << " ----------------";
1501 for ( unsigned tf= 0; tf< ctdTagFiles ; ++tf)
1502 fmt->Format(buf, "|-{!FillC-}", maxTagFileNameLen);
1503 buf << NEW_LINE;
1504 buf << " Sum ";
1505 for ( unsigned i= 0; i< ctdTagFiles ; ++i)
1506 fmt->Format(buf, String64("|{:,")._(maxTagFileNameLen)._("} "), kindSums[i]);
1507 buf << NEW_LINE;
1508 }
1509 app.cOut->PopIndent();
1510
1511 //----------------- files and locations -----------------
1512 app.cOut->Add(NEW_LINE);
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() );
1523
1524 app.cOut->Add(" Unresolved |{:9,} |{:9,} |{:9,}\n" , srcLocationsUnresolved,
1525 htmlLocationsUnresolved, Stats.UnresolvedXLinks.load() );
1526
1527 app.cOut->Add(" Ambiguous |{:9,} |{:9,} |{:9,}\n" , srcLocationsAmbiguous,
1528 htmlLocationsAmbiguous, Stats.AmbiguousXLinks.load() );
1529
1530 app.cOut->Add(" Erroneous |{:9,} |{:9,} |{:9,}\n", srcLocationsWithErrors,
1531 htmlLocationsWithErrors, Stats.XLinksWithErrors.load() );
1532
1533 app.cOut->Add(" Warnings |{:9,} |{:9,} |{:9,}\n", srcLocationsWithWarnings,
1534 htmlLocationsWithWarnings, Stats.XLinksWithWarnings.load() );
1535
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"
1546 , format::ByteSizeIEC(uinteger( Stats.SourceFileSize.load() ))
1547 , format::ByteSizeIEC(uinteger( Stats.HTMLFileSize.load() ))
1548 , format::ByteSizeIEC(uinteger( Stats.SourceFileSize.load() + Stats.HTMLFileSize.load() ))
1549 );
1550 app.cOut->Add(" Time |{:>9} |{:>9} |{:>9}\n", Stats.TimeIndexAndSourceLoading
1551 , Stats.TimeHTMLReplacements, Stats.TimeIndexAndSourceLoading + Stats.TimeHTMLReplacements );
1552
1553 app.cOut->PopIndent();
1554
1555 // Times
1556 app.cOut->Add(NEW_LINE);
1557 app.cOut->Add("Total Time: {}", app.stopWatch.GetCumulated());
1558}
1559
1561 // checks
1562 ALIB_ASSERT_ERROR(xLink.KindSpec == Target::File, "DXL",
1563 "XLink must be of kind 'File' to be resolved from HTML file")
1564 ALIB_ASSERT_ERROR(xLink.Targets.size() == 0, "DXL",
1565 "This method must only be called if on unresolved links")
1566 if ( xLink.Error != XLink::Errors::OK)
1567 return;
1568
1569 // convert file name
1570 system::Path dxNameNormal;
1571 system::Path dxNameSource;
1572 {
1573 String name = xLink.Name();
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;
1588 }
1589 }
1590 dxNameSource << dxNameNormal << "_source";
1591 dxNameNormal << Doxyfile.HtmlFileExtension;
1592 dxNameSource << Doxyfile.HtmlFileExtension;
1593
1594 // ReSharper disable CppDFAUnreachableCode
1595
1596 File foundNormal;
1597 File foundSource;
1600 treeIt.Initialize(fTreeHTML->Root().AsCursor(), lang::Inclusion::Exclude);
1601 while (treeIt.IsValid()) {
1602 if ( !xLink.NoIndirectionWarning && treeIt.Node().Name().Equals(dxNameNormal) )
1603 foundNormal= treeIt.Node();
1604 if ( xLink.NoIndirectionWarning && treeIt.Node().Name().Equals(dxNameSource) )
1605 foundSource= treeIt.Node();
1606 treeIt.Next();
1607 } }
1608
1609 // ReSharper restore CppDFAUnreachableCode
1610 if ( foundNormal.AsCursor().IsInvalid() && foundSource.AsCursor().IsInvalid() )
1611 return;
1612
1613 if (foundNormal.AsCursor().IsValid() && !xLink.NoIndirectionWarning) foundSource= File();
1614 if (foundSource.AsCursor().IsValid() && xLink.NoIndirectionWarning) foundNormal= File();
1615 ALIB_ASSERT(!(foundNormal.AsCursor().IsValid() && foundSource.AsCursor().IsValid()), "DXL")
1616
1617 // create a new file-node in the Index!
1618 Index& index= *Indices.back();
1619 String256 path;
1620 for (int i= 0; i < xLink.ScopeSize(); ++i)
1621 path << xLink.Scope(i) << index.Separator();
1622 path << xLink.Name();
1623 if ( foundSource.AsCursor().IsValid() )
1624 path << "_source";
1625
1626 Index::Node node= index.Root();
1627 { ALIB_LOCK_WITH(index.SLock)
1628 static TGTFilePathComponent filePathComponentTag(-1);
1629 bool created= node.AsCursor().GoToCreatedPathIfNotExistent(path, &filePathComponentTag) != 0;
1630 if ( created ) {
1631 auto* tgtFile= index.ma().New<TGTFile>(
1632 (foundNormal.AsCursor().IsValid() ? foundNormal
1633 : foundSource).Name()
1634 , 0 );
1635 node.ReplaceTarget(tgtFile);
1636 }
1637 }
1638
1639 xLink.Targets.push_back({ node
1640 ,index.BaseURL
1641 ,node.HTMLFile()
1643 ,false,false,false,false, false
1644 ,true // LinksToAScannedHTMLFile
1645 ,foundSource.AsCursor().IsValid() // IsIndirectLinkToScannedHTMLSourceFile
1646 });
1647
1648
1649}
1650} //namespace [dxl]
1651
#define ALIB_LOCK_SHARED_WITH(lock)
#define ALIB_CALLER_NULLED
#define A_CHAR(STR)
#define ALIB_ASSERT(cond, domain)
#define ALIB_LOCK_RECURSIVE_WITH(lock)
#define ALIB_DBG(...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
#define ALIB_LOCK_WITH(lock)
#define Lox_Exception(...)
#define Lox_Info(...)
#define Lox_Prune(...)
#define Lox_SetVerbosity(...)
#define Lox_Error(...)
#define Lox_SetDomain(...)
#define Lox_GetVerbosity(result,...)
#define Lox_Verbose(...)
#define Lox_IsActive(result,...)
#define Lox_Warning(...)
bool IsType() const
void Initialize(CursorType startNode, lang::Inclusion includeStartNode)
const TStringTree::NameType Path() const
void SetPathGeneration(lang::Switch pathGeneration)
constexpr CharacterType Separator() const noexcept
void Format(AString &target, expressions::Scope &scope)
TCustom & GetCustomData()
bool HasCustomData() const
strings::TAString< system::PathCharType > & AssembleSymbolicPath(strings::TAString< system::PathCharType > &target, lang::Inclusion includeFilename) const
Cursor & AsCursor()
static threads::RecursiveLock DEFAULT_LOCK
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)
class DXLApp
Definition dxlapp.hpp:37
alib::Box IsConstant()
alib::String GetExpressionString()
alib::Box ResultType()
bool Includes(XLink *xLink)
alib::String GetOptimizedString()
alib::system::PathString FilePath
The path to the doxygenTagFile.
Definition index.hpp:227
alib::MonoAllocator ma
The allocator used for the parent #"StringTree" and for the hashtable in the field map.
Definition index.hpp:50
const alib::String & BaseURL
The URL of the HTML-output created with this tag-file.
Definition index.hpp:233
void Load()
Loads the tag-file and creates the index.
Definition index.cpp:76
alib::SharedLock SLock
Definition index.hpp:238
static constexpr alib::String SrcFileLine
CSS class name. See user manual chapter #"dxl_styling".
Definition styles.hpp:61
bool isFile
This set when a file is targeted by the XLink.
Definition styles.hpp:50
static constexpr alib::String Dir
CSS class name. See user manual chapter #"dxl_styling".
Definition styles.hpp:62
static constexpr alib::String SrcFile
todo: only set with EL/ELRef today.
Definition styles.hpp:60
static constexpr alib::String FileOrDir
CSS class name. See user manual chapter #"dxl_styling".
Definition styles.hpp:78
bool isDir
This set when a dir is targeted by the XLink.
Definition styles.hpp:47
static constexpr alib::String ELUnknown
CSS class name. See user manual chapter #"dxl_styling".
Definition styles.hpp:89
static constexpr alib::String XLEL
CSS class name. See user manual chapter #"dxl_styling".
Definition styles.hpp:88
void Set(const Index::Node &node, bool hasDisplayText, bool isIndirect)
Definition styles.cpp:18
void Add(const alib::String &style)
Definition styles.hpp:118
Kinds
Enumerates the kinds of compounds found in a the Doxygen tagfile.
Definition target.hpp:28
@ MAX_KIND
The highest bit defining a kind.
Definition target.hpp:57
@ Typedef
Denotes a type definition.
Definition target.hpp:44
@ File
Denotes a source file.
Definition target.hpp:31
@ FILEPATH_COMPONENT
A node of a file path (not a doxygen kind).
Definition target.hpp:52
@ RECORD
Mask to identify records types.
Definition target.hpp:67
TApp & Get()
int Compare(const TChar *lhs, const TChar *rhs, integer cmpLength)
FInfo::ScanStates ScanFiles(FTree &tree, ScanParameters &parameters, 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)())
void Destruct(T &object)
strings::TString< PathCharType > PathString
variables::Variable CampVariable(camp::Camp &camp)
lox::Verbosity Verbosity
lox::textlogger::TextLogger TextLogger
variables::Variable Variable
files::File File
LocalString< 64 > String64
constexpr CString NEW_LINE
constexpr const String EMPTY_STRING
lang::integer integer
LocalString< 4096 > String4K
strings::TString< character > String
app::AppCliCamp APPCLI_CAMP
system::Path Path
strings::TSubstring< character > Substring
characters::nchar nchar
exceptions::Exception Exception
LocalString< 256 > String256
strings::TAString< character, lang::HeapAllocator > AString
lang::uinteger uinteger
int ARG_C
const char ** ARG_VN
containers::StringTreeIterator< TTree > StringTreeIterator
files::SPFileFilter SPFileFilter
LocalString< 32 > String32
LocalString< 512 > String512
todox
Definition doxyfile.cpp:20
alib::StdVectorMA< ResolvedLocation > XLinkList
Definition xlink.hpp:40
void ConvertHTMLEntitiesToAscii(alib::AString &buffer)
Definition dxl.cpp:104
void ConvertASCIItoHTMLEntities(alib::AString &buffer)
Definition dxl.cpp:133
@ NoSourceCopiesFound
No sources found with the specification given in the Doxyfile.
Definition dxl.hpp:100
@ NoSourceFilesFound
No sources found with the specification given in the Doxyfile.
Definition dxl.hpp:98
@ NoHTMLFilesFound
HTML files to process not found.
Definition dxl.hpp:95
static constexpr unsigned InfiniteRecursion
XLink * Xlink
The link to evaluate.
The cursor type of the #"StringTree".
Definition index.hpp:105
const alib::String & HTMLFile() const
Definition index.hpp:187
void ReplaceTarget(class Target *newTarget)
Definition index.hpp:203
Index & Index() const
Definition index.hpp:173
bool IsA(Target::Kinds kind) const
Definition index.hpp:197
int LineNo() const
Definition index.hpp:183
Cursor & AsCursor()
Definition index.hpp:223
Node Node
The cursor pointing to the result.
Definition index.hpp:386
alib::String HTMLFile
Definition index.hpp:395
bool IsResolvedTypeDef
Set the XLink targets a type-definition and requested to resolve that.
Definition index.hpp:417
alib::String HTMLAnchor
The HTML anchor hash. Set only with members.
Definition index.hpp:398
XLink target information for pages.
Definition target.hpp:307
alib::String Title
The title of the group.
Definition target.hpp:313
XLink target information for source files.
Definition target.hpp:271
XLink target information for C++ namespace- and member-functions.
Definition target.hpp:459
alib::String Qualifiers
Additional qualifiers like const or nothrow.
Definition target.hpp:467
XLink target information for C++ structs, classes and unions.
Definition target.hpp:343