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