Doxygen
Loading...
Searching...
No Matches
definition.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2023 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include <algorithm>
17#include <iterator>
18#include <unordered_map>
19#include <string>
20#include <ctype.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <assert.h>
24
25#include "anchor.h"
26#include "md5.h"
27#include "regex.h"
28#include "config.h"
29#include "definitionimpl.h"
30#include "doxygen.h"
31#include "language.h"
32#include "message.h"
33#include "portable.h"
34#include "outputlist.h"
35#include "code.h"
36#include "util.h"
37#include "groupdef.h"
38#include "pagedef.h"
39#include "section.h"
40#include "htags.h"
41#include "parserintf.h"
42#include "debug.h"
43#include "vhdldocgen.h"
44#include "memberlist.h"
45#include "namespacedef.h"
46#include "filedef.h"
47#include "dirdef.h"
48#include "pagedef.h"
49#include "reflist.h"
50#include "utf8.h"
51#include "indexlist.h"
52#include "fileinfo.h"
53
54//-----------------------------------------------------------------------------------------
55
56//! Helper class add copy/assignment support to std::unique_ptr by making a deep copy
57//! Note that T may not be a polymorphic type
58template<class T>
59class DeepCopyUniquePtr : public std::unique_ptr<T>
60{
61 public:
62 using std::unique_ptr<T>::unique_ptr;
64 : std::unique_ptr<T>(other ? new T(*other) : nullptr)
65 {
66 }
68 {
69 if (*this!=other) this->reset(other ? new T(*other) : nullptr);
70 return *this;
71 }
72 DeepCopyUniquePtr(DeepCopyUniquePtr &&other) : std::unique_ptr<T>(std::move(other)) {}
74 {
75 std::unique_ptr<T>::operator=(std::move(other));
76 return *this;
77 }
78 ~DeepCopyUniquePtr() = default;
79};
80
81//! Helper to create an object wrapped in a DeepCopyUniquePtr.
82template<typename T, typename... Args>
84{
85 return DeepCopyUniquePtr<T>(new T(std::forward<Args>(args)...));
86}
87
88/** Private data associated with a Symbol DefinitionImpl object. */
90{
91 public:
92 void init(const QCString &df, const QCString &n);
93 void setDefFileName(const QCString &df);
94
95 Definition *def = nullptr;
96
97 SectionRefs sectionRefs;
98
99 std::unordered_map<std::string,MemberDef *> sourceRefByDict;
100 std::unordered_map<std::string,MemberDef *> sourceRefsDict;
102 GroupList partOfGroups;
103
104 DeepCopyUniquePtr<DocInfo> details; // not exported
105 DeepCopyUniquePtr<DocInfo> inbodyDocs; // not exported
106 DeepCopyUniquePtr<BriefInfo> brief; // not exported
107 DeepCopyUniquePtr<BodyInfo> body; // not exported
110
111 QCString localName; // local (unqualified) name of the definition
112 // in the future m_name should become m_localName
114 QCString ref; // reference to external documentation
115
116 bool hidden = FALSE;
120
121 Definition *outerScope = nullptr; // not owner
122
123 // where the item was defined
124 QCString defFileName;
125 QCString defFileExt;
126
128
129 QCString id; // clang unique id
130
131 QCString name;
133 QCString symbolName;
136
137 MemberVector referencesMembers; // cache for getReferencesMembers()
138 MemberVector referencedByMembers; // cache for getReferencedByMembers()
139};
140
141
143{
144 defFileName = df;
145 int lastDot = defFileName.findRev('.');
146 if (lastDot!=-1)
147 {
148 defFileExt = defFileName.mid(lastDot);
149 }
150}
151
152void DefinitionImpl::IMPL::init(const QCString &df, const QCString &n)
153{
154 setDefFileName(df);
155 QCString lname = n;
156 if (lname!="<globalScope>")
157 {
158 //extractNamespaceName(m_name,m_localName,ns);
160 }
161 else
162 {
163 localName=n;
164 }
165 //printf("localName=%s\n",qPrint(localName));
166
167 brief.reset();
168 details.reset();
169 body.reset();
170 inbodyDocs.reset();
171 sourceRefByDict.clear();
172 sourceRefsDict.clear();
173 outerScope = Doxygen::globalScope;
174 hidden = FALSE;
177 lang = SrcLangExt::Unknown;
178}
179
180void DefinitionImpl::setDefFile(const QCString &df,int defLine,int defCol)
181{
182 m_impl->setDefFileName(df);
183 m_impl->defLine = defLine;
184 m_impl->defColumn = defCol;
185}
186
187//-----------------------------------------------------------------------------------------
188
189static bool matchExcludedSymbols(const QCString &name)
190{
191 const StringVector &exclSyms = Config_getList(EXCLUDE_SYMBOLS);
192 if (exclSyms.empty()) return FALSE; // nothing specified
193 std::string symName = name.str();
194 for (const auto &pat : exclSyms)
195 {
196 QCString pattern = pat.c_str();
197 bool forceStart=FALSE;
198 bool forceEnd=FALSE;
199 if (pattern.at(0)=='^')
200 pattern=pattern.mid(1),forceStart=TRUE;
201 if (pattern.at(pattern.length()-1)=='$')
202 pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
203 if (pattern.find('*')!=-1) // wildcard mode
204 {
205 const reg::Ex re(substitute(pattern,"*",".*").str());
206 reg::Match match;
207 if (reg::search(symName,match,re)) // wildcard match
208 {
209 size_t ui = match.position();
210 size_t pl = match.length();
211 size_t sl = symName.length();
212 if ((ui==0 || pattern.at(0)=='*' || (!isId(symName.at(ui-1)) && !forceStart)) &&
213 (ui+pl==sl || pattern.at(pattern.length()-1)=='*' || (!isId(symName.at(ui+pl)) && !forceEnd))
214 )
215 {
216 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
217 return TRUE;
218 }
219 }
220 }
221 else if (!pattern.isEmpty()) // match words
222 {
223 size_t i = symName.find(pattern.str());
224 if (i!=std::string::npos) // we have a match!
225 {
226 size_t ui=i;
227 size_t pl=pattern.length();
228 size_t sl=symName.length();
229 // check if it is a whole word match
230 if ((ui==0 || (!isId(symName.at(ui-1)) && !forceStart)) &&
231 (ui+pl==sl || (!isId(symName.at(ui+pl)) && !forceEnd))
232 )
233 {
234 //printf("--> name=%s pattern=%s match at %d\n",qPrint(symName),qPrint(pattern),i);
235 return TRUE;
236 }
237 }
238 }
239 }
240 //printf("--> name=%s: no match\n",name);
241 return FALSE;
242}
243
244static void addToMap(const QCString &name,Definition *d)
245{
246 bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
247 QCString symbolName = name;
249 if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
250 if (!symbolName.isEmpty())
251 {
252 //printf("adding symbol %s\n",qPrint(symbolName));
254
256 }
257}
258
259static void removeFromMap(const QCString &name,Definition *d)
260{
262}
263
265 const QCString &df,int dl,int dc,
266 const QCString &name,const char *b,
267 const char *d,bool isSymbol)
268 : m_impl(std::make_unique<DefinitionImpl::IMPL>())
269{
270 setName(name);
271 m_impl->def = def;
272 m_impl->defLine = dl;
273 m_impl->defColumn = dc;
274 m_impl->init(df,name);
275 m_impl->isSymbol = isSymbol;
276 if (isSymbol) addToMap(name,def);
277 _setBriefDescription(b,df,dl);
280 {
281 m_impl->hidden = TRUE;
282 }
283}
284
286 : m_impl(std::make_unique<DefinitionImpl::IMPL>(*d.m_impl))
287{
288 if (m_impl->isSymbol) addToMap(m_impl->name,m_impl->def);
289}
290
292{
293 if (this!=&other)
294 {
295 m_impl = std::make_unique<DefinitionImpl::IMPL>(*other.m_impl);
296 }
297 return *this;
298}
299
301{
302 if (m_impl->isSymbol)
303 {
304 removeFromMap(m_impl->symbolName,m_impl->def);
305 }
306}
307
309{
310 if (name.isEmpty()) return;
311 m_impl->name = name;
312 m_impl->isAnonymous = m_impl->name.isEmpty() ||
313 m_impl->name.at(0)=='@' ||
314 m_impl->name.find("::@")!=-1;
315}
316
318{
319 if (id.isEmpty()) return;
320 m_impl->id = id;
322 {
323 //printf("DefinitionImpl::setId '%s'->'%s'\n",id,qPrint(m_impl->name));
324 Doxygen::clangUsrMap->emplace(id.str(),m_impl->def);
325 }
326}
327
329{
330 return m_impl->id;
331}
332
333void DefinitionImpl::addSectionsToDefinition(const std::vector<const SectionInfo*> &anchorList)
334{
335 //printf("%s: addSectionsToDefinition(%d)\n",qPrint(name()),anchorList->count());
336 for (const SectionInfo *si : anchorList)
337 {
338 //printf("Add section '%s' to definition '%s'\n",
339 // qPrint(si->label()),qPrint(name()));
340 SectionManager &sm = SectionManager::instance();
341 SectionInfo *gsi=sm.find(si->label());
342 //printf("===== label=%s gsi=%p\n",qPrint(si->label),gsi);
343 if (gsi==nullptr)
344 {
345 gsi = sm.add(*si);
346 }
347 if (m_impl->sectionRefs.find(gsi->label())==nullptr)
348 {
349 m_impl->sectionRefs.add(gsi);
350 gsi->setDefinition(m_impl->def);
351 }
352 }
353}
354
356{
357 //printf("DefinitionImpl::hasSections(%s) #sections=%d\n",qPrint(name()),
358 // m_impl->sectionRefs.size());
359 if (m_impl->sectionRefs.empty()) return FALSE;
360 for (const SectionInfo *si : m_impl->sectionRefs)
361 {
362 if (si->type().isSection())
363 {
364 return TRUE;
365 }
366 }
367 return FALSE;
368}
369
371{
372 if (!m_impl->sectionRefs.empty())
373 {
374 //printf("%s: writeDocAnchorsToTagFile(%d)\n",qPrint(name()),m_impl->sectionRef.size());
375 for (const SectionInfo *si : m_impl->sectionRefs)
376 {
377 if (!si->generated() && si->ref().isEmpty() && !AnchorGenerator::instance().isGenerated(si->label().str()))
378 {
379 //printf("write an entry!\n");
380 if (m_impl->def->definitionType()==Definition::TypeMember) tagFile << " ";
381 QCString fn = si->fileName();
383 tagFile << " <docanchor file=\"" << fn << "\"";
384 if (!si->title().isEmpty())
385 {
386 tagFile << " title=\"" << convertToXML(si->title()) << "\"";
387 }
388 tagFile << ">" << si->label() << "</docanchor>\n";
389 }
390 }
391 }
392}
393
395{
396 uint8_t md5_sig[16];
397 char sigStr[33];
398 // to avoid mismatches due to differences in indenting, we first remove
399 // double whitespaces...
400 QCString docStr = doc.simplifyWhiteSpace();
401 MD5Buffer(docStr.data(),static_cast<unsigned int>(docStr.length()),md5_sig);
402 MD5SigToString(md5_sig,sigStr);
403 //printf("%s:_docsAlreadyAdded doc='%s' sig='%s' docSigs='%s'\n",
404 // qPrint(name()),qPrint(doc),qPrint(sigStr),qPrint(sigList));
405 if (sigList.find(sigStr)==-1) // new docs, add signature to prevent re-adding it
406 {
407 sigList+=QCString(":")+sigStr;
408 return FALSE;
409 }
410 else
411 {
412 return TRUE;
413 }
414}
415
417 bool stripWhiteSpace,bool atTop)
418{
419 //printf("%s::setDocumentation(%s,%s,%d,%d)\n",qPrint(name()),d,docFile,docLine,stripWhiteSpace);
420 if (d.isEmpty()) return;
421 QCString doc = d;
422 if (stripWhiteSpace)
423 {
425 }
426 else // don't strip whitespace
427 {
428 doc=d;
429 }
430 if (!_docsAlreadyAdded(doc,m_impl->docSignatures))
431 {
432 //printf("setting docs for %s: '%s'\n",qPrint(name()),qPrint(m_doc));
433 if (!m_impl->details)
434 {
436 }
437 if (m_impl->details->doc.isEmpty()) // fresh detailed description
438 {
439 m_impl->details->doc = doc;
440 }
441 else if (atTop) // another detailed description, append it to the start
442 {
443 m_impl->details->doc = doc+"\n\n"+m_impl->details->doc;
444 }
445 else // another detailed description, append it to the end
446 {
447 m_impl->details->doc += "\n\n"+doc;
448 }
449 if (docLine!=-1) // store location if valid
450 {
451 m_impl->details->file = docFile;
452 m_impl->details->line = docLine;
453 }
454 else
455 {
456 m_impl->details->file = docFile;
457 m_impl->details->line = 1;
458 }
459 }
460}
461
467
469{
470 QCString brief = b;
471 brief = brief.stripWhiteSpace();
473 brief = brief.stripWhiteSpace();
474 if (brief.isEmpty()) return;
475 size_t bl = brief.length();
476 if (bl>0)
477 {
478 if (!theTranslator || theTranslator->needsPunctuation()) // add punctuation if needed
479 {
480 int c = brief.at(bl-1);
481 switch(c)
482 {
483 case '.': case '!': case '?': case '>': case ':': case ')': break;
484 default:
485 if (isUTF8CharUpperCase(brief.str(),0) && !lastUTF8CharIsMultibyte(brief.str())) brief+='.';
486 break;
487 }
488 }
489 }
490
491 if (!_docsAlreadyAdded(brief,m_impl->briefSignatures))
492 {
493 if (m_impl->brief && !m_impl->brief->doc.isEmpty())
494 {
495 //printf("adding to details\n");
497 }
498 else
499 {
500 //fprintf(stderr,"DefinitionImpl::setBriefDescription(%s,%s,%d)\n",b,briefFile,briefLine);
501 if (!m_impl->brief)
502 {
504 }
505 m_impl->brief->doc=brief;
506 if (briefLine!=-1)
507 {
508 m_impl->brief->file = briefFile;
509 m_impl->brief->line = briefLine;
510 }
511 else
512 {
513 m_impl->brief->file = briefFile;
514 m_impl->brief->line = 1;
515 }
516 }
517 }
518 else
519 {
520 //printf("do nothing!\n");
521 }
522}
523
529
531{
532 if (!m_impl->inbodyDocs)
533 {
534 m_impl->inbodyDocs = make_DeepCopyUnique<DocInfo>();
535 }
536 if (m_impl->inbodyDocs->doc.isEmpty()) // fresh inbody docs
537 {
538 m_impl->inbodyDocs->doc = doc;
539 m_impl->inbodyDocs->file = inbodyFile;
540 m_impl->inbodyDocs->line = inbodyLine;
541 }
542 else // another inbody documentation fragment, append this to the end
543 {
544 m_impl->inbodyDocs->doc += QCString("\n\n")+doc;
545 }
546}
547
553
554//---------------------------------------
555
556/*! Cache for storing the result of filtering a file */
558{
559 private:
561 {
562 size_t filePos;
563 size_t fileSize;
564 };
565 using LineOffsets = std::vector<size_t>;
566
567 public:
568 static FilterCache &instance();
569
570 //! collects the part of file \a fileName starting at \a startLine and ending at \a endLine into
571 //! buffer \a str. Applies filtering if FILTER_SOURCE_FILES is enabled and the file extension
572 //! matches a filter. Caches file information so that subsequent extraction of blocks from
573 //! the same file can be performed efficiently
574 bool getFileContents(const QCString &fileName,size_t startLine,size_t endLine, std::string &str)
575 {
576 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
577 QCString filter = getFileFilter(fileName,TRUE);
578 bool usePipe = !filter.isEmpty() && filterSourceFiles;
579 return usePipe ? getFileContentsPipe(fileName,filter,startLine,endLine,str)
580 : getFileContentsDisk(fileName,startLine,endLine,str);
581 }
582 private:
583 bool getFileContentsPipe(const QCString &fileName,const QCString &filter,
584 size_t startLine,size_t endLine,std::string &str)
585 {
586 std::unique_lock<std::mutex> lock(m_mutex);
587 auto it = m_cache.find(fileName.str());
588 if (it!=m_cache.end()) // cache hit: reuse stored result
589 {
590 lock.unlock();
591 auto item = it->second;
592 //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
593 // file already processed, get the results after filtering from the tmp file
594 Debug::print(Debug::FilterOutput,0,"Reusing filter result for %s from %s at offset=%lld size=%zu\n",
595 qPrint(fileName),qPrint(Doxygen::filterDBFileName),item.filePos,item.fileSize);
596
597 auto it_off = m_lineOffsets.find(fileName.str());
598 assert(it_off!=m_lineOffsets.end());
599 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it_off->second,startLine,endLine);
600 //printf("%s: existing file [%zu-%zu]->[%zu-%zu] size=%zu\n",
601 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
603 item.filePos+startLineOffset, fragmentSize);
604 return true;
605 }
606 else // cache miss: filter active but file not previously processed
607 {
608 //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
609 // filter file
610 QCString cmd=filter+" \""+fileName+"\"";
611 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",qPrint(cmd));
612 FILE *f = Portable::popen(cmd,"r");
613 if (f==nullptr)
614 {
615 // handle error
616 err("Error opening filter pipe command '%s'\n",qPrint(cmd));
617 return false;
618 }
620 FilterCacheItem item;
621 item.filePos = m_endPos;
622 if (bf==nullptr)
623 {
624 // handle error
625 err("Error opening filter database file %s\n",qPrint(Doxygen::filterDBFileName));
627 return false;
628 }
629 // append the filtered output to the database file
630 size_t size=0;
631 while (!feof(f))
632 {
633 const int blockSize = 4096;
634 char buf[blockSize];
635 size_t bytesRead = fread(buf,1,blockSize,f);
636 size_t bytesWritten = fwrite(buf,1,bytesRead,bf);
637 if (bytesRead!=bytesWritten)
638 {
639 // handle error
640 err("Failed to write to filter database %s. Wrote %zu out of %zu bytes\n",
641 qPrint(Doxygen::filterDBFileName),bytesWritten,bytesRead);
643 fclose(bf);
644 return false;
645 }
646 size+=bytesWritten;
647 str+=std::string_view(buf,bytesWritten);
648 }
649 item.fileSize = size;
650 // add location entry to the dictionary
651 m_cache.emplace(fileName.str(),item);
652 Debug::print(Debug::FilterOutput,0,"Storing new filter result for %s in %s at offset=%lld size=%zu\n",
654 // update end of file position
655 m_endPos += size;
657 fclose(bf);
658
659 // shrink buffer to [startLine..endLine] part
660 shrinkBuffer(str,fileName,startLine,endLine);
661 }
662 return true;
663 }
664
665 //! reads the fragment start at \a startLine and ending at \a endLine from file \a fileName
666 //! into buffer \a str
667 bool getFileContentsDisk(const QCString &fileName,size_t startLine,size_t endLine,std::string &str)
668 {
669 std::unique_lock<std::mutex> lock(m_mutex);
670 // normal file
671 //printf("getFileContents(%s): no filter\n",qPrint(fileName));
672 auto it = m_lineOffsets.find(fileName.str());
673 if (it == m_lineOffsets.end()) // new file
674 {
675 // read file completely into str buffer
676 readFragmentFromFile(str,fileName,0);
677 // shrink buffer to [startLine..endLine] part
678 shrinkBuffer(str,fileName,startLine,endLine);
679 }
680 else // file already processed before
681 {
682 lock.unlock();
683 auto [ startLineOffset, fragmentSize] = getFragmentLocation(it->second,startLine,endLine);
684 //printf("%s: existing file [%zu-%zu] -> start=%zu size=%zu\n",
685 // qPrint(fileName),startLine,endLine,startLineOffset,fragmentSize);
686 readFragmentFromFile(str,fileName,startLineOffset,fragmentSize);
687 }
688 return true;
689 }
690
691 //! computes the starting offset for each line for file \a fileName, whose contents should
692 //! already be stored in buffer \a str.
693 void compileLineOffsets(const QCString &fileName,const std::string &str)
694 {
695 // line 1 (index 0) is at offset 0
696 auto it = m_lineOffsets.emplace(fileName.data(),LineOffsets{0}).first;
697 const char *p=str.data();
698 while (*p)
699 {
700 char c=0;
701 while ((c=*p)!='\n' && c!=0) p++; // search until end of the line
702 if (c!=0) p++;
703 it->second.push_back(p-str.data());
704 }
705 }
706
707 //! Returns the byte offset and size within a file of a fragment given the array of
708 //! line offsets and the start and end line of the fragment.
709 auto getFragmentLocation(const LineOffsets &lineOffsets,
710 size_t startLine,size_t endLine) -> std::tuple<size_t,size_t>
711 {
712 assert(startLine > 0);
713 assert(startLine <= endLine);
714 const size_t startLineOffset = lineOffsets[std::min(startLine-1,lineOffsets.size()-1)];
715 const size_t endLineOffset = lineOffsets[std::min(endLine, lineOffsets.size()-1)];
716 assert(startLineOffset <= endLineOffset);
717 const size_t fragmentSize = endLineOffset-startLineOffset;
718 return std::tie(startLineOffset,fragmentSize);
719 };
720
721 //! Shrinks buffer \a str which should hold the contents of \a fileName to the
722 //! fragment starting a line \a startLine and ending at line \a endLine
723 void shrinkBuffer(std::string &str,const QCString &fileName,size_t startLine,size_t endLine)
724 {
725 // compute offsets from start for each line
726 compileLineOffsets(fileName,str);
727 auto it = m_lineOffsets.find(fileName.str());
728 assert(it!=m_lineOffsets.end());
729 const LineOffsets &lineOffsets = it->second;
730 auto [ startLineOffset, fragmentSize] = getFragmentLocation(lineOffsets,startLine,endLine);
731 //printf("%s: new file [%zu-%zu]->[%zu-%zu] size=%zu\n",
732 // qPrint(fileName),startLine,endLine,startLineOffset,endLineOffset,fragmentSize);
733 str.erase(0,startLineOffset);
734 str.resize(fragmentSize);
735 }
736
737 //! Reads the fragment start at byte offset \a startOffset of file \a fileName into buffer \a str.
738 //! Result will be a null terminated. If size==0 the whole file will be read and startOffset is ignored.
739 //! If size>0, size bytes will be read.
740 void readFragmentFromFile(std::string &str,const QCString &fileName,size_t startOffset,size_t size=0)
741 {
742 std::ifstream ifs = Portable::openInputStream(fileName,true,true);
743 if (size==0) { startOffset=0; size = static_cast<size_t>(ifs.tellg()); }
744 ifs.seekg(startOffset, std::ios::beg);
745 str.resize(size);
746 ifs.read(str.data(), size);
747 }
748
750 std::unordered_map<std::string,FilterCacheItem> m_cache;
751 std::unordered_map<std::string,LineOffsets> m_lineOffsets;
752 std::mutex m_mutex;
753 size_t m_endPos;
754};
755
757{
758 static FilterCache theInstance;
759 return theInstance;
760}
761
762//-----------------------------------------
763
764
765/*! Reads a fragment of code from file \a fileName starting at
766 * line \a startLine and ending at line \a endLine (inclusive). The fragment is
767 * stored in \a result. If FALSE is returned the code fragment could not be
768 * found.
769 *
770 * The file is scanned for a opening bracket ('{') from \a startLine onward
771 * The line actually containing the bracket is returned via startLine.
772 * The file is scanned for a closing bracket ('}') from \a endLine backward.
773 * The line actually containing the bracket is returned via endLine.
774 * Note that for VHDL code the bracket search is not done.
775 */
776bool readCodeFragment(const QCString &fileName,bool isMacro,
777 int &startLine,int &endLine,QCString &result)
778{
779 bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
780 QCString filter = getFileFilter(fileName,TRUE);
781 bool usePipe = !filter.isEmpty() && filterSourceFiles;
782 int tabSize = Config_getInt(TAB_SIZE);
783 SrcLangExt lang = getLanguageFromFileName(fileName);
784 const int blockSize = 4096;
785 std::string str;
787 static_cast<size_t>(std::max(1,startLine)),
788 static_cast<size_t>(std::max({1,startLine,endLine})),str);
789 //printf("readCodeFragment(%s,startLine=%d,endLine=%d)=\n[[[\n%s]]]\n",qPrint(fileName),startLine,endLine,qPrint(str));
790
791 bool found = lang==SrcLangExt::VHDL ||
792 lang==SrcLangExt::Python ||
793 lang==SrcLangExt::Fortran ||
794 isMacro;
795 // for VHDL, Python, and Fortran no bracket search is possible
796 char *p=str.data();
797 if (p && *p)
798 {
799 char c=0;
800 int col=0;
801 int lineNr=startLine;
802 // skip until the opening bracket or lonely : is found
803 char cn=0;
804 while (*p && !found)
805 {
806 int pc=0;
807 while ((c=*p++)!='{' && c!=':' && c!=0)
808 {
809 //printf("parsing char '%c'\n",c);
810 if (c=='\n')
811 {
812 lineNr++,col=0;
813 }
814 else if (c=='\t')
815 {
816 col+=tabSize - (col%tabSize);
817 }
818 else if (pc=='/' && c=='/') // skip single line comment
819 {
820 while ((c=*p++)!='\n' && c!=0);
821 if (c=='\n') lineNr++,col=0;
822 }
823 else if (pc=='/' && c=='*') // skip C style comment
824 {
825 while (((c=*p++)!='/' || pc!='*') && c!=0)
826 {
827 if (c=='\n') lineNr++,col=0;
828 pc=c;
829 }
830 }
831 else
832 {
833 col++;
834 }
835 pc = c;
836 }
837 if (c==':')
838 {
839 cn=*p++;
840 if (cn!=':') found=TRUE;
841 }
842 else if (c=='{')
843 {
844 found=TRUE;
845 }
846 else if (c==0)
847 {
848 break;
849 }
850 }
851 //printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
852 if (found)
853 {
854 // For code with more than one line,
855 // fill the line with spaces until we are at the right column
856 // so that the opening brace lines up with the closing brace
857 if (endLine!=startLine)
858 {
859 QCString spaces;
860 spaces.fill(' ',col);
861 result+=spaces;
862 }
863 // copy until end of line
864 if (c) result+=c;
865 startLine=lineNr;
866 if (c==':')
867 {
868 result+=cn;
869 if (cn=='\n') lineNr++;
870 }
871 char lineStr[blockSize];
872 do
873 {
874 //printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
875 int size_read=0;
876 do
877 {
878 // read up to blockSize-1 non-zero characters
879 int i=0;
880 while ((c=*p) && i<blockSize-1)
881 {
882 lineStr[i++]=c;
883 p++;
884 if (c=='\n') break; // stop at end of the line
885 }
886 lineStr[i]=0;
887 size_read=i;
888 result+=lineStr; // append line to the output
889 } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
890 lineNr++;
891 } while (*p);
892
893 // strip stuff after closing bracket
894 int newLineIndex = result.findRev('\n');
895 int braceIndex = result.findRev('}');
896 if (braceIndex > newLineIndex)
897 {
898 result.resize(static_cast<size_t>(braceIndex+1));
899 }
900 endLine=lineNr-1;
901 }
902 if (usePipe)
903 {
904 Debug::print(Debug::FilterOutput, 0, "Filter output\n");
905 Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",qPrint(result));
906 }
907 }
908 QCString encoding = getEncoding(FileInfo(fileName.str()));
909 if (encoding!="UTF-8")
910 {
911 std::string encBuf = result.str();
912 bool ok = transcodeCharacterStringToUTF8(encBuf,encoding.data());
913 if (ok)
914 {
915 result = QCString(encBuf);
916 }
917 else
918 {
919 err("failed to transcode characters in code fragment in file %s lines %d to %d, from input encoding %s to UTF-8\n",
920 qPrint(fileName),startLine,endLine,qPrint(encoding));
921
922 }
923 }
924 if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
925 //printf("readCodeFragment(%d-%d)=%s\n",startLine,endLine,qPrint(result));
926 return found;
927}
928
930{
931 ASSERT(m_impl->def->definitionType()!=Definition::TypeFile); // file overloads this method
932 QCString fn;
933 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
934 if (sourceBrowser &&
935 m_impl->body && m_impl->body->startLine!=-1 && m_impl->body->fileDef)
936 {
937 fn = m_impl->body->fileDef->getSourceFileBase();
938 }
939 return fn;
940}
941
943{
944 const int maxAnchorStrLen = 20;
945 char anchorStr[maxAnchorStrLen];
946 anchorStr[0]='\0';
947 if (m_impl->body && m_impl->body->startLine!=-1)
948 {
949 if (Htags::useHtags)
950 {
951 qsnprintf(anchorStr,maxAnchorStrLen,"L%d",m_impl->body->defLine);
952 }
953 else
954 {
955 qsnprintf(anchorStr,maxAnchorStrLen,"l%05d",m_impl->body->defLine);
956 }
957 }
958 return anchorStr;
959}
960
961/*! Write a reference to the source code defining this definition */
963{
964 //printf("DefinitionImpl::writeSourceRef %d %p\n",bodyLine,bodyDef);
965 QCString fn = getSourceFileBase();
966 if (!fn.isEmpty())
967 {
968 QCString refText = theTranslator->trDefinedAtLineInSourceFile();
969 int lineMarkerPos = refText.find("@0");
970 int fileMarkerPos = refText.find("@1");
971 if (lineMarkerPos!=-1 && fileMarkerPos!=-1) // should always pass this.
972 {
973 QCString lineStr;
974 lineStr.sprintf("%d",m_impl->body->defLine);
975 QCString anchorStr = getSourceAnchor();
976 ol.startParagraph("definition");
977 if (lineMarkerPos<fileMarkerPos) // line marker before file marker
978 {
979 // write text left from linePos marker
980 ol.parseText(refText.left(lineMarkerPos));
981 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
982 // write text between markers
983 ol.parseText(refText.mid(lineMarkerPos+2,fileMarkerPos-lineMarkerPos-2));
984 // write file link
985 ol.writeObjectLink(QCString(),fn,QCString(),m_impl->body->fileDef->name());
986 // write text right from file marker
987 ol.parseText(refText.right(refText.length()-static_cast<size_t>(fileMarkerPos)-2));
988 }
989 else // file marker before line marker
990 {
991 // write text left from file marker
992 ol.parseText(refText.left(fileMarkerPos));
993 // write file link
994 ol.writeObjectLink(QCString(),fn,QCString(),m_impl->body->fileDef->name());
995 // write text between markers
996 ol.parseText(refText.mid(fileMarkerPos+2,lineMarkerPos-fileMarkerPos-2));
997 // write line link
998 ol.writeObjectLink(QCString(),fn,anchorStr,lineStr);
999 // write text right from linePos marker
1000 ol.parseText(refText.right(refText.length()-static_cast<size_t>(lineMarkerPos)-2));
1001 }
1002 ol.endParagraph();
1003 }
1004 else
1005 {
1006 err("translation error: invalid markers in trDefinedAtLineInSourceFile()\n");
1007 }
1008 }
1009}
1010
1011void DefinitionImpl::setBodySegment(int defLine, int bls,int ble)
1012{
1013 if (!m_impl->body) m_impl->body = make_DeepCopyUnique<BodyInfo>();
1014 m_impl->body->defLine = defLine;
1015 m_impl->body->startLine = bls;
1016 m_impl->body->endLine = ble;
1017}
1018
1020{
1021 if (!m_impl->body) m_impl->body = make_DeepCopyUnique<BodyInfo>();
1022 m_impl->body->fileDef=fd;
1023}
1024
1026{
1027 return m_impl->body && m_impl->body->startLine!=-1 &&
1028 m_impl->body->endLine>=m_impl->body->startLine &&
1029 m_impl->body->fileDef;
1030}
1031
1032/*! Write code of this definition into the documentation */
1034{
1035 const MemberDef *thisMd = nullptr;
1036 if (m_impl->def->definitionType()==Definition::TypeMember)
1037 {
1038 thisMd = toMemberDef(m_impl->def);
1039 }
1040 bool inlineSources = thisMd && thisMd->hasInlineSource();
1041 //printf("Source Fragment %s: %d-%d\n",qPrint(name()),
1042 // m_impl->body->startLine,m_impl->body->endLine);
1043 if (inlineSources && hasSources())
1044 {
1045 ol.pushGeneratorState();
1046 QCString codeFragment;
1047 bool isMacro = thisMd && thisMd->memberType()==MemberType::Define;
1048 int actualStart=m_impl->body->startLine,actualEnd=m_impl->body->endLine;
1049 if (readCodeFragment(m_impl->body->fileDef->absFilePath(),isMacro,
1050 actualStart,actualEnd,codeFragment)
1051 )
1052 {
1053 //printf("Adding code fragment '%s' ext='%s' range=%d-%d\n",
1054 // qPrint(codeFragment),qPrint(m_impl->defFileExt),actualStart,actualEnd);
1055 auto intf = Doxygen::parserManager->getCodeParser(m_impl->defFileExt);
1056 intf->resetCodeParserState();
1057 //printf("Read:\n'%s'\n\n",qPrint(codeFragment));
1058
1059 auto &codeOL = ol.codeGenerators();
1060 codeOL.startCodeFragment("DoxyCode");
1061 intf->parseCode(codeOL, // codeOutIntf
1062 scopeName, // scope
1063 codeFragment, // input
1064 m_impl->lang, // lang
1065 Config_getBool(STRIP_CODE_COMMENTS),
1066 FALSE, // isExample
1067 QCString(), // exampleName
1068 m_impl->body->fileDef, // fileDef
1069 actualStart, // startLine
1070 actualEnd, // endLine
1071 TRUE, // inlineFragment
1072 thisMd, // memberDef
1073 TRUE // show line numbers
1074 );
1075 codeOL.endCodeFragment("DoxyCode");
1076 }
1077 ol.popGeneratorState();
1078 }
1079}
1080
1081static inline MemberVector refMapToVector(const std::unordered_map<std::string,MemberDef *> &map)
1082{
1083 // convert map to a vector of values
1084 MemberVector result;
1085 std::transform(map.begin(),map.end(), // iterate over map
1086 std::back_inserter(result), // add results to vector
1087 [](const auto &item)
1088 { return item.second; } // extract value to add from map Key,Value pair
1089 );
1090 // and sort it
1091 std::stable_sort(result.begin(),result.end(),
1092 [](const auto &m1,const auto &m2) { return genericCompareMembers(m1,m2)<0; });
1093 return result;
1094}
1095
1096/*! Write a reference to the source code fragments in which this
1097 * definition is used.
1098 */
1100 const QCString &text,const std::unordered_map<std::string,MemberDef *> &membersMap,
1101 bool /*funcOnly*/) const
1102{
1103 if (!membersMap.empty())
1104 {
1105 auto members = refMapToVector(membersMap);
1106
1107 auto replaceFunc = [this,&members,scopeName,&ol](size_t entryIndex)
1108 {
1109 bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1110 bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
1111 const MemberDef *md=members[entryIndex];
1112 if (md)
1113 {
1114 QCString scope=md->getScopeString();
1115 QCString name=md->name();
1116 //printf("class=%p scope=%s scopeName=%s\n",md->getClassDef(),qPrint(scope),scopeName);
1117 if (!scope.isEmpty() && scope!=scopeName)
1118 {
1119 name.prepend(scope+getLanguageSpecificSeparator(m_impl->lang));
1120 }
1121 if (!md->isObjCMethod() &&
1122 (md->isFunction() || md->isSlot() ||
1123 md->isPrototype() || md->isSignal()
1124 )
1125 )
1126 {
1127 name+="()";
1128 }
1129 if (sourceBrowser &&
1130 !(md->isLinkable() && !refLinkSource) &&
1131 md->getStartBodyLine()!=-1 &&
1132 md->getBodyDef()
1133 )
1134 {
1135 const int maxLineNrStr = 10;
1136 char anchorStr[maxLineNrStr];
1137 qsnprintf(anchorStr,maxLineNrStr,"l%05d",md->getStartBodyLine());
1138 //printf("Write object link to %s\n",qPrint(md->getBodyDef()->getSourceFileBase()));
1139 ol.writeObjectLink(QCString(),md->getBodyDef()->getSourceFileBase(),anchorStr,name);
1140 }
1141 else if (md->isLinkable())
1142 {
1144 md->getOutputFileBase(),
1145 md->anchor(),name);
1146 }
1147 else
1148 {
1149 ol.docify(name);
1150 }
1151 }
1152 };
1153
1154 ol.startParagraph("reference");
1155 ol.parseText(text);
1156 ol.docify(" ");
1157 writeMarkerList(ol,
1158 theTranslator->trWriteList(static_cast<int>(members.size())).str(),
1159 members.size(),
1160 replaceFunc);
1161 ol.writeString(".");
1162 ol.endParagraph();
1163
1164 }
1165}
1166
1168{
1169 _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
1170}
1171
1173{
1174 _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
1175}
1176
1178{
1179 return !m_impl->sourceRefByDict.empty();
1180}
1181
1183{
1184 return !m_impl->sourceRefsDict.empty();
1185}
1186
1188{
1189 bool extractAll = Config_getBool(EXTRACT_ALL);
1190 //bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
1191 bool hasDocs =
1192 (m_impl->details && !m_impl->details->doc.isEmpty()) || // has detailed docs
1193 (m_impl->brief && !m_impl->brief->doc.isEmpty()) || // has brief description
1194 (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty()) || // has inbody docs
1195 extractAll //|| // extract everything
1196 // (sourceBrowser && m_impl->body &&
1197 // m_impl->body->startLine!=-1 && m_impl->body->fileDef)
1198 ; // link to definition
1199 return hasDocs;
1200}
1201
1203{
1204 bool hasDocs =
1205 (m_impl->details && !m_impl->details->doc.isEmpty()) ||
1206 (m_impl->brief && !m_impl->brief->doc.isEmpty()) ||
1207 (m_impl->inbodyDocs && !m_impl->inbodyDocs->doc.isEmpty());
1208 return hasDocs;
1209}
1210
1212{
1213 if (md)
1214 {
1215 m_impl->sourceRefByDict.emplace(sourceRefName.str(),md);
1216 }
1217}
1218
1220{
1221 if (md)
1222 {
1223 m_impl->sourceRefsDict.emplace(sourceRefName.str(),md);
1224 }
1225}
1226
1228{
1229 return nullptr;
1230}
1231
1233{
1234 err("DefinitionImpl::addInnerCompound() called\n");
1235}
1236
1237static std::recursive_mutex g_qualifiedNameMutex;
1238
1240{
1241 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1242 if (!m_impl->qualifiedName.isEmpty())
1243 {
1244 return m_impl->qualifiedName;
1245 }
1246
1247 //printf("start %s::qualifiedName() localName=%s\n",qPrint(name()),qPrint(m_impl->localName));
1248 if (m_impl->outerScope==nullptr)
1249 {
1250 if (m_impl->localName=="<globalScope>")
1251 {
1252 return "";
1253 }
1254 else
1255 {
1256 return m_impl->localName;
1257 }
1258 }
1259
1260 if (m_impl->outerScope->name()=="<globalScope>")
1261 {
1262 m_impl->qualifiedName = m_impl->localName;
1263 }
1264 else
1265 {
1266 m_impl->qualifiedName = m_impl->outerScope->qualifiedName()+
1268 m_impl->localName;
1269 }
1270 //printf("end %s::qualifiedName()=%s\n",qPrint(name()),qPrint(m_impl->qualifiedName));
1271 //count--;
1272 return m_impl->qualifiedName;
1273}
1274
1276{
1277 std::lock_guard<std::recursive_mutex> lock(g_qualifiedNameMutex);
1278 //printf("%s::setOuterScope(%s)\n",qPrint(name()),d?qPrint(d->name()):"<none>");
1279 Definition *p = m_impl->outerScope;
1280 bool found=false;
1281 // make sure that we are not creating a recursive scope relation.
1282 while (p && !found)
1283 {
1284 found = (p==d);
1285 p = p->getOuterScope();
1286 }
1287 if (!found)
1288 {
1289 m_impl->qualifiedName.clear(); // flush cached scope name
1290 m_impl->outerScope = d;
1291 }
1292 m_impl->hidden = m_impl->hidden || d->isHidden();
1293 assert(m_impl->def!=m_impl->outerScope);
1294}
1295
1297{
1298 return m_impl->localName;
1299}
1300
1302{
1303 m_impl->partOfGroups.push_back(gd);
1304}
1305
1307{
1308 m_impl->xrefListItems.insert(m_impl->xrefListItems.end(), sli.cbegin(), sli.cend());
1309}
1310
1312{
1313 auto otherXrefList = d->xrefListItems();
1314
1315 // append vectors
1316 m_impl->xrefListItems.reserve(m_impl->xrefListItems.size()+otherXrefList.size());
1317 m_impl->xrefListItems.insert (m_impl->xrefListItems.end(),
1318 otherXrefList.begin(),otherXrefList.end());
1319
1320 // sort results on itemId
1321 std::stable_sort(m_impl->xrefListItems.begin(),m_impl->xrefListItems.end(),
1322 [](RefItem *left,RefItem *right)
1323 { return left->id() <right->id() ||
1324 (left->id()==right->id() &&
1325 left->list()->listName() < right->list()->listName());
1326 });
1327
1328 // filter out duplicates
1329 auto last = std::unique(m_impl->xrefListItems.begin(),m_impl->xrefListItems.end(),
1330 [](const RefItem *left,const RefItem *right)
1331 { return left->id()==right->id() &&
1332 left->list()->listName()==right->list()->listName();
1333 });
1334 m_impl->xrefListItems.erase(last, m_impl->xrefListItems.end());
1335}
1336
1338{
1339 for (const RefItem *item : m_impl->xrefListItems)
1340 {
1341 if (item->list()->listName()==listName)
1342 {
1343 return item->id();
1344 }
1345 }
1346 return -1;
1347}
1348
1350{
1351 return m_impl->xrefListItems;
1352}
1353
1355{
1356 QCString result;
1357 if (m_impl->outerScope && m_impl->outerScope!=Doxygen::globalScope)
1358 {
1359 result = m_impl->outerScope->pathFragment();
1360 }
1361 if (m_impl->def->isLinkable())
1362 {
1363 if (!result.isEmpty()) result+="/";
1364 if (m_impl->def->definitionType()==Definition::TypeGroup &&
1365 !toGroupDef(m_impl->def)->groupTitle().isEmpty())
1366 {
1367 result+=toGroupDef(m_impl->def)->groupTitle();
1368 }
1369 else if (m_impl->def->definitionType()==Definition::TypePage &&
1370 toPageDef(m_impl->def)->hasTitle())
1371 {
1372 result+=toPageDef(m_impl->def)->title();
1373 }
1374 else
1375 {
1376 result+=m_impl->localName;
1377 }
1378 }
1379 else
1380 {
1381 result+=m_impl->localName;
1382 }
1383 return result;
1384}
1385
1386//----------------------------------------------------------------------------------------
1387
1388// TODO: move to htmlgen
1389/*! Returns the string used in the footer for $navpath when
1390 * GENERATE_TREEVIEW is enabled
1391 */
1393{
1394 QCString result;
1395 Definition *outerScope = getOuterScope();
1396 QCString locName = localName();
1397 if (outerScope && outerScope!=Doxygen::globalScope)
1398 {
1399 result+=outerScope->navigationPathAsString();
1400 }
1401 else if (m_impl->def->definitionType()==Definition::TypeFile &&
1402 toFileDef(m_impl->def)->getDirDef())
1403 {
1404 result+=(toFileDef(m_impl->def))->getDirDef()->navigationPathAsString();
1405 }
1406 result+="<li class=\"navelem\">";
1407 if (m_impl->def->isLinkableInProject())
1408 {
1409 QCString fn = m_impl->def->getOutputFileBase();
1411 if (m_impl->def->definitionType()==Definition::TypeGroup &&
1412 !toGroupDef(m_impl->def)->groupTitle().isEmpty())
1413 {
1414 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1415 convertToHtml(toGroupDef(m_impl->def)->groupTitle())+"</a>";
1416 }
1417 else if (m_impl->def->definitionType()==Definition::TypePage &&
1418 toPageDef(m_impl->def)->hasTitle())
1419 {
1420 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1421 convertToHtml((toPageDef(m_impl->def))->title())+"</a>";
1422 }
1423 else if (m_impl->def->definitionType()==Definition::TypeClass)
1424 {
1425 QCString name = locName;
1426 if (name.endsWith("-p"))
1427 {
1428 name = name.left(name.length()-2);
1429 }
1430 result+="<a class=\"el\" href=\"$relpath^"+fn;
1431 if (!m_impl->def->anchor().isEmpty()) result+="#"+m_impl->def->anchor();
1432 result+="\">"+convertToHtml(name)+"</a>";
1433 }
1434 else
1435 {
1436 result+="<a class=\"el\" href=\"$relpath^"+fn+"\">"+
1437 convertToHtml(locName)+"</a>";
1438 }
1439 }
1440 else
1441 {
1442 result+="<b>"+convertToHtml(locName)+"</b>";
1443 }
1444 result+="</li>";
1445 return result;
1446}
1447
1448// TODO: move to htmlgen
1450{
1451 ol.pushGeneratorState();
1453
1454 QCString navPath;
1455 navPath += "<div id=\"nav-path\" class=\"navpath\">\n"
1456 " <ul>\n";
1457 navPath += navigationPathAsString();
1458 navPath += " </ul>\n"
1459 "</div>\n";
1460 ol.writeNavigationPath(navPath);
1461
1462 ol.popGeneratorState();
1463}
1464
1465void DefinitionImpl::writeToc(OutputList &ol, const LocalToc &localToc) const
1466{
1467 if (m_impl->sectionRefs.empty()) return;
1468 ol.writeLocalToc(m_impl->sectionRefs,localToc);
1469}
1470
1471//----------------------------------------------------------------------------------------
1472
1474{
1475 return m_impl->sectionRefs;
1476}
1477
1479{
1480 return m_impl->symbolName;
1481}
1482
1483//----------------------
1484
1486{
1487 return m_impl->details ? m_impl->details->doc : QCString("");
1488}
1489
1491{
1492 return m_impl->details ? m_impl->details->line : m_impl->brief ? m_impl->brief->line : 1;
1493}
1494
1496{
1497 if (m_impl->details && !m_impl->details->file.isEmpty()) return m_impl->details->file;
1498 else if (m_impl->brief && !m_impl->brief->file.isEmpty()) return m_impl->brief->file;
1499 else return "<" + m_impl->name + ">";
1500}
1501
1502//----------------------------------------------------------------------------
1503// strips w from s iff s starts with w
1504static bool stripWord(QCString &s,QCString w)
1505{
1506 bool success=FALSE;
1507 if (s.left(w.length())==w)
1508 {
1509 success=TRUE;
1510 s=s.right(s.length()-w.length());
1511 }
1512 return success;
1513}
1514
1515//----------------------------------------------------------------------------
1516// some quasi intelligent brief description abbreviator :^)
1517static QCString abbreviate(const QCString &s,const QCString &name)
1518{
1519 QCString scopelessName=name;
1520 int i=scopelessName.findRev("::");
1521 if (i!=-1) scopelessName=scopelessName.mid(i+2);
1522 QCString result=s;
1523 result=result.stripWhiteSpace();
1524 // strip trailing .
1525 if (!result.isEmpty() && result.at(result.length()-1)=='.')
1526 result=result.left(result.length()-1);
1527
1528 // strip any predefined prefix
1529 const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
1530 for (const auto &p : briefDescAbbrev)
1531 {
1532 QCString str = substitute(p.c_str(),"$name",scopelessName); // replace $name with entity name
1533 str += " ";
1534 stripWord(result,str);
1535 }
1536
1537 // capitalize first word
1538 if (!result.isEmpty())
1539 {
1540 char c=result[0];
1541 if (c>='a' && c<='z') c+='A'-'a';
1542 result[0]=c;
1543 }
1544 return result;
1545}
1546
1547
1548//----------------------
1549
1551{
1552 //printf("%s::briefDescription(%d)='%s'\n",qPrint(name()),abbr,m_impl->brief?qPrint(m_impl->brief->doc):"<none>");
1553 return m_impl->brief ?
1554 (abbr ? abbreviate(m_impl->brief->doc,m_impl->def->displayName()) : m_impl->brief->doc) :
1555 QCString("");
1556}
1557
1559{
1560 if (m_impl->brief && m_impl->brief->tooltip.isEmpty() && !m_impl->brief->doc.isEmpty())
1561 {
1562 const MemberDef *md = m_impl->def->definitionType()==Definition::TypeMember ? toMemberDef(m_impl->def) : nullptr;
1563 const Definition *scope = m_impl->def->definitionType()==Definition::TypeMember ? m_impl->def->getOuterScope() : m_impl->def;
1564 m_impl->brief->tooltip = parseCommentAsText(scope,md,
1565 m_impl->brief->doc, m_impl->brief->file, m_impl->brief->line);
1566 }
1567}
1568
1570{
1571 return m_impl->brief ? m_impl->brief->tooltip : QCString();
1572}
1573
1575{
1576 return m_impl->brief ? m_impl->brief->line : 1;
1577}
1578
1580{
1581 return m_impl->brief && !m_impl->brief->file.isEmpty() ? m_impl->brief->file : QCString("<"+m_impl->name+">");
1582}
1583
1584//----------------------
1585
1587{
1588 return m_impl->inbodyDocs ? m_impl->inbodyDocs->doc : QCString("");
1589}
1590
1592{
1593 return m_impl->inbodyDocs ? m_impl->inbodyDocs->line : 1;
1594}
1595
1597{
1598 return m_impl->inbodyDocs && !m_impl->inbodyDocs->file.isEmpty() ? m_impl->inbodyDocs->file : QCString("<"+m_impl->name+">");
1599}
1600
1601
1602//----------------------
1603
1605{
1606 return m_impl->defFileName;
1607}
1608
1610{
1611 return m_impl->defFileExt;
1612}
1613
1615{
1616 return m_impl->hidden;
1617}
1618
1620{
1621 return m_impl->def->isLinkableInProject() && !m_impl->hidden;
1622}
1623
1625{
1626 return m_impl->def->isLinkable() && !m_impl->hidden;
1627}
1628
1630{
1631 return m_impl->isArtificial;
1632}
1633
1635{
1636 return m_impl->isExported;
1637}
1638
1640{
1641 return m_impl->ref;
1642}
1643
1645{
1646 return !m_impl->ref.isEmpty();
1647}
1648
1650{
1651 return m_impl->body ? m_impl->body->defLine : -1;
1652}
1653
1655{
1656 return m_impl->body ? m_impl->body->startLine : -1;
1657}
1658
1660{
1661 return m_impl->body ? m_impl->body->endLine : -1;
1662}
1663
1665{
1666 return m_impl->body ? m_impl->body->fileDef : nullptr;
1667}
1668
1670{
1671 return m_impl->partOfGroups;
1672}
1673
1675{
1676 for (const auto &gd : partOfGroups())
1677 {
1678 if (gd->isLinkable()) return true;
1679 }
1680 return false;
1681}
1682
1684{
1685 return m_impl->outerScope;
1686}
1687
1688static std::mutex g_memberReferenceMutex;
1689
1691{
1692 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1693 if (m_impl->referencesMembers.empty() && !m_impl->sourceRefsDict.empty())
1694 {
1695 m_impl->referencesMembers = refMapToVector(m_impl->sourceRefsDict);
1696 }
1697 return m_impl->referencesMembers;
1698}
1699
1701{
1702 std::lock_guard<std::mutex> lock(g_memberReferenceMutex);
1703 if (m_impl->referencedByMembers.empty() && !m_impl->sourceRefByDict.empty())
1704 {
1705 m_impl->referencedByMembers = refMapToVector(m_impl->sourceRefByDict);
1706 }
1707 return m_impl->referencedByMembers;
1708}
1709
1711{
1712 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1713 if (defImpl)
1714 {
1715 for (const auto &kv : defImpl->m_impl->sourceRefsDict)
1716 {
1717 auto it = m_impl->sourceRefsDict.find(kv.first);
1718 if (it != m_impl->sourceRefsDict.end())
1719 {
1720 m_impl->sourceRefsDict.insert(kv);
1721 }
1722 }
1723 }
1724}
1725
1727{
1728 const DefinitionImpl *defImpl = other->toDefinitionImpl_();
1729 if (defImpl)
1730 {
1731 for (const auto &kv : defImpl->m_impl->sourceRefByDict)
1732 {
1733 auto it = m_impl->sourceRefByDict.find(kv.first);
1734 if (it != m_impl->sourceRefByDict.end())
1735 {
1736 m_impl->sourceRefByDict.emplace(kv.first,kv.second);
1737 }
1738 }
1739 }
1740}
1741
1742
1744{
1745 m_impl->ref=r;
1746}
1747
1749{
1750 return m_impl->lang;
1751}
1752
1754{
1755 m_impl->hidden = m_impl->hidden || b;
1756}
1757
1759{
1760 m_impl->isArtificial = b;
1761}
1762
1764{
1765 m_impl->isExported = b;
1766}
1767
1769{
1770 m_impl->localName=name;
1771}
1772
1774{
1775 m_impl->lang=lang;
1776}
1777
1778
1780{
1781 m_impl->symbolName=name;
1782}
1783
1785{
1786 return m_impl->symbolName;
1787}
1788
1790{
1791 bool briefMemberDesc = Config_getBool(BRIEF_MEMBER_DESC);
1792 return !briefDescription().isEmpty() && briefMemberDesc;
1793}
1794
1796{
1797 QCString ref = getReference();
1798 if (!ref.isEmpty())
1799 {
1800 auto it = Doxygen::tagDestinationMap.find(ref.str());
1802 {
1803 QCString result(it->second);
1804 size_t l = result.length();
1805 if (!relPath.isEmpty() && l>0 && result.at(0)=='.')
1806 { // relative path -> prepend relPath.
1807 result.prepend(relPath);
1808 l+=relPath.length();
1809 }
1810 if (l>0 && result.at(l-1)!='/') result+='/';
1811 return result;
1812 }
1813 }
1814 return relPath;
1815}
1816
1818{
1819 return m_impl->name;
1820}
1821
1823{
1824 return m_impl->isAnonymous;
1825}
1826
1828{
1829 return m_impl->defLine;
1830}
1831
1833{
1834 return m_impl->defColumn;
1835}
1836
1840
1844
1845//---------------------------------------------------------------------------------
1846
1848 : m_def(def), m_scope(scope), m_symbolName(alias->_symbolName())
1849{
1850}
1851
1855
1857{
1858 //printf("%s::addToMap(%s)\n",qPrint(name()),qPrint(alias->name()));
1860 if (m_scope==nullptr)
1861 {
1862 m_qualifiedName = m_def->localName();
1863 }
1864 else
1865 {
1866 m_qualifiedName = m_scope->qualifiedName()+
1867 getLanguageSpecificSeparator(m_scope->getLanguage())+
1868 m_def->localName();
1869 }
1870}
1871
1876
1881
1883{
1884 return m_qualifiedName;
1885}
1886
1887//---------------------------------------------------------------------------------
1888
1890{
1891 if (dm==nullptr) return nullptr;
1892 return dm->toDefinition_();
1893}
1894
1896{
1897 if (d==nullptr) return nullptr;
1898 return d->toDefinitionMutable_();
1899}
1900
bool isGenerated(const std::string &anchor) const
Returns true iff anchor is one of the generated anchors.
Definition anchor.cpp:128
static AnchorGenerator & instance()
Returns the singleton instance.
Definition anchor.cpp:38
@ FilterOutput
Definition debug.h:37
@ ExtCmd
Definition debug.h:35
static void print(DebugMask mask, int prio, const char *fmt,...)
Definition debug.cpp:81
Helper class add copy/assignment support to std::unique_ptr by making a deep copy Note that T may not...
DeepCopyUniquePtr & operator=(const DeepCopyUniquePtr &other)
~DeepCopyUniquePtr()=default
DeepCopyUniquePtr(const DeepCopyUniquePtr &other)
DeepCopyUniquePtr(DeepCopyUniquePtr &&other)
DeepCopyUniquePtr & operator=(DeepCopyUniquePtr &&other)
DefinitionAliasImpl(Definition *def, const Definition *scope, const Definition *alias)
const Definition * m_scope
const QCString & name() const
QCString qualifiedName() const
virtual ~DefinitionAliasImpl()
The common base class of all entity definitions found in the sources.
Definition definition.h:76
virtual const RefItemVector & xrefListItems() const =0
virtual QCString navigationPathAsString() const =0
virtual bool isLinkable() const =0
virtual QCString anchor() const =0
virtual DefinitionMutable * toDefinitionMutable_()=0
virtual const FileDef * getBodyDef() const =0
virtual bool isHidden() const =0
virtual QCString getReference() const =0
virtual void _setSymbolName(const QCString &name)=0
virtual QCString getSourceFileBase() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
virtual int getStartBodyLine() const =0
virtual const DefinitionImpl * toDefinitionImpl_() const =0
virtual const QCString & name() const =0
Private data associated with a Symbol DefinitionImpl object.
std::unordered_map< std::string, MemberDef * > sourceRefsDict
DeepCopyUniquePtr< BodyInfo > body
MemberVector referencedByMembers
DeepCopyUniquePtr< DocInfo > inbodyDocs
Definition * outerScope
DeepCopyUniquePtr< DocInfo > details
SectionRefs sectionRefs
std::unordered_map< std::string, MemberDef * > sourceRefByDict
void setDefFileName(const QCString &df)
DeepCopyUniquePtr< BriefInfo > brief
void init(const QCString &df, const QCString &n)
MemberVector referencesMembers
RefItemVector xrefListItems
void setId(const QCString &name)
void setBodySegment(int defLine, int bls, int ble)
void setExported(bool b)
int getDefLine() const
bool isHidden() const
void mergeRefItems(Definition *d)
QCString documentation() const
void addSourceReferencedBy(MemberDef *d, const QCString &sourceRefName)
const RefItemVector & xrefListItems() const
void writeSummaryLinks(OutputList &) const
void setHidden(bool b)
QCString _symbolName() const
QCString getSourceFileBase() const
QCString externalReference(const QCString &relPath) const
bool isReference() const
bool isVisible() const
int briefLine() const
void addSectionsToDefinition(const std::vector< const SectionInfo * > &anchorList)
bool isAnonymous() const
bool isLinkableViaGroup() const
void setDefFile(const QCString &df, int defLine, int defColumn)
std::unique_ptr< IMPL > m_impl
const Definition * findInnerCompound(const QCString &name) const
void setName(const QCString &name)
SrcLangExt getLanguage() const
void addInnerCompound(Definition *d)
void setArtificial(bool b)
bool hasSourceReffedBy() const
void _writeSourceRefList(OutputList &ol, const QCString &scopeName, const QCString &text, const std::unordered_map< std::string, MemberDef * > &members, bool) const
void writeNavigationPath(OutputList &ol) const
QCString getDefFileName() const
void writeSourceReffedBy(OutputList &ol, const QCString &scopeName) const
bool _docsAlreadyAdded(const QCString &doc, QCString &sigList)
void _setInbodyDocumentation(const QCString &d, const QCString &docFile, int docLine)
void setRefItems(const RefItemVector &sli)
int getStartBodyLine() const
void setLocalName(const QCString &name)
QCString symbolName() const
QCString id() const
void setOuterScope(Definition *d)
void _setBriefDescription(const QCString &b, const QCString &briefFile, int briefLine)
QCString qualifiedName() const
const MemberVector & getReferencesMembers() const
void setBodyDef(const FileDef *fd)
void writeInlineCode(OutputList &ol, const QCString &scopeName) const
int docLine() const
void setInbodyDocumentation(const QCString &d, const QCString &docFile, int docLine)
bool isArtificial() const
bool isExported() const
QCString briefDescriptionAsTooltip() const
int _getXRefListId(const QCString &listName) const
QCString inbodyDocumentation() const
QCString getSourceAnchor() const
QCString getDefFileExtension() const
void writeQuickMemberLinks(OutputList &, const MemberDef *) const
const GroupList & partOfGroups() const
void setBriefDescription(const QCString &b, const QCString &briefFile, int briefLine)
const QCString & name() const
QCString briefFile() const
bool hasUserDocumentation() const
int inbodyLine() const
QCString briefDescription(bool abbreviate=FALSE) const
bool hasBriefDescription() const
bool hasSources() const
const SectionRefs & getSectionRefs() const
DefinitionImpl & operator=(const DefinitionImpl &d)
bool isVisibleInProject() const
void writeSourceRefs(OutputList &ol, const QCString &scopeName) const
void makePartOfGroup(GroupDef *gd)
const QCString & localName() const
void mergeReferencedBy(const Definition *other)
int getStartDefLine() const
void setDocumentation(const QCString &d, const QCString &docFile, int docLine, bool stripWhiteSpace=TRUE)
void setReference(const QCString &r)
bool hasSourceRefs() const
void writeToc(OutputList &ol, const LocalToc &lt) const
QCString navigationPathAsString() const
void _setDocumentation(const QCString &d, const QCString &docFile, int docLine, bool stripWhiteSpace, bool atTop)
const FileDef * getBodyDef() const
void writeSourceDef(OutputList &ol) const
void setLanguage(SrcLangExt lang)
void mergeReferences(const Definition *other)
QCString inbodyFile() const
bool hasSections() const
QCString docFile() const
bool hasDocumentation() const
Definition * getOuterScope() const
const MemberVector & getReferencedByMembers() const
QCString pathFragment() const
DefinitionImpl(Definition *def, const QCString &defFileName, int defLine, int defColumn, const QCString &name, const char *b=nullptr, const char *d=nullptr, bool isSymbol=TRUE)
int getDefColumn() const
int getEndBodyLine() const
void writeDocAnchorsToTagFile(TextStream &) const
void _setSymbolName(const QCString &name)
QCString getReference() const
void addSourceReferences(MemberDef *d, const QCString &sourceRefName)
virtual Definition * toDefinition_()=0
static ParserManager * parserManager
Definition doxygen.h:131
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
static StringMap tagDestinationMap
Definition doxygen.h:116
static QCString filterDBFileName
Definition doxygen.h:133
static SymbolMap< Definition > * symbolMap
Definition doxygen.h:125
static ClangUsrMap * clangUsrMap
Definition doxygen.h:126
A model of a file symbol.
Definition filedef.h:99
virtual DirDef * getDirDef() const =0
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
void shrinkBuffer(std::string &str, const QCString &fileName, size_t startLine, size_t endLine)
Shrinks buffer str which should hold the contents of fileName to the fragment starting a line startLi...
std::vector< size_t > LineOffsets
auto getFragmentLocation(const LineOffsets &lineOffsets, size_t startLine, size_t endLine) -> std::tuple< size_t, size_t >
Returns the byte offset and size within a file of a fragment given the array of line offsets and the ...
std::unordered_map< std::string, LineOffsets > m_lineOffsets
bool getFileContentsDisk(const QCString &fileName, size_t startLine, size_t endLine, std::string &str)
reads the fragment start at startLine and ending at endLine from file fileName into buffer str
static FilterCache & instance()
void readFragmentFromFile(std::string &str, const QCString &fileName, size_t startOffset, size_t size=0)
Reads the fragment start at byte offset startOffset of file fileName into buffer str.
size_t m_endPos
void compileLineOffsets(const QCString &fileName, const std::string &str)
computes the starting offset for each line for file fileName, whose contents should already be stored...
bool getFileContents(const QCString &fileName, size_t startLine, size_t endLine, std::string &str)
collects the part of file fileName starting at startLine and ending at endLine into buffer str.
bool getFileContentsPipe(const QCString &fileName, const QCString &filter, size_t startLine, size_t endLine, std::string &str)
std::unordered_map< std::string, FilterCacheItem > m_cache
std::mutex m_mutex
A model of a group of symbols.
Definition groupdef.h:52
virtual QCString groupTitle() const =0
const T * find(const std::string &key) const
Find an object given the key.
Definition linkedmap.h:47
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
virtual bool isSignal() const =0
virtual bool isObjCMethod() const =0
virtual bool isSlot() const =0
virtual bool isFunction() const =0
virtual QCString getScopeString() const =0
virtual bool hasInlineSource() const =0
virtual MemberType memberType() const =0
virtual bool isPrototype() const =0
A vector of MemberDef object.
Definition memberlist.h:34
iterator end() noexcept
Definition memberlist.h:55
iterator begin() noexcept
Definition memberlist.h:53
void startCodeFragment(const QCString &style)
Definition outputlist.h:278
Class representing a list of output generators that are written to in parallel.
Definition outputlist.h:314
void writeString(const QCString &text)
Definition outputlist.h:412
const OutputCodeList & codeGenerators() const
Definition outputlist.h:357
void writeObjectLink(const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name)
Definition outputlist.h:440
void docify(const QCString &s)
Definition outputlist.h:438
void startParagraph(const QCString &classDef=QCString())
Definition outputlist.h:408
void endParagraph()
Definition outputlist.h:410
void pushGeneratorState()
void disableAllBut(OutputType o)
void popGeneratorState()
void writeLocalToc(const SectionRefs &refs, const LocalToc &lt)
Definition outputlist.h:743
void writeNavigationPath(const QCString &s)
Definition outputlist.h:609
void parseText(const QCString &textStr)
virtual bool hasTitle() const =0
virtual QCString title() const =0
std::unique_ptr< CodeParserInterface > getCodeParser(const QCString &extension)
Gets the interface to the parser associated with a given extension.
Definition parserintf.h:218
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
void fill(char c, int len=-1)
Fills a string with a predefined character.
Definition qcstring.h:180
QCString & prepend(const char *s)
Definition qcstring.h:407
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:153
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:567
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:245
void resize(size_t newlen)
Definition qcstring.h:167
const std::string & str() const
Definition qcstring.h:526
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition qcstring.cpp:185
QCString right(size_t len) const
Definition qcstring.h:219
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:91
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:159
QCString left(size_t len) const
Definition qcstring.h:214
void clear()
Definition qcstring.h:169
int id() const
Definition reflist.h:52
RefList * list() const
Definition reflist.h:53
QCString listName() const
Definition reflist.h:101
QCString label() const
Definition section.h:68
QCString ref() const
Definition section.h:71
void setDefinition(Definition *d)
Definition section.h:82
QCString fileName() const
Definition section.h:73
bool generated() const
Definition section.h:74
QCString title() const
Definition section.h:69
SectionType type() const
Definition section.h:70
SectionInfo * add(const SectionInfo &si)
Add a new section given the data of an existing section.
Definition section.h:138
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:175
class that represents a list of constant references to sections.
Definition section.h:102
constexpr bool isSection() const
Definition section.h:46
void remove(const QCString &name, Ptr def)
Remove a symbol def from the map that was stored under key name.
Definition symbolmap.h:55
void add(const QCString &name, Ptr def)
Add a symbol def into the map under key name.
Definition symbolmap.h:41
Text streaming class that buffers data.
Definition textstream.h:36
virtual QCString trWriteList(int numEntries)=0
virtual QCString trReferencedBy()=0
virtual QCString trReferences()=0
virtual bool needsPunctuation()
add punctuation at the end of a brief description when needed and supported by the language
Definition translator.h:154
virtual QCString trDefinedAtLineInSourceFile()=0
#define Config_getInt(name)
Definition config.h:34
#define Config_getList(name)
Definition config.h:38
#define Config_getBool(name)
Definition config.h:33
std::vector< std::string > StringVector
Definition containers.h:33
static std::mutex g_memberReferenceMutex
static void removeFromMap(const QCString &name, Definition *d)
bool readCodeFragment(const QCString &fileName, bool isMacro, int &startLine, int &endLine, QCString &result)
Reads a fragment from file fileName starting with line startLine and ending with line endLine.
static void addToMap(const QCString &name, Definition *d)
static bool matchExcludedSymbols(const QCString &name)
static QCString abbreviate(const QCString &s, const QCString &name)
DeepCopyUniquePtr< T > make_DeepCopyUnique(Args &&... args)
Helper to create an object wrapped in a DeepCopyUniquePtr.
Definition * toDefinition(DefinitionMutable *dm)
static MemberVector refMapToVector(const std::unordered_map< std::string, MemberDef * > &map)
static std::recursive_mutex g_qualifiedNameMutex
static bool stripWord(QCString &s, QCString w)
DefinitionMutable * toDefinitionMutable(Definition *d)
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1892
GroupDef * toGroupDef(Definition *d)
Translator * theTranslator
Definition language.cpp:71
MemberDef * toMemberDef(Definition *d)
#define err(fmt,...)
Definition message.h:84
std::ifstream openInputStream(const QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676
FILE * popen(const QCString &name, const QCString &type)
Definition portable.cpp:496
FILE * fopen(const QCString &fileName, const QCString &mode)
Definition portable.cpp:366
int pclose(FILE *stream)
Definition portable.cpp:505
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition regex.cpp:748
PageDef * toPageDef(Definition *d)
Definition pagedef.cpp:467
Portable versions of functions that are platform dependent.
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:477
#define qsnprintf
Definition qcstring.h:49
const char * qPrint(const char *s)
Definition qcstring.h:661
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
std::vector< RefItem * > RefItemVector
Definition reflist.h:133
std::string_view stripWhiteSpace(std::string_view s)
Given a string view s, returns a new, narrower view on that string, skipping over any leading or trai...
Definition stringutil.h:72
static bool useHtags
Definition htags.h:23
SrcLangExt
Language as given by extension.
Definition types.h:42
@ Fortran
Definition types.h:53
@ Unknown
Definition types.h:43
@ Python
Definition types.h:52
bool isUTF8CharUpperCase(const std::string &input, size_t pos)
Returns true iff the input string at byte position pos holds an upper case character.
Definition utf8.cpp:218
bool lastUTF8CharIsMultibyte(const std::string &input)
Returns true iff the last character in input is a multibyte character.
Definition utf8.cpp:212
Various UTF8 related helper functions.
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5549
QCString convertToHtml(const QCString &s, bool keepEntities)
Definition util.cpp:4317
QCString parseCommentAsText(const Definition *scope, const MemberDef *md, const QCString &doc, const QCString &fileName, int lineNr)
Definition util.cpp:5707
bool transcodeCharacterStringToUTF8(std::string &input, const char *inputEncoding)
Definition util.cpp:1376
bool found
Definition util.cpp:984
QCString stripScope(const QCString &name)
Definition util.cpp:4133
int computeQualifiedIndex(const QCString &name)
Return the index of the last :: in the string name that is still before the first <.
Definition util.cpp:7151
QCString convertToXML(const QCString &s, bool keepEntities)
Definition util.cpp:4266
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Returns the scope separator to use given the programming language lang.
Definition util.cpp:6229
QCString getEncoding(const FileInfo &fi)
Definition util.cpp:6007
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5368
QCString getFileFilter(const QCString &name, bool isSourceCode)
Definition util.cpp:1342
void writeMarkerList(OutputList &ol, const std::string &markerText, size_t numMarkers, std::function< void(size_t)> replaceFunc)
Definition util.cpp:1103
void addHtmlExtensionIfMissing(QCString &fName)
Definition util.cpp:5243
A bunch of utility functions.
bool isId(int c)
Definition util.h:202