Doxygen
Loading...
Searching...
No Matches
docnode.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2022 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 "docnode.h"
17#include "docparser_p.h"
18#include "htmlentity.h"
19#include "configimpl.h"
20#include "configoptions.h"
21#include "emoji.h"
22#include "message.h"
23#include "doxygen.h"
24#include "cite.h"
25#include "util.h"
26#include "formula.h"
27#include "markdown.h"
28#include "pagedef.h"
29#include "namespacedef.h"
30#include "groupdef.h"
31#include "cmdmapper.h"
32#include "config.h"
33#include "vhdldocgen.h"
34#include "doctokenizer.h"
35#include "plantuml.h"
36#include "language.h"
37#include "datetime.h"
38#include "trace.h"
39#include "anchor.h"
40#include "aliases.h"
41
42#if !ENABLE_DOCPARSER_TRACING
43#undef AUTO_TRACE
44#undef AUTO_TRACE_ADD
45#undef AUTO_TRACE_EXIT
46#define AUTO_TRACE(...) (void)0
47#define AUTO_TRACE_ADD(...) (void)0
48#define AUTO_TRACE_EXIT(...) (void)0
49#endif
50
51#define INTERNAL_ASSERT(x) do {} while(0)
52//#define INTERNAL_ASSERT(x) if (!(x)) TRACE("INTERNAL_ASSERT({}) failed retval={:#x}: file={} line={}",#x,retval,__FILE__,__LINE__)
53
54//---------------------------------------------------------------------------
55
56static const char *g_sectionLevelToName[] =
57{
58 "page",
59 "section",
60 "subsection",
61 "subsubsection",
62 "paragraph",
63 "subparagraph"
64};
65
66
67//---------------------------------------------------------------------------
68
70 "uml", "bpm", "wire", "dot", "ditaa",
71 "salt", "math", "latex", "gantt", "mindmap",
72 "wbs", "yaml", "creole", "json", "flow",
73 "board", "git", "hcl", "regex", "ebnf",
74 "files", "chen", "chronology"
75};
76
77//---------------------------------------------------------------------------
78
79// replaces { with < and } with > and also
80// replaces &gt; with < and &gt; with > within string s
81static void unescapeCRef(QCString &s)
82{
83 QCString result;
84 const char *p = s.data();
85 if (p)
86 {
87 char c = 0;
88 while ((c=*p++))
89 {
90 if (c=='{') c='<'; else if (c=='}') c='>';
91 result+=c;
92 }
93 }
94
95 result=substitute(result,"&lt;","<");
96 result=substitute(result,"&gt;",">");
97 s = result;
98}
99
100//---------------------------------------------------------------------------
101
102/*! Strips known html and tex extensions from \a text. */
104{
105 QCString result=text;
106 if (result.endsWith(".tex"))
107 {
108 result=result.left(result.length()-4);
109 }
110 else if (result.right(Doxygen::htmlFileExtension.length())==
112 {
113 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
114 }
115 return result;
116}
117
118static void setParent(DocNodeVariant *n,DocNodeVariant *newParent)
119{
120 std::visit([&](auto &&x)->decltype(auto) { return x.setParent(newParent); }, *n);
121}
122
123//----------- DocStyleChange
124
126{
127 switch (m_style)
128 {
129 case DocStyleChange::Bold: return "b";
130 case DocStyleChange::Italic: return "em";
131 case DocStyleChange::Code: return "code";
132 case DocStyleChange::Center: return "center";
133 case DocStyleChange::Small: return "small";
134 case DocStyleChange::Cite: return "cite";
135 case DocStyleChange::Subscript: return "subscript";
136 case DocStyleChange::Superscript: return "superscript";
137 case DocStyleChange::Preformatted: return "pre";
138 case DocStyleChange::Div: return "div";
139 case DocStyleChange::Span: return "span";
140 case DocStyleChange::Strike: return "strike";
141 case DocStyleChange::S: return "s";
142 case DocStyleChange::Del: return "del";
143 case DocStyleChange::Underline: return "u";
144 case DocStyleChange::Ins: return "ins";
145 case DocStyleChange::Kbd: return "kbd";
146 case DocStyleChange::Typewriter: return "tt";
147 }
148 return "<invalid>";
149}
150
151//----------- DocSymbol
152
157
158//----------- DocEmoji
159
161 DocNode(parser,parent), m_symName(symName), m_index(-1)
162{
163 QCString locSymName = symName;
164 size_t len=locSymName.length();
165 if (len>0)
166 {
167 if (locSymName.at(len-1)!=':') locSymName.append(":");
168 if (locSymName.at(0)!=':') locSymName.prepend(":");
169 }
170 m_symName = locSymName;
172 if (m_index==-1)
173 {
174 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Found unsupported emoji symbol '{}'",m_symName);
175 }
176}
177
178//---------------------------------------------------------------------------
179
182{
183 //printf("new word %s url=%s\n",qPrint(word),qPrint(parser->context.searchUrl));
184 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
185 {
186 Doxygen::searchIndex.addWord(word,false);
187 }
188}
189
190//---------------------------------------------------------------------------
191
193 const QCString &ref,const QCString &file,
194 const QCString &anchor,const QCString &tooltip) :
198{
199 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
200 // qPrint(word),qPrint(parser->context.searchUrl),qPrint(tooltip));
201 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
202 {
203 Doxygen::searchIndex.addWord(word,false);
204 }
205}
206
207//---------------------------------------------------------------------------
208
210{
211 if (id.isEmpty())
212 {
213 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Empty anchor label");
214 return;
215 }
216
218 QCString anchorPrefix = ct.anchorPrefix();
219 if (id.left(anchorPrefix.length()) == anchorPrefix)
220 {
221 const CiteInfo *cite = ct.find(id.mid(anchorPrefix.length()));
222 if (cite)
223 {
225 m_anchor = id;
226 }
227 else
228 {
229 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid cite anchor id '{}'",id);
230 m_anchor = "invalid";
231 m_file = "invalid";
232 }
233 }
234 else if (newAnchor) // found <a name="label">
235 {
236 m_anchor = id;
237 }
238 else // found \anchor label
239 {
240 const SectionInfo *sec = SectionManager::instance().find(id);
241 if (sec)
242 {
243 //printf("Found anchor %s\n",qPrint(id));
244 m_file = sec->fileName();
245 m_anchor = sec->label();
246 }
247 else
248 {
249 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid anchor id '{}'",id);
250 m_anchor = "invalid";
251 m_file = "invalid";
252 }
253 }
254}
255
256//---------------------------------------------------------------------------
257
264
265
266//---------------------------------------------------------------------------
267
269{
270 AUTO_TRACE("file={} text={}",m_file,Trace::trunc(m_text));
271 switch(m_type)
272 {
273 case DontIncWithLines:
274 // fall through
275 case IncWithLines:
276 // fall through
277 case Include:
278 // fall through
279 case DontInclude:
288 //printf("parser->context.includeFile=<<%s>>\n",qPrint(parser->context.includeFileText));
289 break;
290 case VerbInclude:
291 // fall through
292 case HtmlInclude:
293 case LatexInclude:
299 break;
300 case Snippet:
301 case SnippetWithLines:
303 // check here for the existence of the blockId inside the file, so we
304 // only generate the warning once.
305 int count = 0;
306 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
307 {
308 warn_doc_error(parser()->context.fileName,
309 parser()->tokenizer.getLineNr(),
310 "block marked with {} for \\snippet should appear twice in file {}, found it {:d} times",
311 m_blockId,m_file,count);
312 }
313 break;
314 }
315}
316
317//---------------------------------------------------------------------------
318
320{
321 if (parser()->context.includeFileName.isEmpty())
322 {
323 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
324 "No previous '\\include' or '\\dontinclude' command for '\\{}' present",
325 typeAsString());
326 }
327 bool found = false;
328
330 const char *p = parser()->context.includeFileText.data();
331 size_t l = parser()->context.includeFileLength;
332 size_t o = parser()->context.includeFileOffset;
333 int il = parser()->context.includeFileLine;
334 AUTO_TRACE("text={} off={} len={}",Trace::trunc(p),o,l);
335 size_t so = o, bo = 0;
336 bool nonEmpty = FALSE;
337 switch(type())
338 {
339 case Line:
340 while (o<l)
341 {
342 char c = p[o];
343 if (c=='\n')
344 {
346 if (nonEmpty) break; // we have a pattern to match
347 so=o+1; // no pattern, skip empty line
348 }
349 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
350 {
351 nonEmpty=TRUE;
352 }
353 o++;
354 }
355 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
356 {
357 m_line = il;
359 found = true;
360 AUTO_TRACE_ADD("\\line {}",Trace::trunc(m_text));
361 }
362 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
365 break;
366 case SkipLine:
367 while (o<l)
368 {
369 so=o;
370 while (o<l)
371 {
372 char c = p[o];
373 if (c=='\n')
374 {
376 if (nonEmpty) break; // we have a pattern to match
377 so=o+1; // no pattern, skip empty line
378 }
379 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
380 {
381 nonEmpty=TRUE;
382 }
383 o++;
384 }
385 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
386 {
387 m_line = il;
389 found = true;
390 AUTO_TRACE_ADD("\\skipline {}",Trace::trunc(m_text));
391 break;
392 }
393 o++; // skip new line
394 }
395 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
398 break;
399 case Skip:
400 while (o<l)
401 {
402 so=o;
403 while (o<l)
404 {
405 char c = p[o];
406 if (c=='\n')
407 {
409 if (nonEmpty) break; // we have a pattern to match
410 so=o+1; // no pattern, skip empty line
411 }
412 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
413 {
414 nonEmpty=TRUE;
415 }
416 o++;
417 }
418 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
419 {
420 found = true;
421 break;
422 }
423 o++; // skip new line
424 }
425 parser()->context.includeFileOffset = so; // set pointer to start of new line
428 break;
429 case Until:
430 bo=o;
431 while (o<l)
432 {
433 so=o;
434 while (o<l)
435 {
436 char c = p[o];
437 if (c=='\n')
438 {
440 if (nonEmpty) break; // we have a pattern to match
441 so=o+1; // no pattern, skip empty line
442 }
443 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
444 {
445 nonEmpty=TRUE;
446 }
447 o++;
448 }
449 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
450 {
451 m_line = il;
453 found = true;
454 AUTO_TRACE_ADD("\\until {}",Trace::trunc(m_text));
455 break;
456 }
457 o++; // skip new line
458 }
459 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
462 break;
463 }
464 if (!found)
465 {
466 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
467 "referenced pattern '{}' for command '\\{}' not found",m_pattern,typeAsString());
468 }
469}
470
471//---------------------------------------------------------------------------
472
477
479{
481 if (refList && refList->isEnabled())
482 {
483 RefItem *item = refList->find(m_id);
484 ASSERT(item!=nullptr);
485 if (item)
486 {
487 if (parser()->context.memberDef && parser()->context.memberDef->name().at(0)=='@')
488 {
489 m_file = "@"; // can't cross reference anonymous enum
490 m_anchor = "@";
491 }
492 else
493 {
494 m_file = refList->fileName();
495 m_anchor = item->anchor();
496 }
497 m_title = refList->sectionTitle();
498 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
499 // qPrint(m_file),qPrint(m_anchor),qPrint(m_title));
500
501 if (!item->text().isEmpty())
502 {
503 parser()->pushContext();
505 parser()->popContext();
506 }
507 }
508 return TRUE;
509 }
510 return FALSE;
511}
512
513//---------------------------------------------------------------------------
514
516 m_relPath(parser->context.relPath)
517{
518 const Formula *formula = FormulaManager::instance().findFormula(id);
519 if (formula && !formula->text().isEmpty())
520 {
521 m_id = id;
522 m_name.sprintf("form_%d",m_id);
523 m_text = formula->text();
524 }
525 else // wrong \_form#<n> command
526 {
527 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Wrong formula id {:d}",id);
528 m_id = -1;
529 }
530}
531
532//---------------------------------------------------------------------------
533
538
540{
541 AUTO_TRACE();
542 auto ns = AutoNodeStack(parser(),thisVariant());
543
545 Token tok = parser()->tokenizer.lex();
546 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
547 {
548 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
549 {
550 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\refitem");
551 }
552 tok = parser()->tokenizer.lex();
553 }
556
557 if (!m_target.isEmpty())
558 {
560 if (sec==nullptr && parser()->context.lang==SrcLangExt::Markdown) // lookup as markdown file
561 {
563 }
564 if (sec) // ref to section or anchor
565 {
566 // set defaults
567 m_ref = sec->ref();
570 m_anchor = sec->label();
571 m_isSubPage = false;
572 // adjust if needed
573 switch (sec->type().level())
574 {
576 {
578 m_isSubPage = pd && pd->hasParentPage();
579 if (!m_isSubPage)
580 {
581 m_anchor="";
582 }
583 }
584 break;
587 break;
590 break;
591 default:
592 break;
593 }
594 //printf("m_ref=%s,m_file=%s,type=%d\n",
595 // qPrint(m_ref),qPrint(m_file),m_refType);
596 }
597 else
598 {
599 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to unknown section {}",m_target);
600 }
601 }
602 else
603 {
604 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to empty target");
605 }
606}
607
608//---------------------------------------------------------------------------
609
611{
612 AUTO_TRACE();
613 auto ns = AutoNodeStack(parser(),thisVariant());
614
615 Token tok=parser()->tokenizer.lex();
616 // skip white space
617 while (tok.is_any_of(TokenRetval::TK_WHITESPACE, TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
618 // handle items
619 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
620 {
621 if (tok.is_any_of(TokenRetval::TK_COMMAND_AT, TokenRetval::TK_COMMAND_BS))
622 {
623 switch (Mappers::cmdMapper->map(parser()->context.token->name))
624 {
626 {
627 tok=parser()->tokenizer.lex();
628 if (!tok.is(TokenRetval::TK_WHITESPACE))
629 {
630 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\refitem command");
631 break;
632 }
633 tok=parser()->tokenizer.lex();
634 if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
635 {
636 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\refitem",
637 tok.to_string());
638 break;
639 }
640
643 }
644 break;
646 return;
647 default:
648 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\secreflist",
649 tok.command_to_char(),qPrint(parser()->context.token->name));
650 return;
651 }
652 }
653 else if (tok.is(TokenRetval::TK_WHITESPACE))
654 {
655 // ignore whitespace
656 }
657 else
658 {
659 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} inside section reference list",
660 tok.to_string());
661 return;
662 }
663 tok=parser()->tokenizer.lex();
664 }
665
666}
667
668//---------------------------------------------------------------------------
669
672{
673 int i=ref.find('#');
674 if (i!=-1)
675 {
676 m_anchor = ref.right(static_cast<int>(ref.length())-i-1);
677 m_file = ref.left(i);
678 }
679 else
680 {
681 m_file = ref;
682 }
683}
684
686{
687 AUTO_TRACE();
688 auto ns = AutoNodeStack(parser(),thisVariant());
689
690 Token tok = parser()->tokenizer.lex();
691 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
692 {
693 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
694 {
696 }
697 tok=parser()->tokenizer.lex();
698 }
699
701}
702
703//---------------------------------------------------------------------------
704
707{
708 const Definition *compound = nullptr;
710 AUTO_TRACE("target='{}',context='{}'",target,context);
711 ASSERT(!target.isEmpty());
712 m_relPath = parser->context.relPath;
713 auto lang = parser->context.lang;
714 const SectionInfo *sec = SectionManager::instance().find(parser->context.prefix+target);
715 if (sec==nullptr && !parser->context.prefix.isEmpty())
716 {
717 sec = SectionManager::instance().find(target);
718 }
719
720 if (sec==nullptr && getLanguageFromFileName(target)==SrcLangExt::Markdown) // lookup as markdown file
721 {
723 }
724 if (sec) // ref to section or anchor
725 {
726 PageDef *pd = nullptr;
727 int secLevel = sec->type().level();
728 if (secLevel==SectionType::Page)
729 {
730 pd = Doxygen::pageLinkedMap->find(target);
731 }
732 m_text = sec->title();
733 if (m_text.isEmpty()) m_text = sec->label();
734
735 m_ref = sec->ref();
737 if (secLevel==SectionType::Anchor)
738 {
740 }
741 else if (secLevel==SectionType::Table)
742 {
744 }
745 else
746 {
748 }
749 m_isSubPage = pd && pd->hasParentPage();
750 if (secLevel!=SectionType::Page || m_isSubPage) m_anchor = sec->label();
751 m_sectionType = sec->type();
752 //printf("m_text=%s,m_ref=%s,m_file=%s,type=%d\n",
753 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),m_refType);
754 AUTO_TRACE_EXIT("section");
755 return;
756 }
757 else if (resolveLink(context,target,true,&compound,anchor,lang,parser->context.prefix))
758 {
759 bool isFile = compound ?
760 (compound->definitionType()==Definition::TypeFile ||
762 FALSE;
763 m_text = linkToText(lang,target,isFile);
765 if (compound && compound->isLinkable()) // ref to compound
766 {
767 if (anchor.isEmpty() && /* compound link */
768 compound->definitionType()==Definition::TypeGroup && /* is group */
769 !toGroupDef(compound)->groupTitle().isEmpty() /* with title */
770 )
771 {
772 m_text=(toGroupDef(compound))->groupTitle(); // use group's title as link
773 }
774 else if (compound->definitionType()==Definition::TypeMember &&
775 toMemberDef(compound)->isObjCMethod())
776 {
777 // Objective C Method
778 const MemberDef *member = toMemberDef(compound);
779 bool localLink = parser->context.memberDef ? member->getClassDef()==parser->context.memberDef->getClassDef() : FALSE;
780 m_text = member->objCMethodName(localLink,parser->context.inSeeBlock);
781 }
782 else if (Config_getBool(HIDE_SCOPE_NAMES))
783 {
785 }
786
787 m_file = compound->getOutputFileBase();
788 m_ref = compound->getReference();
789 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
790 // compound->definitionType());
791 AUTO_TRACE_EXIT("compound");
792 return;
793 }
794 else if (compound && compound->definitionType()==Definition::TypeFile &&
795 toFileDef(compound)->generateSourceFile()
796 ) // undocumented file that has source code we can link to
797 {
798 m_file = compound->getSourceFileBase();
799 m_ref = compound->getReference();
800 AUTO_TRACE_EXIT("source");
801 return;
802 }
803 else
804 {
805 AUTO_TRACE_EXIT("compound '{}' not linkable",compound?compound->name():"none");
806 }
807 }
808 m_text = target;
809 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\ref command",
810 target);
811}
812
814{
815 for (auto &&elem : elements)
816 {
817 emplace_back(std::move(elem));
818 }
819 elements.clear();
820}
821
822static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
823{
824 DocNodeList newChildren;
825 for (auto &dn : children)
826 {
827 DocPara *para = std::get_if<DocPara>(&dn);
828 if (para)
829 {
830 //// move the children of the paragraph to the end of the newChildren list
831 newChildren.move_append(para->children());
832 }
833 }
834
835 // replace the children list by the newChildren list
836 children.clear();
837 children.move_append(newChildren);
838 // reparent the children
839 for (auto &cn : children)
840 {
841 setParent(&cn,root);
842 // we also need to set the parent for each child of cn, as cn's address may have changed.
843 auto opt_children = call_method_children(&cn);
844 if (opt_children)
845 {
846 for (auto &ccn : *opt_children)
847 {
848 setParent(&ccn,&cn);
849 }
850 }
851 }
852}
853
855{
856 AUTO_TRACE();
857 auto ns = AutoNodeStack(parser(),thisVariant());
858
859 Token tok = parser()->tokenizer.lex();
860 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
861 {
862 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
863 {
864 switch (tok.value())
865 {
866 case TokenRetval::TK_HTMLTAG:
867 break;
868 default:
870 break;
871 }
872 }
873 tok=parser()->tokenizer.lex();
874 }
875
876 if (children().empty() && !m_text.isEmpty())
877 {
878 QCString text = m_text;
879 if (parser()->context.insideHtmlLink)
880 {
881 // we already in a link/title only output anchor
882 text = m_anchor;
883 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
884 "Potential recursion while resolving \\ref command!");
885 }
887 parser()->pushContext();
889 parser()->popContext();
893 }
894
896}
897
898//---------------------------------------------------------------------------
899
901{
902 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
903 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
904 ASSERT(!target.isEmpty());
905 m_relPath = parser->context.relPath;
907 const CiteInfo *cite = ct.find(target);
908 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
909 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
910 {
911 m_text = cite->text();
912 m_ref = "";
913 m_anchor = ct.anchorPrefix()+cite->label();
915 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
916 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
917 return;
918 }
919 m_text = target;
920 if (numBibFiles==0)
921 {
922 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
923 }
924 else if (cite==nullptr)
925 {
926 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\cite command",
927 target);
928 }
929 else
930 {
931 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '{}' does not have an associated number",
932 target);
933 }
934}
935
936//---------------------------------------------------------------------------
937
939{
940 const Definition *compound = nullptr;
942 m_refText = target;
943 m_relPath = parser->context.relPath;
944 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
945 {
946 m_refText = m_refText.right(m_refText.length()-1);
947 }
948 if (resolveLink(parser->context.context,stripKnownExtensions(target),
949 parser->context.inSeeBlock,&compound,anchor,
950 parser->context.lang,parser->context.prefix))
951 {
952 m_anchor = anchor;
953 if (compound && compound->isLinkable())
954 {
955 m_file = compound->getOutputFileBase();
956 m_ref = compound->getReference();
957 }
958 else if (compound && compound->definitionType()==Definition::TypeFile &&
959 (toFileDef(compound))->generateSourceFile()
960 ) // undocumented file that has source code we can link to
961 {
962 m_file = compound->getSourceFileBase();
963 m_ref = compound->getReference();
964 }
965 return;
966 }
967
968 // bogus link target
969 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '{}' for \\link command",
970 target);
971}
972
973
974QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
975{
976 AUTO_TRACE();
977 QCString result;
978 auto ns = AutoNodeStack(parser(),thisVariant());
979
980 Token tok = parser()->tokenizer.lex();
981 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
982 {
983 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
984 {
985 switch (tok.value())
986 {
987 case TokenRetval::TK_COMMAND_AT:
988 // fall through
989 case TokenRetval::TK_COMMAND_BS:
990 switch (Mappers::cmdMapper->map(parser()->context.token->name))
991 {
993 if (isJavaLink)
994 {
995 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{{@link...' ended with '{:c}{}' command",
996 tok.command_to_char(),parser()->context.token->name);
997 }
998 goto endlink;
999 default:
1000 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\link",
1001 tok.command_to_char(),parser()->context.token->name);
1002 break;
1003 }
1004 break;
1005 case TokenRetval::TK_SYMBOL:
1006 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a \\link",
1007 parser()->context.token->name);
1008 break;
1009 case TokenRetval::TK_HTMLTAG:
1010 if (parser()->context.token->name!="see" || !isXmlLink)
1011 {
1012 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command {} found as part of a \\link",
1013 parser()->context.token->name);
1014 }
1015 goto endlink;
1016 case TokenRetval::TK_LNKWORD:
1017 case TokenRetval::TK_WORD:
1018 if (isJavaLink) // special case to detect closing }
1019 {
1021 int p = 0;
1022 if (w=="}")
1023 {
1024 goto endlink;
1025 }
1026 else if ((p=w.find('}'))!=-1)
1027 {
1028 int l = static_cast<int>(w.length());
1030 if (p<l-1) // something left after the } (for instance a .)
1031 {
1032 result=w.right(l-p-1);
1033 }
1034 goto endlink;
1035 }
1036 }
1038 break;
1039 default:
1040 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",tok.to_string());
1041 break;
1042 }
1043 }
1044 tok = parser()->tokenizer.lex();
1045 }
1046 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1047 {
1048 warn_doc_error(parser()->context.fileName,
1049 parser()->tokenizer.getLineNr(),
1050 "Unexpected end of comment while inside link command");
1051 }
1052endlink:
1053
1054 if (children().empty()) // no link text
1055 {
1057 }
1058
1060 return result;
1061}
1062
1063
1064//---------------------------------------------------------------------------
1065
1072
1074{
1075 bool ok = false;
1077
1078 bool ambig = false;
1080 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1081 {
1082 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1083 }
1084 if (fd)
1085 {
1086 p->file = fd->absFilePath();
1087 ok = true;
1088 if (ambig)
1089 {
1090 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '{}' is ambiguous.\n"
1091 "Possible candidates:\n{}",p->name,
1093 );
1094 }
1095 }
1096 else
1097 {
1098 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '{}' is not found "
1099 "in any of the paths specified via DOTFILE_DIRS!",p->name);
1100 }
1101 return ok;
1102}
1103
1110
1112{
1113 bool ok = false;
1115
1116 bool ambig = false;
1118 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1119 {
1120 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1121 }
1122 if (fd)
1123 {
1124 p->file = fd->absFilePath();
1125 ok = true;
1126 if (ambig)
1127 {
1128 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '{}' is ambiguous.\n"
1129 "Possible candidates:\n{}",qPrint(p->name),
1131 );
1132 }
1133 }
1134 else
1135 {
1136 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '{}' is not found "
1137 "in any of the paths specified via MSCFILE_DIRS!",p->name);
1138 }
1139 return ok;
1140}
1141
1142//---------------------------------------------------------------------------
1143
1150
1152{
1153 bool ok = false;
1155
1156 bool ambig = false;
1158 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1159 {
1160 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
1161 }
1162 if (fd)
1163 {
1164 p->file = fd->absFilePath();
1165 ok = true;
1166 if (ambig)
1167 {
1168 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file name '{}' is ambiguous.\n"
1169 "Possible candidates:\n{}",p->name,
1171 );
1172 }
1173 }
1174 else
1175 {
1176 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file '{}' is not found "
1177 "in any of the paths specified via DIAFILE_DIRS!",p->name);
1178 }
1179 return ok;
1180}
1181//---------------------------------------------------------------------------
1182
1189
1191{
1192 bool ok = false;
1194
1195 bool ambig = false;
1197 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1198 {
1199 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1200 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1201 {
1202 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1203 }
1204 }
1205 if (fd)
1206 {
1207 p->file = fd->absFilePath();
1208 ok = true;
1209 if (ambig)
1210 {
1211 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '{}' is ambiguous.\n"
1212 "Possible candidates:\n{}",p->name,
1214 );
1215 }
1216 }
1217 else
1218 {
1219 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '{}' is not found "
1220 "in any of the paths specified via PLANTUMLFILE_DIRS!",p->name);
1221 }
1222 return ok;
1223}
1224
1225//---------------------------------------------------------------------------
1226
1230
1232{
1233 AUTO_TRACE();
1234 auto ns = AutoNodeStack(parser(),thisVariant());
1235
1237 Token tok = parser()->tokenizer.lex();
1238 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1239 {
1240 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1241 {
1242 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1243 }
1244 tok = parser()->tokenizer.lex();
1245 }
1246 parser()->tokenizer.lex();
1247
1250
1251 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1252}
1253
1254
1255//---------------------------------------------------------------------------
1256
1258 Type t,const QCString &url, bool inlineImage) :
1259 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1260{
1261}
1262
1264{
1265 QCString locName = p->url.isEmpty() ? p->name : p->url;
1266 int len = static_cast<int>(locName.length());
1267 int fnd = locName.find('?'); // ignore part from ? until end
1268 if (fnd==-1) fnd=len;
1269 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1270}
1271
1276
1277
1278//---------------------------------------------------------------------------
1279
1281{
1282 AUTO_TRACE();
1283 Token retval(TokenRetval::RetVal_OK);
1284 auto ns = AutoNodeStack(parser(),thisVariant());
1285
1286 Token tok = parser()->tokenizer.lex();
1287 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1288 {
1289 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1290 {
1291 switch (tok.value())
1292 {
1293 case TokenRetval::TK_HTMLTAG:
1294 {
1295 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1296 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1297 {
1298 if (m_level!=1)
1299 {
1300 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h1>",
1301 m_level);
1302 }
1303 goto endheader;
1304 }
1305 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1306 {
1307 if (m_level!=2)
1308 {
1309 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h2>",
1310 m_level);
1311 }
1312 goto endheader;
1313 }
1314 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1315 {
1316 if (m_level!=3)
1317 {
1318 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h3>",
1319 m_level);
1320 }
1321 goto endheader;
1322 }
1323 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1324 {
1325 if (m_level!=4)
1326 {
1327 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h4>",
1328 m_level);
1329 }
1330 goto endheader;
1331 }
1332 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1333 {
1334 if (m_level!=5)
1335 {
1336 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h5>",
1337 m_level);
1338 }
1339 goto endheader;
1340 }
1341 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1342 {
1343 if (m_level!=6)
1344 {
1345 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h6>",
1346 m_level);
1347 }
1348 goto endheader;
1349 }
1350 else if (tagId==HtmlTagType::HTML_A)
1351 {
1352 if (!parser()->context.token->endTag)
1353 {
1354 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1355 }
1356 }
1357 else if (tagId==HtmlTagType::HTML_BR)
1358 {
1360 }
1361 else
1362 {
1363 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <h{:d}> context",
1364 parser()->context.token->endTag?"/":"",parser()->context.token->name,m_level);
1365 }
1366 }
1367 break;
1368 default:
1369 char tmp[20];
1370 qsnprintf(tmp,20,"<h%d> tag",m_level);
1372 }
1373 }
1374 tok = parser()->tokenizer.lex();
1375 }
1376 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1377 {
1378 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1379 " <h{:d}> tag",m_level);
1380 }
1381endheader:
1383 return retval;
1384}
1385//---------------------------------------------------------------------------
1386
1388{
1389 AUTO_TRACE();
1390 auto ns = AutoNodeStack(parser(),thisVariant());
1392 Token tok = parser()->tokenizer.lex();
1393 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1394 {
1396 // check of </summary>
1397 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1398 (tagId=Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1399 parser()->context.token->endTag
1400 )
1401 {
1402 break;
1403 }
1404 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1405 {
1406 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1407 }
1408 tok = parser()->tokenizer.lex();
1409 }
1411 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1412 {
1413 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1414 " <summary> tag");
1415 }
1416}
1417
1418//---------------------------------------------------------------------------
1419
1421{
1422 AUTO_TRACE();
1423 Token retval(TokenRetval::TK_NONE);
1424 auto ns = AutoNodeStack(parser(),thisVariant());
1425
1426 // parse one or more paragraphs
1427 bool isFirst=TRUE;
1428 DocPara *par=nullptr;
1429 do
1430 {
1432 par = children().get_last<DocPara>();
1433 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1434 retval=par->parse();
1435 }
1436 while (retval.is(TokenRetval::TK_NEWPARA));
1437 if (par) par->markLast();
1438
1439 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1440 {
1441 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1442 }
1443
1444 if (!summary())
1445 {
1446 HtmlAttribList summaryAttribs;
1448 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1449 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1450 }
1451 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1452 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1453}
1454
1462
1463//---------------------------------------------------------------------------
1464
1466{
1467 AUTO_TRACE();
1468 Token retval(TokenRetval::RetVal_OK);
1469 auto ns = AutoNodeStack(parser(),thisVariant());
1470
1471 Token tok = parser()->tokenizer.lex();
1472 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1473 {
1474 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1475 {
1476 switch (tok.value())
1477 {
1478 case TokenRetval::TK_HTMLTAG:
1479 {
1480 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1481 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1482 {
1483 goto endhref;
1484 }
1485 else if (tagId==HtmlTagType::HTML_BR)
1486 {
1488 }
1489 else
1490 {
1491 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <a href=...> context",
1492 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1493 }
1494 }
1495 break;
1496 default:
1497 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1498 break;
1499 }
1500 }
1501 tok = parser()->tokenizer.lex();
1502 }
1503 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1504 {
1505 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1506 " <a href=...> tag");
1507 }
1508endhref:
1510 return retval;
1511}
1512
1513//---------------------------------------------------------------------------
1514
1516{
1517 AUTO_TRACE();
1518 Token retval(TokenRetval::RetVal_OK);
1519 auto ns = AutoNodeStack(parser(),thisVariant());
1520
1521 // first parse any number of paragraphs
1522 bool isFirst=TRUE;
1523 DocPara *lastPar=nullptr;
1524 do
1525 {
1527 DocPara *par = children().get_last<DocPara>();
1528 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1529 retval=par->parse();
1530 if (!par->isEmpty())
1531 {
1532 if (lastPar) lastPar->markLast(FALSE);
1533 lastPar=par;
1534 }
1535 else
1536 {
1537 children().pop_back();
1538 }
1539 if (retval.is(TokenRetval::TK_LISTITEM))
1540 {
1541 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1542 }
1543 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1544 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1545 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1546 TokenRetval::RetVal_EndInternal));
1547 if (lastPar) lastPar->markLast();
1548
1549 // then parse any number of level-n sections
1550 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1551 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1552 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1553 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1554 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1555 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1556 )
1557 {
1559 level,
1561 retval = children().get_last<DocSection>()->parse();
1562 }
1563
1564 if (retval.is(TokenRetval::RetVal_Internal))
1565 {
1566 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1567 }
1568
1569 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1570 return retval;
1571}
1572
1573//---------------------------------------------------------------------------
1574
1576{
1577 AUTO_TRACE();
1578 Token retval(TokenRetval::RetVal_OK);
1579 auto ns = AutoNodeStack(parser(),thisVariant());
1580 Token tok=parser()->tokenizer.lex();
1581 if (!tok.is(TokenRetval::TK_WHITESPACE))
1582 {
1583 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1584 goto endindexentry;
1585 }
1587 m_entry="";
1588 tok = parser()->tokenizer.lex();
1589 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1590 {
1591 switch (tok.value())
1592 {
1593 case TokenRetval::TK_WHITESPACE:
1594 m_entry+=" ";
1595 break;
1596 case TokenRetval::TK_WORD:
1597 case TokenRetval::TK_LNKWORD:
1599 break;
1600 case TokenRetval::TK_SYMBOL:
1601 {
1602 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1603 switch (s)
1604 {
1605 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1606 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1607 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1608 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1609 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1610 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1611 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1612 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1613 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1614 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1615 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1616 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1617 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1618 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1619 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1620 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1621 default:
1622 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '{}' found as argument of \\addindex",parser()->context.token->name);
1623 break;
1624 }
1625 }
1626 break;
1627 case TokenRetval::TK_COMMAND_AT:
1628 // fall through
1629 case TokenRetval::TK_COMMAND_BS:
1630 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1631 {
1632 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1633 case CommandType::CMD_AT: m_entry+='@'; break;
1634 case CommandType::CMD_LESS: m_entry+='<'; break;
1635 case CommandType::CMD_GREATER: m_entry+='>'; break;
1636 case CommandType::CMD_AMP: m_entry+='&'; break;
1637 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1638 case CommandType::CMD_HASH: m_entry+='#'; break;
1639 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1640 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1641 case CommandType::CMD_NDASH: m_entry+="--"; break;
1642 case CommandType::CMD_MDASH: m_entry+="---"; break;
1643 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1644 case CommandType::CMD_PUNT: m_entry+='.'; break;
1645 case CommandType::CMD_PLUS: m_entry+='+'; break;
1646 case CommandType::CMD_MINUS: m_entry+='-'; break;
1647 case CommandType::CMD_EQUAL: m_entry+='='; break;
1648 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1649 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1650 default:
1651 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command {} found as argument of \\addindex",
1652 parser()->context.token->name);
1653 break;
1654 }
1655 break;
1656 default:
1657 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
1658 tok.to_string());
1659 break;
1660 }
1661 tok = parser()->tokenizer.lex();
1662 }
1664 m_entry = m_entry.stripWhiteSpace();
1665endindexentry:
1666 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1667 return retval;
1668}
1669
1670//---------------------------------------------------------------------------
1671
1674{
1676 for (const auto &opt : attribs)
1677 {
1678 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1679 {
1680 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1681 if (sec)
1682 {
1683 //printf("Found anchor %s\n",qPrint(id));
1684 m_file = sec->fileName();
1685 m_anchor = sec->label();
1687 }
1688 else
1689 {
1690 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '{}'",opt.value);
1691 }
1692 }
1693 else // copy attribute
1694 {
1695 m_attribs.push_back(opt);
1696 }
1697 }
1698}
1699
1701{
1702 AUTO_TRACE();
1703 Token retval = Token::make_TK_NONE();
1704 auto ns = AutoNodeStack(parser(),thisVariant());
1705 Token tok = parser()->tokenizer.lex();
1706 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1707 {
1708 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1709 {
1710 switch (tok.value())
1711 {
1712 case TokenRetval::TK_HTMLTAG:
1713 {
1714 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1715 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1716 {
1717 retval = Token::make_RetVal_OK();
1718 goto endcaption;
1719 }
1720 else
1721 {
1722 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <caption> context",
1723 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1724 }
1725 }
1726 break;
1727 default:
1728 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1729 break;
1730 }
1731 }
1732 tok = parser()->tokenizer.lex();
1733 }
1734 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1735 {
1736 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1737 " <caption> tag");
1738 }
1739endcaption:
1741 return retval;
1742}
1743
1744//---------------------------------------------------------------------------
1745
1747{
1748 AUTO_TRACE();
1749 Token retval = Token::make_RetVal_OK();
1750 auto ns = AutoNodeStack(parser(),thisVariant());
1751
1752 // parse one or more paragraphs
1753 bool isFirst=TRUE;
1754 DocPara *par=nullptr;
1755 do
1756 {
1758 par = children().get_last<DocPara>();
1759 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1760 retval=par->parse();
1761 if (retval.is(TokenRetval::TK_HTMLTAG))
1762 {
1763 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1764 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1765 {
1766 retval = Token::make_TK_NEWPARA(); // ignore the tag
1767 }
1768 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1769 {
1770 retval = Token::make_TK_NEWPARA(); // ignore the tag
1771 }
1772 }
1773 }
1774 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1775 if (par) par->markLast();
1776
1777 return retval;
1778}
1779
1781{
1782 AUTO_TRACE();
1783 Token retval = Token::make_RetVal_OK();
1784 auto ns = AutoNodeStack(parser(),thisVariant());
1785
1786 // parse one or more paragraphs
1787 bool isFirst=TRUE;
1788 DocPara *par=nullptr;
1789 do
1790 {
1792 par = children().get_last<DocPara>();
1793 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1794 retval=par->parse();
1795 if (retval.is(TokenRetval::TK_HTMLTAG))
1796 {
1797 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1798 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1799 {
1800 retval = Token::make_TK_NEWPARA(); // ignore the tag
1801 }
1802 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1803 {
1804 retval = Token::make_TK_NEWPARA(); // ignore the tag
1805 }
1806 }
1807 }
1808 while (retval.is(TokenRetval::TK_NEWPARA));
1809 if (par) par->markLast();
1810
1811 return retval;
1812}
1813
1814uint32_t DocHtmlCell::rowSpan() const
1815{
1816 for (const auto &attr : attribs())
1817 {
1818 if (attr.name.lower()=="rowspan")
1819 {
1820 return attr.value.toUInt();
1821 }
1822 }
1823 return 0;
1824}
1825
1826uint32_t DocHtmlCell::colSpan() const
1827{
1828 for (const auto &attr : attribs())
1829 {
1830 if (attr.name.lower()=="colspan")
1831 {
1832 return std::max(1u,attr.value.toUInt());
1833 }
1834 }
1835 return 1;
1836}
1837
1839{
1840 for (const auto &attr : attribs())
1841 {
1842 QCString attrName = attr.name.lower();
1843 QCString attrValue = attr.value.lower();
1844 if (attrName=="align")
1845 {
1846 if (attrValue=="center")
1847 return Center;
1848 else if (attrValue=="right")
1849 return Right;
1850 else return Left;
1851 }
1852 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1853 {
1854 if (attrValue=="markdowntableheadcenter")
1855 return Center;
1856 else if (attrValue=="markdowntableheadright")
1857 return Right;
1858 else if (attrValue=="markdowntableheadleft")
1859 return Left;
1860 else if (attrValue=="markdowntableheadnone")
1861 return Center;
1862 else if (attrValue=="markdowntablebodycenter")
1863 return Center;
1864 else if (attrValue=="markdowntablebodyright")
1865 return Right;
1866 else if (attrValue=="markdowntablebodyleft")
1867 return Left;
1868 else if (attrValue=="markdowntablebodynone")
1869 return Left;
1870 else return Left;
1871 }
1872 }
1873 return Left;
1874}
1875
1877{
1878 for (const auto &attr : attribs())
1879 {
1880 QCString attrName = attr.name.lower();
1881 QCString attrValue = attr.value.lower();
1882 if (attrName=="valign")
1883 {
1884 if (attrValue=="top")
1885 return Top;
1886 else if (attrValue=="bottom")
1887 return Bottom;
1888 else if (attrValue=="middle")
1889 return Middle;
1890 else return Middle;
1891 }
1892 }
1893 return Middle;
1894}
1895
1896//---------------------------------------------------------------------------
1897
1899{ // a row is a table heading if all cells are marked as such
1900 bool heading=TRUE;
1901 for (const auto &n : children())
1902 {
1903 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1904 if (cell && !cell->isHeading())
1905 {
1906 heading = FALSE;
1907 break;
1908 }
1909 }
1910 return !children().empty() && heading;
1911}
1912
1914{
1915 AUTO_TRACE();
1916 Token retval = Token::make_RetVal_OK();
1917 auto ns = AutoNodeStack(parser(),thisVariant());
1918
1919 bool isHeading=FALSE;
1920 bool isFirst=TRUE;
1921 DocHtmlCell *cell=nullptr;
1922
1923 // get next token
1924 Token tok=parser()->tokenizer.lex();
1925 // skip whitespace
1926 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
1927 // should find a html tag now
1928 if (tok.is(TokenRetval::TK_HTMLTAG))
1929 {
1930 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1931 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
1932 {
1933 }
1934 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
1935 {
1937 }
1938 else // found some other tag
1939 {
1940 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
1941 "found <{}> instead!",parser()->context.token->name);
1942 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
1943 goto endrow;
1944 }
1945 }
1946 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
1947 {
1948 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
1949 " for a html description title");
1950 goto endrow;
1951 }
1952 else // token other than html token
1953 {
1954 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
1955 tok.to_string());
1956 goto endrow;
1957 }
1958
1959 // parse one or more cells
1960 do
1961 {
1964 isHeading);
1965 cell = children().get_last<DocHtmlCell>();
1966 cell->markFirst(isFirst);
1967 isFirst=FALSE;
1968 retval=cell->parse();
1969 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
1970 }
1971 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
1972 cell->markLast(TRUE);
1973
1974endrow:
1975 return retval;
1976}
1977
1979{
1980 AUTO_TRACE();
1981 Token retval = Token::make_RetVal_OK();
1982 auto ns = AutoNodeStack(parser(),thisVariant());
1983
1984 bool isFirst=TRUE;
1985 DocHtmlCell *cell=nullptr;
1986
1987 // get next token
1988 Token tok=parser()->tokenizer.lex();
1989 // skip whitespace
1990 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
1991 // should find a html tag now
1992 if (tok.is(TokenRetval::TK_HTMLTAG))
1993 {
1994 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1995 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
1996 {
1997 }
1998 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
1999 {
2000 }
2001 else // found some other tag
2002 {
2003 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
2004 "found <{}> instead!",parser()->context.token->name);
2005 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2006 goto endrow;
2007 }
2008 }
2009 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2010 {
2011 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2012 " for a html description title");
2013 goto endrow;
2014 }
2015 else // token other than html token
2016 {
2017 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2018 tok.to_string());
2019 goto endrow;
2020 }
2021
2022 do
2023 {
2025 cell = children().get_last<DocHtmlCell>();
2026 cell->markFirst(isFirst);
2027 isFirst=FALSE;
2028 retval=cell->parseXml();
2029 }
2030 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2031 cell->markLast(TRUE);
2032
2033endrow:
2034 return retval;
2035}
2036
2037//---------------------------------------------------------------------------
2038
2040{
2041 return m_caption!=nullptr;
2042}
2043
2045{
2046 return m_caption.get();
2047}
2048
2050{
2051 if (!children().empty() && std::holds_alternative<DocHtmlRow>(children().front()))
2052 {
2053 return &children().front();
2054 }
2055 return nullptr;
2056}
2057
2059{
2060 AUTO_TRACE();
2061 Token retval = Token::make_RetVal_OK();
2062 auto ns = AutoNodeStack(parser(),thisVariant());
2063
2064getrow:
2065 // get next token
2066 Token tok=parser()->tokenizer.lex();
2067 // skip whitespace
2068 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2069 // should find a html tag now
2070 if (tok.is(TokenRetval::TK_HTMLTAG))
2071 {
2072 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2073 if (tagId==HtmlTagType::HTML_THEAD && !parser()->context.token->endTag) // found <thead> tag
2074 {
2075 goto getrow;
2076 }
2077 else if (tagId==HtmlTagType::HTML_TBODY && !parser()->context.token->endTag) // found <tbody> tag
2078 {
2079 goto getrow;
2080 }
2081 else if (tagId==HtmlTagType::HTML_TFOOT && !parser()->context.token->endTag) // found <tfoot> tag
2082 {
2083 goto getrow;
2084 }
2085 else if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2086 {
2087 // no caption, just rows
2088 retval = Token::make_RetVal_TableRow();
2089 }
2090 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2091 {
2092 if (m_caption)
2093 {
2094 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2095 }
2096 else
2097 {
2098 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2099 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2100
2101 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2102 {
2103 goto getrow;
2104 }
2105 }
2106 }
2107 else // found wrong token
2108 {
2109 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2110 "found <{}{}> instead!", parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2111 }
2112 }
2113 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2114 {
2115 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2116 " for a <tr> or <caption> tag");
2117 }
2118 else // token other than html token
2119 {
2120 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found {} token instead!",
2121 tok.to_string());
2122 }
2123
2124 // parse one or more rows
2125 while (retval.is(TokenRetval::RetVal_TableRow))
2126 {
2128 retval = children().get_last<DocHtmlRow>()->parse();
2129 }
2130
2132
2133 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2134}
2135
2137{
2138 AUTO_TRACE();
2139 Token retval = Token::make_RetVal_OK();
2140 auto ns = AutoNodeStack(parser(),thisVariant());
2141
2142 // get next token
2143 Token tok=parser()->tokenizer.lex();
2144 // skip whitespace
2145 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2146 // should find a html tag now
2148 bool isHeader=FALSE;
2149 if (tok.is(TokenRetval::TK_HTMLTAG))
2150 {
2151 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2152 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2153 {
2154 retval = Token::make_RetVal_TableRow();
2155 }
2156 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2157 {
2158 retval = Token::make_RetVal_TableRow();
2159 isHeader=TRUE;
2160 }
2161 }
2162
2163 // parse one or more rows
2164 while (retval.is(TokenRetval::RetVal_TableRow))
2165 {
2168 retval=tr->parseXml(isHeader);
2169 isHeader=FALSE;
2170 }
2171
2173
2174 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2175 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2176}
2177
2178/** Helper class to compute the grid for an HTML style table */
2180{
2181 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2182 uint32_t rowsLeft;
2183 uint32_t column;
2184};
2185
2186/** List of ActiveRowSpan classes. */
2187typedef std::vector<ActiveRowSpan> RowSpanList;
2188
2189/** determines the location of all cells in a grid, resolving row and
2190 column spans. For each the total number of visible cells is computed,
2191 and the total number of visible columns over all rows is stored.
2192 */
2194{
2195 //printf("computeTableGrid()\n");
2196 RowSpanList rowSpans;
2197 uint32_t maxCols=0;
2198 uint32_t rowIdx=1;
2199 for (auto &rowNode : children())
2200 {
2201 uint32_t colIdx=1;
2202 uint32_t cells=0;
2203 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2204 if (row)
2205 {
2206 for (auto &cellNode : row->children())
2207 {
2208 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2209 if (cell)
2210 {
2211 uint32_t rs = cell->rowSpan();
2212 uint32_t cs = cell->colSpan();
2213
2214 for (size_t i=0;i<rowSpans.size();i++)
2215 {
2216 if (rowSpans[i].rowsLeft>0 &&
2217 rowSpans[i].column==colIdx)
2218 {
2219 colIdx=rowSpans[i].column+1;
2220 cells++;
2221 }
2222 }
2223 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2224 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2225 cell->setRowIndex(rowIdx);
2226 cell->setColumnIndex(colIdx);
2227 colIdx+=cs;
2228 cells++;
2229 }
2230 }
2231 for (size_t i=0;i<rowSpans.size();i++)
2232 {
2233 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2234 }
2235 row->setVisibleCells(cells);
2236 row->setRowIndex(rowIdx);
2237 rowIdx++;
2238 }
2239 if (colIdx-1>maxCols) maxCols=colIdx-1;
2240 }
2241 m_numCols = maxCols;
2242}
2243
2244//---------------------------------------------------------------------------
2245
2247{
2248 AUTO_TRACE();
2249 Token retval = Token::make_TK_NONE();
2250 auto ns = AutoNodeStack(parser(),thisVariant());
2251
2252 Token tok = parser()->tokenizer.lex();
2253 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2254 {
2255 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2256 {
2257 switch (tok.value())
2258 {
2259 case TokenRetval::TK_COMMAND_AT:
2260 // fall through
2261 case TokenRetval::TK_COMMAND_BS:
2262 {
2263 QCString cmdName=parser()->context.token->name;
2264 bool isJavaLink=FALSE;
2265 switch (Mappers::cmdMapper->map(cmdName))
2266 {
2268 {
2269 tok=parser()->tokenizer.lex();
2270 if (!tok.is(TokenRetval::TK_WHITESPACE))
2271 {
2272 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
2273 tok.command_to_char(),cmdName);
2274 }
2275 else
2276 {
2278 tok=parser()->tokenizer.lex(); // get the reference id
2279 if (!tok.is(TokenRetval::TK_WORD))
2280 {
2281 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}' command",
2282 tok.to_string(),tok.command_to_char(),cmdName);
2283 }
2284 else
2285 {
2287 children().get_last<DocRef>()->parse();
2288 }
2290 }
2291 }
2292 break;
2294 isJavaLink=TRUE;
2295 // fall through
2297 {
2298 tok=parser()->tokenizer.lex();
2299 if (!tok.is(TokenRetval::TK_WHITESPACE))
2300 {
2301 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
2302 cmdName);
2303 }
2304 else
2305 {
2307 tok=parser()->tokenizer.lex();
2308 if (!tok.is(TokenRetval::TK_WORD))
2309 {
2310 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\{} command",
2311 tok.to_string(),cmdName);
2312 }
2313 else
2314 {
2317 DocLink *lnk = children().get_last<DocLink>();
2318 QCString leftOver = lnk->parse(isJavaLink);
2319 if (!leftOver.isEmpty())
2320 {
2321 children().append<DocWord>(parser(),thisVariant(),leftOver);
2322 }
2323 }
2324 }
2325 }
2326
2327 break;
2328 default:
2329 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' found as part of a <dt> tag",
2330 tok.command_to_char(),cmdName);
2331 }
2332 }
2333 break;
2334 case TokenRetval::TK_SYMBOL:
2335 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a <dt> tag",
2336 parser()->context.token->name);
2337 break;
2338 case TokenRetval::TK_HTMLTAG:
2339 {
2340 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2341 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2342 {
2343 retval = Token::make_RetVal_DescData();
2344 goto endtitle;
2345 }
2346 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2347 {
2348 // ignore </dt> tag.
2349 }
2350 else if (tagId==HtmlTagType::HTML_DT)
2351 {
2352 // missing <dt> tag.
2353 retval = Token::make_RetVal_DescTitle();
2354 goto endtitle;
2355 }
2356 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2357 {
2358 retval = Token::make_RetVal_EndDesc();
2359 goto endtitle;
2360 }
2361 else if (tagId==HtmlTagType::HTML_A)
2362 {
2363 if (!parser()->context.token->endTag)
2364 {
2365 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2366 }
2367 }
2368 else
2369 {
2370 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <dt> context",
2371 parser()->context.token->endTag?"/":"",parser()->context.token->name);
2372 }
2373 }
2374 break;
2375 default:
2376 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} found as part of a <dt> tag",
2377 tok.to_string());
2378 break;
2379 }
2380 }
2381 tok = parser()->tokenizer.lex();
2382 }
2383 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2384 {
2385 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2386 " <dt> tag");
2387 }
2388endtitle:
2390 return retval;
2391}
2392
2393//---------------------------------------------------------------------------
2394
2396{
2397 AUTO_TRACE();
2399 Token retval = Token::make_TK_NONE();
2400 auto ns = AutoNodeStack(parser(),thisVariant());
2401
2402 bool isFirst=TRUE;
2403 DocPara *par=nullptr;
2404 do
2405 {
2407 par = children().get_last<DocPara>();
2408 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2409 retval=par->parse();
2410 }
2411 while (retval.is(TokenRetval::TK_NEWPARA));
2412 if (par) par->markLast();
2413
2414 return retval;
2415}
2416
2417//---------------------------------------------------------------------------
2418
2420{
2421 AUTO_TRACE();
2422 Token retval = Token::make_RetVal_OK();
2423 auto ns = AutoNodeStack(parser(),thisVariant());
2424
2425 // get next token
2426 Token tok=parser()->tokenizer.lex();
2427 // skip whitespace
2428 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2429 // should find a html tag now
2430 if (tok.is(TokenRetval::TK_HTMLTAG))
2431 {
2432 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2433 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2434 {
2435 // continue
2436 }
2437 else // found some other tag
2438 {
2439 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2440 "found <{}> instead!",parser()->context.token->name);
2441 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2442 goto enddesclist;
2443 }
2444 }
2445 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2446 {
2447 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2448 " for a html description title");
2449 goto enddesclist;
2450 }
2451 else // token other than html token
2452 {
2453 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found {} token instead!",
2454 tok.to_string());
2455 goto enddesclist;
2456 }
2457
2458 do
2459 {
2464 retval=dt->parse();
2465 if (retval.is(TokenRetval::RetVal_DescData))
2466 {
2467 retval=dd->parse();
2468 while (retval.is(TokenRetval::RetVal_DescData))
2469 {
2472 retval=dd->parse();
2473 }
2474 }
2475 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2476 {
2477 // error
2478 break;
2479 }
2480 } while (retval.is(TokenRetval::RetVal_DescTitle));
2481
2482 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2483 {
2484 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2485 }
2486
2487enddesclist:
2488
2489 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2490}
2491
2492//---------------------------------------------------------------------------
2493
2495{
2496 AUTO_TRACE();
2497 Token retval = Token::make_TK_NONE();
2498 auto ns = AutoNodeStack(parser(),thisVariant());
2499
2500 // parse one or more paragraphs
2501 bool isFirst=TRUE;
2502 DocPara *par=nullptr;
2503 do
2504 {
2506 par = children().get_last<DocPara>();
2507 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2508 retval=par->parse();
2509 }
2510 while (retval.is(TokenRetval::TK_NEWPARA));
2511 if (par) par->markLast();
2512
2513 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2514 return retval;
2515}
2516
2518{
2519 AUTO_TRACE();
2520 Token retval = Token::make_TK_NONE();
2521 auto ns = AutoNodeStack(parser(),thisVariant());
2522
2523 // parse one or more paragraphs
2524 bool isFirst=TRUE;
2525 DocPara *par=nullptr;
2526 do
2527 {
2529 par = children().get_last<DocPara>();
2530 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2531 retval=par->parse();
2532 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2533
2534 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2535 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2536 if (retval.is(TokenRetval::RetVal_ListItem))
2537 {
2538 break;
2539 }
2540 }
2541 while (!retval.is(TokenRetval::RetVal_CloseXml));
2542
2543 if (par) par->markLast();
2544
2545 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2546 return retval;
2547}
2548
2549//---------------------------------------------------------------------------
2550
2552{
2553 AUTO_TRACE();
2554 Token retval = Token::make_RetVal_OK();
2555 int num=1;
2556 auto ns = AutoNodeStack(parser(),thisVariant());
2557
2558 // get next token
2559 Token tok=parser()->tokenizer.lex();
2560 // skip whitespace and paragraph breaks
2561 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2562 // should find a html tag now
2563 if (tok.is(TokenRetval::TK_HTMLTAG))
2564 {
2565 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2566 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2567 {
2568 // ok, we can go on.
2569 }
2570 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2572 ) && parser()->context.token->endTag
2573 ) // found empty list
2574 {
2575 // add dummy item to obtain valid HTML
2577 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2578 retval = Token::make_RetVal_EndList();
2579 goto endlist;
2580 }
2581 else // found some other tag
2582 {
2583 // add dummy item to obtain valid HTML
2585 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2586 "found <{}{}> instead!",parser()->context.token->endTag?"/":"",parser()->context.token->name);
2587 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2588 goto endlist;
2589 }
2590 }
2591 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2592 {
2593 // add dummy item to obtain valid HTML
2595 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2596 " for a html list item");
2597 goto endlist;
2598 }
2599 else // token other than html token
2600 {
2601 // add dummy item to obtain valid HTML
2603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found {} token instead!",
2604 tok.to_string());
2605 goto endlist;
2606 }
2607
2608 do
2609 {
2612 retval=li->parse();
2613 } while (retval.is(TokenRetval::RetVal_ListItem));
2614
2615 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2616 {
2617 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <{:c}l> block",
2618 m_type==Unordered ? 'u' : 'o');
2619 }
2620
2621endlist:
2622 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2623 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2624}
2625
2627{
2628 AUTO_TRACE();
2629 Token retval = Token::make_RetVal_OK();
2630 int num=1;
2631 auto ns = AutoNodeStack(parser(),thisVariant());
2632
2633 // get next token
2634 Token tok=parser()->tokenizer.lex();
2635 // skip whitespace and paragraph breaks
2636 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2637 // should find a html tag now
2638 if (tok.is(TokenRetval::TK_HTMLTAG))
2639 {
2640 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2641 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2642 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2643 {
2644 // ok, we can go on.
2645 }
2646 else // found some other tag
2647 {
2648 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2649 "found <{}> instead!",parser()->context.token->name);
2650 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2651 goto endlist;
2652 }
2653 }
2654 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2655 {
2656 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2657 " for a html list item");
2658 goto endlist;
2659 }
2660 else // token other than html token
2661 {
2662 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found {} token instead!",
2663 tok.to_string());
2664 goto endlist;
2665 }
2666
2667 do
2668 {
2671 retval=li->parseXml();
2672 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2673 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2674 } while (retval.is(TokenRetval::RetVal_ListItem));
2675
2676 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2677 {
2678 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"{}\"> block",
2679 m_type==Unordered ? "bullet" : "number");
2680 }
2681
2682endlist:
2683 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2684 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2685 Token::make_RetVal_OK() : retval;
2686}
2687
2688//--------------------------------------------------------------------------
2689
2691{
2692 AUTO_TRACE();
2693 Token retval = Token::make_TK_NONE();
2694 auto ns = AutoNodeStack(parser(),thisVariant());
2695
2696 // parse one or more paragraphs
2697 bool isFirst=TRUE;
2698 DocPara *par=nullptr;
2699 do
2700 {
2702 par = children().get_last<DocPara>();
2703 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2704 retval=par->parse();
2705 }
2706 while (retval.is(TokenRetval::TK_NEWPARA));
2707 if (par) par->markLast();
2708
2709 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2710 {
2711 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2712 }
2713
2714 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2715 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2716}
2717
2718//---------------------------------------------------------------------------
2719
2721{
2722 AUTO_TRACE();
2723 Token retval = Token::make_TK_NONE();
2724 auto ns = AutoNodeStack(parser(),thisVariant());
2725
2726 // parse one or more paragraphs
2727 bool isFirst=TRUE;
2728 DocPara *par=nullptr;
2729 do
2730 {
2732 par = children().get_last<DocPara>();
2733 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2734 retval=par->parse();
2735 }
2736 while (retval.is(TokenRetval::TK_NEWPARA));
2737 if (par) par->markLast();
2738
2739 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2740 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2741}
2742
2743//---------------------------------------------------------------------------
2744
2749
2750
2752{
2753 auto ns = AutoNodeStack(parser(),thisVariant());
2755 DocPara *par = &std::get<DocPara>(*m_paragraph);
2756 Token rv=par->parse();
2757 par->markFirst();
2758 par->markLast();
2759 return rv;
2760}
2761
2762//--------------------------------------------------------------------------
2763
2765{
2766 auto ns = AutoNodeStack(parser(),thisVariant());
2767 Token rv = Token::make_TK_NONE();
2768 do
2769 {
2772 rv=li->parse();
2773 } while (rv.is(TokenRetval::RetVal_ListItem));
2774 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2775}
2776
2777//--------------------------------------------------------------------------
2778
2783
2785{
2786 AUTO_TRACE();
2787 Token retval = Token::make_RetVal_OK();
2788 auto ns = AutoNodeStack(parser(),thisVariant());
2789
2790 // first parse any number of paragraphs
2791 bool isFirst=TRUE;
2792 DocPara *lastPar=nullptr;
2793 do
2794 {
2796 DocPara *par = children().get_last<DocPara>();
2797 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2798 retval=par->parse();
2799 if (!par->isEmpty())
2800 {
2801 if (lastPar) lastPar->markLast(FALSE);
2802 lastPar=par;
2803 }
2804 else
2805 {
2806 children().pop_back();
2807 }
2808 // next paragraph should be more indented than the - marker to belong
2809 // to this item
2810 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2811 if (lastPar) lastPar->markLast();
2812
2813 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2814 return retval;
2815}
2816
2817//--------------------------------------------------------------------------
2818
2825
2827{
2828 AUTO_TRACE();
2829 Token retval = Token::make_RetVal_OK();
2830 int num=1;
2831 auto ns = AutoNodeStack(parser(),thisVariant());
2833 // first item or sub list => create new list
2834 do
2835 {
2836 switch (parser()->context.token->id)
2837 {
2838 case -1:
2839 break;
2840 case DocAutoList::Unchecked: // unchecked
2841 case DocAutoList::Checked_x: // checked with x
2842 case DocAutoList::Checked_X: // checked with X
2843 num = parser()->context.token->id;
2844 break;
2845 default: // explicitly numbered list
2846 num=parser()->context.token->id; // override num with real number given
2847 break;
2848 }
2849
2851 retval = children().get_last<DocAutoListItem>()->parse();
2852 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
2853 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
2854 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
2855 // qPrint(parser()->context.token->name));
2856 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
2857 }
2858 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
2859 m_indent==parser()->context.token->indent && // at same indent level
2860 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
2861 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
2862 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
2863 );
2864
2866 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2867 return retval;
2868}
2869
2870//--------------------------------------------------------------------------
2871
2873{
2874 AUTO_TRACE();
2875 auto ns = AutoNodeStack(parser(),thisVariant());
2877 Token tok = parser()->tokenizer.lex();
2878 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2879 {
2880 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2881 {
2882 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
2883 }
2884 tok = parser()->tokenizer.lex();
2885 }
2888}
2889
2891{
2893 parser()->pushContext(); // this will create a new parser->context.token
2895 parser()->popContext(); // this will restore the old parser->context.token
2899}
2900
2901//--------------------------------------------------------------------------
2902
2907
2909{
2910 return m_title && std::get<DocTitle>(*m_title).hasTitle();
2911}
2912
2913Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
2914{
2915 AUTO_TRACE();
2916 auto ns = AutoNodeStack(parser(),thisVariant());
2917
2918 // handle case for user defined title
2919 if (userTitle)
2920 {
2922 std::get_if<DocTitle>(m_title.get())->parse();
2923 }
2924
2925 // add new paragraph as child
2926 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
2927 {
2928 std::get<DocPara>(children().back()).markLast(FALSE);
2929 }
2930 bool markFirst = children().empty();
2931 if (needsSeparator)
2932 {
2934 }
2936 DocPara *par = children().get_last<DocPara>();
2937 if (markFirst)
2938 {
2939 par->markFirst();
2940 }
2941 par->markLast();
2942
2943 // parse the contents of the paragraph
2944 Token retval = par->parse();
2945
2946 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2947 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
2948}
2949
2951{
2952 AUTO_TRACE();
2953 auto ns = AutoNodeStack(parser(),thisVariant());
2954
2956 DocTitle *title = &std::get<DocTitle>(*m_title);
2957 title->parseFromString(thisVariant(),parser()->context.token->name);
2958
2959 QCString text = parser()->context.token->text;
2960 parser()->pushContext(); // this will create a new parser->context.token
2962 parser()->popContext(); // this will restore the old parser->context.token
2963
2964 return Token::make_RetVal_OK();
2965}
2966
2968{
2969 AUTO_TRACE();
2970 auto ns = AutoNodeStack(parser(),thisVariant());
2971
2972 Token retval = Token::make_RetVal_OK();
2973 for (;;)
2974 {
2975 // add new paragraph as child
2976 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
2977 {
2978 std::get<DocPara>(children().back()).markLast(false);
2979 }
2980 bool markFirst = children().empty();
2982 DocPara *par = children().get_last<DocPara>();
2983 if (markFirst)
2984 {
2985 par->markFirst();
2986 }
2987 par->markLast();
2988
2989 // parse the contents of the paragraph
2990 retval = par->parse();
2991 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2992 if (retval.is(TokenRetval::RetVal_CloseXml))
2993 {
2994 retval = Token::make_RetVal_OK();
2995 break;
2996 }
2997 }
2998
2999 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3000 return retval;
3001}
3002
3004{
3005 DocPara *p=nullptr;
3006 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
3007 {
3009 p = children().get_last<DocPara>();
3010 }
3011 else
3012 {
3013 // Comma-separate <seealso> links.
3014 p->injectToken(Token::make_TK_WORD(),",");
3015 p->injectToken(Token::make_TK_WHITESPACE()," ");
3016 }
3017
3019 p->injectToken(Token::make_TK_LNKWORD(),word);
3021}
3022
3024{
3025 switch (m_type)
3026 {
3027 case Unknown: break;
3028 case See: return "see";
3029 case Return: return "return";
3030 case Author: // fall through
3031 case Authors: return "author";
3032 case Version: return "version";
3033 case Since: return "since";
3034 case Date: return "date";
3035 case Note: return "note";
3036 case Warning: return "warning";
3037 case Pre: return "pre";
3038 case Post: return "post";
3039 case Copyright: return "copyright";
3040 case Invar: return "invariant";
3041 case Remark: return "remark";
3042 case Attention: return "attention";
3043 case Important: return "important";
3044 case User: return "user";
3045 case Rcs: return "rcs";
3046 }
3047 return "unknown";
3048}
3049
3050//--------------------------------------------------------------------------
3051
3053{
3054 AUTO_TRACE();
3055 Token retval = Token::make_RetVal_OK();
3056 auto ns = AutoNodeStack(parser(),thisVariant());
3057 DocPara *par=nullptr;
3058 QCString saveCmdName = cmdName;
3059
3060 Token tok=parser()->tokenizer.lex();
3061 if (!tok.is(TokenRetval::TK_WHITESPACE))
3062 {
3063 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3064 saveCmdName);
3065 retval = Token::make_RetVal_EndParBlock();
3066 goto endparamlist;
3067 }
3069 tok=parser()->tokenizer.lex();
3070 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3071 {
3073 {
3074 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3075 if (typeSeparator!=-1)
3076 {
3077 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3078 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3081 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3082 {
3083 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3084 }
3085 }
3086 else
3087 {
3090 }
3091 }
3092 else if (m_type==DocParamSect::RetVal)
3093 {
3096 }
3097 //m_params.append(parser()->context.token->name);
3099 tok=parser()->tokenizer.lex();
3100 }
3102 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3103 {
3104 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3105 "argument of command {}",saveCmdName);
3106 retval = Token::make_RetVal_EndParBlock();
3107 goto endparamlist;
3108 }
3109 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3110 {
3111 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3112 {
3113 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3114 "argument of command {}",tok.to_string(),saveCmdName);
3115 }
3116 retval = Token::make_RetVal_EndParBlock();
3117 goto endparamlist;
3118 }
3119
3121 par = m_paragraphs.get_last<DocPara>();
3122 retval = par->parse();
3123 par->markFirst();
3124 par->markLast();
3125
3126endparamlist:
3127 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3128 return retval;
3129}
3130
3132{
3133 AUTO_TRACE();
3134 Token retval = Token::make_RetVal_OK();
3135 auto ns = AutoNodeStack(parser(),thisVariant());
3136
3137 parser()->context.token->name = paramName;
3139 {
3142 }
3143 else if (m_type==DocParamSect::RetVal)
3144 {
3147 }
3148
3150
3151 do
3152 {
3154 DocPara *par = m_paragraphs.get_last<DocPara>();
3155 retval = par->parse();
3156 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3157 // after </para> and before </param>
3158 {
3159 m_paragraphs.pop_back();
3160 break;
3161 }
3162 else // append the paragraph to the list
3163 {
3164 if (!m_paragraphs.empty())
3165 {
3166 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3167 }
3168 bool markFirst = m_paragraphs.empty();
3169 par = &std::get<DocPara>(m_paragraphs.back());
3170 if (markFirst)
3171 {
3172 par->markFirst();
3173 }
3174 par->markLast();
3175 }
3176
3177 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3178
3179 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3180 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3181 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3182 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3183
3184 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3185 {
3186 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3187 }
3188 else
3189 {
3190 retval = Token::make_RetVal_OK();
3191 }
3192
3193 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3194 return retval;
3195}
3196
3197//--------------------------------------------------------------------------
3198
3199Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3200{
3201 AUTO_TRACE();
3202 Token retval = Token::make_RetVal_OK();
3203 auto ns = AutoNodeStack(parser(),thisVariant());
3204
3205 if (d!=Unspecified)
3206 {
3208 }
3209
3210 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3211 {
3212 DocParamList &lastPl = std::get<DocParamList>(children().back());
3213 lastPl.markLast(false);
3214 }
3215 bool markFirst = children().empty();
3218 if (markFirst)
3219 {
3220 pl->markFirst();
3221 }
3222 pl->markLast();
3223 if (xmlContext)
3224 {
3225 retval = pl->parseXml(cmdName);
3226 }
3227 else
3228 {
3229 retval = pl->parse(cmdName);
3230 }
3231 if (retval.is(TokenRetval::RetVal_EndParBlock))
3232 {
3233 retval = Token::make_RetVal_OK();
3234 }
3235
3236 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3237 return retval;
3238}
3239
3240//--------------------------------------------------------------------------
3241
3247
3249{
3250 AUTO_TRACE();
3251 DocSimpleSect *ss=nullptr;
3252 bool needsSeparator = FALSE;
3253 if (!children().empty() && // has previous element
3254 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3255 ss->type()==t && // of same type
3256 t!=DocSimpleSect::User) // but not user defined
3257 {
3258 // append to previous section
3259 needsSeparator = TRUE;
3260 }
3261 else // start new section
3262 {
3265 }
3266 Token rv = Token::make_RetVal_OK();
3267 if (xmlContext)
3268 {
3269 return ss->parseXml();
3270 }
3271 else
3272 {
3273 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3274 }
3275 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3276}
3277
3280 bool xmlContext=FALSE,
3281 int direction=DocParamSect::Unspecified)
3282{
3283 AUTO_TRACE();
3284 DocParamSect *ps = nullptr;
3285 if (!children().empty() && // previous element
3286 (ps=children().get_last<DocParamSect>()) && // was a param sect
3287 ps->type()==t) // of same type
3288 { // append to previous section ps
3289 }
3290 else // start new section
3291 {
3293 ps = children().get_last<DocParamSect>();
3294 }
3295 Token rv=ps->parse(cmdName,xmlContext,
3296 static_cast<DocParamSect::Direction>(direction));
3297 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3298 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3299}
3300
3301void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3302{
3303 AUTO_TRACE();
3304 // get the argument of the cite command.
3305 Token tok=parser()->tokenizer.lex();
3306 if (!tok.is(TokenRetval::TK_WHITESPACE))
3307 {
3308 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3309 cmdChar,cmdName);
3310 return;
3311 }
3313 tok=parser()->tokenizer.lex();
3314 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3315 {
3316 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3317 "argument of command '{:c}{}'",cmdChar,cmdName);
3318 return;
3319 }
3320 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3321 {
3322 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3323 tok.to_string(),cmdChar,cmdName);
3324 return;
3325 }
3329
3331}
3332
3333void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3334{
3335 AUTO_TRACE();
3336 // get the argument of the emoji command.
3337 Token tok=parser()->tokenizer.lex();
3338 if (!tok.is(TokenRetval::TK_WHITESPACE))
3339 {
3340 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3341 cmdChar,cmdName);
3342 return;
3343 }
3345 tok=parser()->tokenizer.lex();
3346 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3347 {
3348 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3349 "argument of command '{:c}{}'",cmdChar,cmdName);
3351 return;
3352 }
3353 else if (!tok.is(TokenRetval::TK_WORD))
3354 {
3355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3356 tok.to_string(),cmdChar,cmdName);
3358 return;
3359 }
3362}
3363
3364void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3365{
3366 // get the argument of the cite command.
3367 Token tok=parser()->tokenizer.lex();
3368 if (!tok.is(TokenRetval::TK_WHITESPACE))
3369 {
3370 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3371 cmdChar,cmdName);
3372 return;
3373 }
3375 tok=parser()->tokenizer.lex();
3376 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3377 {
3378 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3379 "argument of command '{:c}{}'",cmdChar,cmdName);
3380 return;
3381 }
3382 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3383 {
3384 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3385 tok.to_string(),cmdChar,cmdName);
3386 return;
3387 }
3388 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3389 if (opt)
3390 {
3391 QCString optionValue;
3392 switch (opt->kind())
3393 {
3395 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3396 break;
3398 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3399 break;
3401 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3402 break;
3404 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3405 break;
3407 {
3408 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3409 optionValue="";
3410 if (!lst->empty())
3411 {
3412 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3413 static const reg::Ex marker(R"(@(\d+))");
3414 reg::Iterator it(lstFormat,marker);
3416 size_t index=0;
3417 // now replace all markers with the real text
3418 for ( ; it!=end ; ++it)
3419 {
3420 const auto &match = *it;
3421 size_t newIndex = match.position();
3422 size_t matchLen = match.length();
3423 optionValue += lstFormat.substr(index,newIndex-index);
3424 unsigned long entryIndex = std::stoul(match[1].str());
3425 if (entryIndex<(unsigned long)lst->size())
3426 {
3427 optionValue += lst->at(entryIndex);
3428 }
3429 index=newIndex+matchLen;
3430 }
3431 optionValue+=lstFormat.substr(index);
3432 }
3433 }
3434 break;
3436 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3437 cmdChar,cmdName,parser()->context.token->name);
3438 break;
3440 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3441 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3442 cmdChar,cmdName,parser()->context.token->name);
3443 break;
3445 // nothing to show here
3446 break;
3447 }
3448 if (!optionValue.isEmpty())
3449 {
3450 children().append<DocWord>(parser(),thisVariant(),optionValue);
3451 }
3452 }
3453 else
3454 {
3455 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3456 cmdChar,cmdName,parser()->context.token->name);
3458 }
3460}
3461
3463{
3464 AUTO_TRACE();
3465 Token retval=parser()->tokenizer.lex();
3466 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3468 retval=parser()->tokenizer.lex();
3469 if (retval.is(TokenRetval::RetVal_OK))
3470 {
3474 if (!ref->parse())
3475 {
3476 children().pop_back();
3477 }
3478 }
3480 return retval;
3481}
3482
3483void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3484{
3485 AUTO_TRACE();
3486 QCString fmt;
3487 QCString date;
3488 Token tok=parser()->tokenizer.lex();
3489 if (!tok.is(TokenRetval::TK_WHITESPACE))
3490 {
3491 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3492 cmdChar,cmdName);
3493 return;
3494 }
3496 tok = parser()->tokenizer.lex();
3497 if (!tok.is(TokenRetval::TK_WORD))
3498 {
3499 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3500 cmdChar,cmdName);
3502 return;
3503 }
3504 fmt = parser()->context.token->name;
3505
3507 tok = parser()->tokenizer.lex();
3508
3509 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3510 QCString specDate = specDateRaw.stripWhiteSpace();
3511 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3512 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3513 {
3514 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3515 cmdChar,cmdName);
3517 return;
3518 }
3519
3520 std::tm dat{};
3521 int specFormat=0;
3522 QCString err = dateTimeFromString(specDate,dat,specFormat);
3523 if (!err.isEmpty())
3524 {
3525 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3526 cmdChar,cmdName,err);
3528 return;
3529 }
3530
3531 int usedFormat=0;
3532 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3533
3534 // warn the user if the format contains markers that are not explicitly filled in
3535 for (int i=0;i<SF_NumBits;i++)
3536 {
3537 int bitMask = 1<<i;
3538 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3539 {
3540 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{:c}{}' <format> parameter '{}' has {} related markers which are not specified in the <date_time> parameter '{}'. Filling in the current value for {} instead.",
3541 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3542 }
3543 }
3544
3545 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3546 if (specDateOnlyWS) // specDate is only whitespace
3547 {
3549 }
3551}
3552
3553void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3554{
3555 AUTO_TRACE();
3557 Token tok = parser()->tokenizer.lex();
3558 if (!tok.is(TokenRetval::TK_WORD))
3559 {
3560 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
3561 cmdChar,cmdName);
3562 return;
3563 }
3565}
3566
3567void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3568{
3569 AUTO_TRACE();
3570 Token tok=parser()->tokenizer.lex();
3571 if (!tok.is(TokenRetval::TK_WHITESPACE))
3572 {
3573 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3574 cmdChar,cmdName);
3575 return;
3576 }
3578 tok=parser()->tokenizer.lex();
3580 if (!tok.is(TokenRetval::TK_WORD))
3581 {
3582 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3583 tok.to_string(),cmdChar,cmdName);
3584 return;
3585 }
3588}
3589
3590
3592{
3593 AUTO_TRACE("cmdName={}",cmdName);
3594 QCString saveCmdName = cmdName;
3595 Token tok=parser()->tokenizer.lex();
3596 if (!tok.is(TokenRetval::TK_WHITESPACE))
3597 {
3598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3599 saveCmdName);
3600 return;
3601 }
3603 tok=parser()->tokenizer.lex();
3605 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3606 {
3607 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3608 "argument of command {}", saveCmdName);
3609 return;
3610 }
3611 else if (!tok.is(TokenRetval::TK_WORD))
3612 {
3613 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3614 tok.to_string(),saveCmdName);
3615 return;
3616 }
3617 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3618 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3619 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3620 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3621 //TODO get from context the stripCodeComments()
3622 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3626 stripCodeComments,
3629 );
3631 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3632 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3633 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3634 bool isFirst = !n1 || // no last node
3635 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3636 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3637 op->markFirst(isFirst);
3638 op->markLast(true);
3639 if (n1_docIncOp)
3640 {
3641 n1_docIncOp->markLast(false);
3642 }
3643 else if (n1_docWs && n2_docIncOp)
3644 {
3645 n2_docIncOp->markLast(false);
3646 }
3647 op->parse();
3648}
3649
3650template<class T>
3651void DocPara::handleFile(const QCString &cmdName)
3652{
3653 AUTO_TRACE("cmdName={}",cmdName);
3654 QCString saveCmdName = cmdName;
3655 Token tok=parser()->tokenizer.lex();
3656 if (!tok.is(TokenRetval::TK_WHITESPACE))
3657 {
3658 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3659 saveCmdName);
3660 return;
3661 }
3663 tok=parser()->tokenizer.lex();
3665 if (!tok.is(TokenRetval::TK_WORD))
3666 {
3667 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3668 tok.to_string(),saveCmdName);
3669 return;
3670 }
3671 QCString name = parser()->context.token->name;
3672 children().append<T>(parser(),thisVariant(),name,
3676 auto df = children().get_last<T>();
3677 if (!df->parse())
3678 {
3679 children().pop_back();
3680 }
3681}
3682
3689
3690void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3691{
3692 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3693 QCString saveCmdName = cmdName;
3694 Token tok=parser()->tokenizer.lex();
3695 if (!tok.is(TokenRetval::TK_WHITESPACE))
3696 {
3697 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3698 saveCmdName);
3699 return;
3700 }
3702 tok=parser()->tokenizer.lex();
3703 if (!tok.is(TokenRetval::TK_WORD))
3704 {
3705 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3706 tok.to_string(),saveCmdName);
3707 return;
3708 }
3709 if (saveCmdName == "javalink")
3710 {
3712 parser()->context.nodeStack.size(),
3713 DocStyleChange::Code,cmdName,TRUE);
3714 }
3717 DocLink *lnk = children().get_last<DocLink>();
3718 if (saveCmdName == "javalink")
3719 {
3721 parser()->context.nodeStack.size(),
3722 DocStyleChange::Code,cmdName,FALSE);
3723 }
3724 QCString leftOver = lnk->parse(isJavaLink);
3725 if (!leftOver.isEmpty())
3726 {
3727 children().append<DocWord>(parser(),thisVariant(),leftOver);
3728 }
3729}
3730
3731void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3732{
3733 AUTO_TRACE("cmdName={}",cmdName);
3734 QCString saveCmdName = cmdName;
3735 Token tok=parser()->tokenizer.lex();
3736 if (!tok.is(TokenRetval::TK_WHITESPACE))
3737 {
3738 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3739 cmdChar,qPrint(saveCmdName));
3740 return;
3741 }
3743 tok=parser()->tokenizer.lex(); // get the reference id
3744 if (!tok.is(TokenRetval::TK_WORD))
3745 {
3746 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3747 tok.to_string(),cmdChar,saveCmdName);
3748 goto endref;
3749 }
3753 children().get_last<DocRef>()->parse();
3754endref:
3756}
3757
3759{
3760 AUTO_TRACE("cmdName={}",cmdName);
3761 QCString saveCmdName = cmdName;
3762 Token tok=parser()->tokenizer.lex();
3763 bool isBlock = false;
3764 bool trimLeft = false;
3765 bool localScope = false;
3766 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3767 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3768 {
3770 parser()->tokenizer.lex();
3772 StringVector optList=split(parser()->context.token->name.str(),",");
3773 auto contains = [&optList](const char *kw)
3774 {
3775 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
3776 };
3777 localScope = contains("local");
3778 if (contains("nostrip"))
3779 {
3780 stripCodeComments = false;
3781 }
3782 else if (contains("strip"))
3783 {
3784 stripCodeComments = true;
3785 }
3786 if (t==DocInclude::Snippet && contains("trimleft"))
3787 {
3788 trimLeft = true;
3789 }
3790
3791 if (contains("lineno"))
3792 {
3796 }
3797 tok=parser()->tokenizer.lex();
3798 if (!tok.is(TokenRetval::TK_WHITESPACE))
3799 {
3800 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3801 saveCmdName);
3802 return;
3803 }
3804 }
3805 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
3806 {
3808 parser()->tokenizer.lex();
3809 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
3811 parser()->tokenizer.lex();
3812 }
3813 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3814 {
3815 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3816 saveCmdName);
3817 return;
3818 }
3820 tok=parser()->tokenizer.lex();
3822 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3823 {
3824 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3825 "argument of command {}",saveCmdName);
3826 return;
3827 }
3828 else if (!tok.is(TokenRetval::TK_WORD))
3829 {
3830 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3831 tok.to_string(),saveCmdName);
3832 return;
3833 }
3834 QCString fileName = parser()->context.token->name;
3835 QCString blockId;
3837 {
3838 if (fileName == "this") fileName=parser()->context.fileName;
3840 tok=parser()->tokenizer.lex();
3842 if (!tok.is(TokenRetval::TK_WORD))
3843 {
3844 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
3845 tok.to_string(),saveCmdName);
3846 return;
3847 }
3848 blockId = "["+parser()->context.token->name+"]";
3849 }
3850
3852 thisVariant(),
3853 fileName,
3854 localScope ? parser()->context.context : "",
3855 t,
3856 stripCodeComments,
3859 blockId,isBlock,trimLeft);
3861}
3862
3863void DocPara::handleSection(char cmdChar,const QCString &cmdName)
3864{
3865 AUTO_TRACE("cmdName={}",cmdName);
3866 QCString saveCmdName = cmdName;
3867 // get the argument of the section command.
3868 Token tok=parser()->tokenizer.lex();
3869 if (!tok.is(TokenRetval::TK_WHITESPACE))
3870 {
3871 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3872 cmdChar,saveCmdName);
3873 return;
3874 }
3875 tok=parser()->tokenizer.lex();
3876 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3877 {
3878 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3879 "argument of command '{:c}{}'", cmdChar,saveCmdName);
3880 return;
3881 }
3882 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3883 {
3884 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3885 tok.to_string(),cmdChar,saveCmdName);
3886 return;
3887 }
3890 parser()->tokenizer.lex();
3892}
3893
3894Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
3895{
3896 AUTO_TRACE();
3897 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
3898 Token retval = children().get_last<DocHtmlHeader>()->parse();
3899 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
3900}
3901
3902// For XML tags whose content is stored in attributes rather than
3903// contained within the element, we need a way to inject the attribute
3904// text into the current paragraph.
3905bool DocPara::injectToken(Token tok,const QCString &tokText)
3906{
3907 AUTO_TRACE();
3908 parser()->context.token->name = tokText;
3909 return parser()->defaultHandleToken(thisVariant(),tok,children());
3910}
3911
3913{
3914 AUTO_TRACE();
3915 Token retval = parser()->tokenizer.lex();
3916 QCString lang = parser()->context.token->name;
3917 if (!lang.isEmpty() && lang.at(0)!='.')
3918 {
3919 lang="."+lang;
3920 }
3921 if (parser()->context.xmlComment)
3922 {
3923 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
3924 }
3925 // search for the first non-whitespace line, index is stored in li
3926 size_t i=0,li=0,l=parser()->context.token->verb.length();
3927 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
3928 {
3929 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
3930 i++;
3931 }
3934 stripIndentation(parser()->context.token->verb.mid(li)),
3938 FALSE,lang);
3939 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3940 {
3941 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
3942 }
3944 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3945 return retval;
3946}
3947
3949{
3950 if (parser()->context.memberDef) // inheriting docs from a member
3951 {
3952 const MemberDef *reMd = parser()->context.memberDef->reimplements();
3953 if (reMd) // member from which was inherited.
3954 {
3955 const MemberDef *thisMd = parser()->context.memberDef;
3956 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
3957 parser()->pushContext();
3958 parser()->context.scope=reMd->getOuterScope();
3959 if (parser()->context.scope!=Doxygen::globalScope)
3960 {
3962 }
3963 parser()->context.memberDef=reMd;
3964 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
3965 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
3966 parser()->context.copyStack.push_back(reMd);
3969 parser()->context.copyStack.pop_back();
3970 auto hasParamCommand = parser()->context.hasParamCommand;
3971 auto hasReturnCommand = parser()->context.hasReturnCommand;
3972 auto retvalsFound = parser()->context.retvalsFound;
3973 auto paramsFound = parser()->context.paramsFound;
3974 parser()->popContext();
3975 parser()->context.hasParamCommand = hasParamCommand;
3976 parser()->context.hasReturnCommand = hasReturnCommand;
3977 parser()->context.retvalsFound = retvalsFound;
3978 parser()->context.paramsFound = paramsFound;
3979 parser()->context.memberDef = thisMd;
3980 }
3981 }
3982}
3983
3984
3985Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
3986{
3987 AUTO_TRACE("cmdName={}",cmdName);
3988 Token retval = Token::make_RetVal_OK();
3989 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
3990 switch (cmdId)
3991 {
3993 {
3994 std::string str{cmdChar};
3995 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
3996 if (isAliasCmd(cmdName.view()))
3997 {
3998 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
3999 }
4000 else
4001 {
4002 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
4003 }
4004 }
4005 break;
4008 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4010 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4011 break;
4014 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4016 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4017 break;
4020 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4022 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4023 break;
4026 break;
4029 break;
4032 break;
4035 break;
4038 break;
4041 break;
4044 break;
4047 break;
4050 break;
4053 break;
4057 break;
4062 break;
4065 break;
4068 break;
4071 break;
4074 break;
4077 break;
4080 break;
4083 break;
4088 break;
4092 break;
4095 break;
4098 break;
4101 break;
4104 break;
4107 break;
4110 break;
4113 break;
4116 break;
4119 break;
4122 break;
4125 break;
4128 break;
4131 break;
4134 break;
4137 break;
4139 {
4141 retval = children().get_last<DocSimpleList>()->parse();
4142 }
4143 break;
4145 {
4146 handleSection(cmdChar,cmdName);
4147 retval = Token::make_RetVal_Section();
4148 }
4149 break;
4151 {
4152 handleSection(cmdChar,cmdName);
4153 retval = Token::make_RetVal_Subsection();
4154 }
4155 break;
4157 {
4158 handleSection(cmdChar,cmdName);
4159 retval = Token::make_RetVal_Subsubsection();
4160 }
4161 break;
4163 {
4164 handleSection(cmdChar,cmdName);
4165 retval = Token::make_RetVal_Paragraph();
4166 }
4167 break;
4169 {
4170 handleSection(cmdChar,cmdName);
4171 retval = Token::make_RetVal_SubParagraph();
4172 }
4173 break;
4175 {
4176 handleSection(cmdChar,cmdName);
4177 retval = Token::make_RetVal_SubSubParagraph();
4178 }
4179 break;
4181 {
4183 retval = handleStartCode();
4184 }
4185 break;
4187 {
4189 retval = handleStartCode();
4190 }
4191 break;
4193 {
4195 retval = parser()->tokenizer.lex();
4197 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4198 {
4199 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4200 }
4202 }
4203 break;
4205 {
4207 retval = parser()->tokenizer.lex();
4209 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4210 {
4211 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4212 }
4214 }
4215 break;
4217 {
4219 retval = parser()->tokenizer.lex();
4221 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4222 {
4223 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4224 }
4226 }
4227 break;
4229 {
4231 retval = parser()->tokenizer.lex();
4233 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4234 {
4235 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4236 }
4238 }
4239 break;
4241 {
4243 retval = parser()->tokenizer.lex();
4245 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4246 {
4247 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4248 }
4250 }
4251 break;
4253 {
4255 retval = parser()->tokenizer.lex();
4257 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4258 {
4259 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4260 }
4262 }
4263 break;
4265 {
4268 parser()->tokenizer.lex();
4269
4270 QCString fullMatch = parser()->context.token->verb;
4271 int idx = fullMatch.find('{');
4272 int idxEnd = fullMatch.find("}",idx+1);
4273 StringVector optList;
4274 if (idx != -1) // options present
4275 {
4276 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4277 optList = split(optStr.str(),",");
4278 for (const auto &opt : optList)
4279 {
4280 if (opt.empty()) continue;
4281 QCString locOpt(opt);
4282 locOpt = locOpt.stripWhiteSpace().lower();
4283 if (locOpt == "code")
4284 {
4286 }
4287 else if (!locOpt.isEmpty())
4288 {
4289 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4290 }
4291 }
4292 }
4293
4295 retval = parser()->tokenizer.lex();
4297 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4298 {
4299 if (t == DocVerbatim::JavaDocCode)
4300 {
4301 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4302 }
4303 else
4304 {
4305 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4306 }
4307 }
4309 }
4310 break;
4313 {
4314 if (cmdId == CommandType::CMD_VERBATIM)
4315 {
4317 }
4318 else
4319 {
4321 }
4322 retval = parser()->tokenizer.lex();
4324 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4325 {
4326 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4327 }
4329 }
4330 break;
4332 {
4341 QCString width,height;
4342 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4344 retval = parser()->tokenizer.lex();
4345 dv->setText(parser()->context.token->verb);
4346 dv->setWidth(width);
4347 dv->setHeight(height);
4348 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4349 if (!Config_getBool(HAVE_DOT))
4350 {
4351 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4352 children().pop_back();
4353 }
4354 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4355 {
4356 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4357 }
4359 }
4360 break;
4362 {
4371 QCString width,height;
4372 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4374 retval = parser()->tokenizer.lex();
4375 dv->setText(parser()->context.token->verb);
4376 dv->setWidth(width);
4377 dv->setHeight(height);
4378 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4379 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4380 {
4381 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4382 }
4384 }
4385 break;
4387 {
4388 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4390 parser()->tokenizer.lex();
4391 QCString fullMatch = parser()->context.token->sectionId;
4392 QCString sectionId = "";
4393 int idx = fullMatch.find('{');
4394 int idxEnd = fullMatch.find("}",idx+1);
4395 StringVector optList;
4396 QCString engine;
4397 if (idx != -1) // options present
4398 {
4399 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4400 optList = split(optStr.str(),",");
4401 for (const auto &opt : optList)
4402 {
4403 if (opt.empty()) continue;
4404 bool found = false;
4405 QCString locOpt(opt);
4406 locOpt = locOpt.stripWhiteSpace().lower();
4407 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4408 {
4409 if (!engine.isEmpty())
4410 {
4411 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4412 }
4413 engine = locOpt;
4414 found = true;
4415 }
4416 if (!found)
4417 {
4418 if (sectionId.isEmpty())
4419 {
4420 sectionId = opt;
4421 }
4422 else
4423 {
4424 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4425 }
4426 }
4427 }
4428 }
4429 else
4430 {
4431 sectionId = parser()->context.token->sectionId;
4432 }
4433 if (engine.isEmpty()) engine = "uml";
4434
4435 if (sectionId.isEmpty())
4436 {
4438 retval = parser()->tokenizer.lex();
4439 assert(retval.is(TokenRetval::RetVal_OK));
4440
4441 sectionId = parser()->context.token->sectionId;
4442 sectionId = sectionId.stripWhiteSpace();
4443 }
4444
4445 QCString plantFile(sectionId);
4450 FALSE,plantFile);
4452 dv->setEngine(engine);
4454 QCString width,height;
4455 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4457 retval = parser()->tokenizer.lex();
4458 int line = 0;
4459 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4460 if (engine == "ditaa")
4461 {
4462 dv->setUseBitmap(true);
4463 }
4464 else if (engine == "uml")
4465 {
4466 int i = trimmedVerb.find('\n');
4467 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4468 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4469 }
4470 dv->setText(trimmedVerb);
4471 dv->setWidth(width);
4472 dv->setHeight(height);
4473 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4474 if (jarPath.isEmpty())
4475 {
4476 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4477 children().pop_back();
4478 }
4479 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4480 {
4481 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4482 }
4484 }
4485 break;
4487 retval = Token::make_RetVal_EndParBlock();
4488 break;
4504 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4505 break;
4507 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4508 break;
4510 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4511 break;
4513 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4514 break;
4517 break;
4519 retval = handleXRefItem();
4520 break;
4522 {
4524 }
4525 break;
4528 {
4530 }
4531 break;
4533 {
4535 }
4536 break;
4538 {
4542 retval = children().get_last<DocIndexEntry>()->parse();
4543 }
4544 break;
4546 retval = Token::make_RetVal_Internal();
4547 break;
4549 retval = Token::make_RetVal_EndInternal();
4550 break;
4552 {
4554 retval = children().get_last<DocParBlock>()->parse();
4555 }
4556 break;
4557 case CommandType::CMD_COPYDOC: // fall through
4558 case CommandType::CMD_COPYBRIEF: // fall through
4560 //retval = Token::make_RetVal_CopyDoc();
4561 // these commands should already be resolved by processCopyDoc()
4562 break;
4565 break;
4568 break;
4571 break;
4574 break;
4577 break;
4580 break;
4583 break;
4586 break;
4589 break;
4592 break;
4595 break;
4598 break;
4601 break;
4604 break;
4607 break;
4610 break;
4613 break;
4615 if (!Config_getBool(HAVE_DOT))
4616 {
4617 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4618 "ignoring \\dotfile command because HAVE_DOT is not set");
4619 }
4620 else
4621 {
4622 handleFile<DocDotFile>(cmdName);
4623 }
4624 break;
4627 break;
4629 handleFile<DocMscFile>(cmdName);
4630 break;
4632 handleFile<DocDiaFile>(cmdName);
4633 break;
4636 break;
4638 handleLink(cmdName,FALSE);
4639 break;
4641 handleLink(cmdName,TRUE);
4642 break;
4644 handleCite(cmdChar,cmdName);
4645 break;
4647 handleEmoji(cmdChar,cmdName);
4648 break;
4650 handleDoxyConfig(cmdChar,cmdName);
4651 break;
4652 case CommandType::CMD_REF: // fall through
4654 handleRef(cmdChar,cmdName);
4655 break;
4657 {
4660 }
4661 break;
4663 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4664 break;
4666 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4667 break;
4669 {
4671 }
4672 break;
4673 //case CommandType::CMD_LANGSWITCH:
4674 // retval = handleLanguageSwitch();
4675 // break;
4677 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4678 {
4681 }
4682 break;
4685 break;
4687 handleShowDate(cmdChar,cmdName);
4688 break;
4690 handleILine(cmdChar,cmdName);
4691 break;
4693 handleIFile(cmdChar,cmdName);
4694 break;
4696 {
4698 (void)parser()->tokenizer.lex();
4700 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4702 }
4703 break;
4704 default:
4705 // we should not get here!
4706 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4707 break;
4708 }
4709 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4710 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4711 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4712 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4713 TokenRetval::RetVal_EndInternal)
4714 );
4715 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4716 return retval;
4717}
4718
4719static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4720 const char *attrName,
4721 QCString *result)
4722{
4723
4724 for (const auto &opt : tagHtmlAttribs)
4725 {
4726 if (opt.name==attrName)
4727 {
4728 *result = opt.value;
4729 return TRUE;
4730 }
4731 }
4732 return FALSE;
4733}
4734
4735Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4736{
4737 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4738 Token retval = Token::make_RetVal_OK();
4739 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4740 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4743 {
4744 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4745 tagName);
4746 }
4747 switch (tagId)
4748 {
4750 if (!parser()->context.token->emptyTag)
4751 {
4753 tagHtmlAttribs,DocHtmlList::Unordered);
4754 retval=children().get_last<DocHtmlList>()->parse();
4755 }
4756 break;
4758 if (!parser()->context.token->emptyTag)
4759 {
4761 tagHtmlAttribs,DocHtmlList::Ordered);
4762 retval=children().get_last<DocHtmlList>()->parse();
4763 }
4764 break;
4766 if (parser()->context.token->emptyTag) break;
4768 {
4769 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4770 }
4771 else
4772 {
4773 retval = Token::make_RetVal_ListItem();
4774 }
4775 break;
4777 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
4778 break;
4780 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
4781 break;
4783 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
4784 break;
4786 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
4787 break;
4789 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
4790 break;
4792 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
4793 break;
4795 if (parser()->context.token->emptyTag) break;
4796 if (parser()->context.xmlComment)
4797 // for C# source or inside a <summary> or <remark> section we
4798 // treat <code> as an XML tag (so similar to @code)
4799 {
4801 retval = handleStartCode();
4802 }
4803 else // normal HTML markup
4804 {
4805 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4806 }
4807 break;
4809 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
4810 break;
4812 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Typewriter,tagName,&parser()->context.token->attribs);
4813 break;
4815 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
4816 break;
4818 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
4819 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
4820 break;
4822 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
4823 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
4824 break;
4826 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
4827 break;
4829 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
4830 break;
4832 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
4833 break;
4835 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
4836 break;
4838 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
4839 break;
4841 if (parser()->context.token->emptyTag) break;
4842 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
4845 break;
4847 retval = Token::make_TK_NEWPARA();
4848 break;
4850 if (!parser()->context.token->emptyTag)
4851 {
4852 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
4853 retval=children().get_last<DocHtmlDescList>()->parse();
4854 }
4855 break;
4857 if (insideDL(thisVariant()))
4858 {
4859 retval = Token::make_RetVal_DescTitle();
4860 }
4861 else
4862 {
4863 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
4864 }
4865 break;
4867 if (insideDL(thisVariant()))
4868 {
4869 retval = Token::make_RetVal_DescData();
4870 }
4871 else
4872 {
4873 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
4874 }
4875 break;
4877 if (!parser()->context.token->emptyTag)
4878 {
4879 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
4880 retval=children().get_last<DocHtmlTable>()->parse();
4881 }
4882 break;
4884 retval = Token::make_RetVal_TableRow();
4885 break;
4887 retval = Token::make_RetVal_TableCell();
4888 break;
4890 retval = Token::make_RetVal_TableHCell();
4891 break;
4895 // for time being ignore </t....> tag
4896 break;
4898 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
4899 break;
4901 {
4902 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
4903 }
4904 break;
4906 {
4907 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
4908 }
4909 break;
4911 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
4912 break;
4914 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
4915 break;
4917 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
4918 break;
4920 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
4921 break;
4923 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
4924 break;
4926 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
4927 break;
4929 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
4930 break;
4932 {
4933 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
4934 }
4935 break;
4937 if (!parser()->context.token->emptyTag)
4938 {
4939 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
4940 retval=children().get_last<DocHtmlDetails>()->parse();
4941 }
4942 break;
4944 if (!parser()->context.token->emptyTag)
4945 {
4946 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
4947 retval = children().get_last<DocHtmlBlockQuote>()->parse();
4948 }
4949 break;
4950
4953 {
4954 if (!parser()->context.token->emptyTag)
4955 {
4957 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
4958 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
4959 if (d)
4960 {
4961 if (!d->summary()) // details section does not have a summary yet
4962 {
4963 d->parseSummary(n,parser()->context.token->attribs);
4964 }
4965 else
4966 {
4967 retval = Token::make_TK_NEWPARA();
4968 }
4969 }
4970 }
4971 }
4972 break;
4976 // fall through
4979 if (!children().empty())
4980 {
4981 retval = Token::make_TK_NEWPARA();
4982 }
4983 break;
4985 if (insideTable(thisVariant()))
4986 {
4987 retval = Token::make_RetVal_TableCell();
4988 }
4989 break;
4990 case HtmlTagType::XML_C:
4991 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4992 break;
4995 {
4997 QCString paramName;
4998 if (findAttribute(tagHtmlAttribs,"name",&paramName))
4999 {
5000 if (paramName.isEmpty())
5001 {
5002 if (Config_getBool(WARN_NO_PARAMDOC))
5003 {
5004 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5005 }
5006 }
5007 else
5008 {
5009 retval = handleParamSection(paramName,
5011 TRUE);
5012 }
5013 }
5014 else
5015 {
5016 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5017 }
5018 }
5019 break;
5022 {
5023 QCString paramName;
5024 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5025 {
5026 //printf("paramName=%s\n",qPrint(paramName));
5028 children().append<DocWord>(parser(),thisVariant(),paramName);
5030 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5031 }
5032 else
5033 {
5034 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5035 }
5036 }
5037 break;
5039 {
5041 QCString exceptName;
5042 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5043 {
5044 unescapeCRef(exceptName);
5045 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5046 }
5047 else
5048 {
5049 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5050 }
5051 }
5052 break;
5055 if (insideTable(thisVariant()))
5056 {
5057 retval = Token::make_RetVal_TableRow();
5058 }
5059 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5060 {
5061 retval = Token::make_RetVal_ListItem();
5062 }
5063 else
5064 {
5065 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5066 }
5067 break;
5072 break;
5074 if (insideTable(thisVariant()))
5075 {
5076 retval = Token::make_RetVal_TableCell();
5077 }
5078 break;
5080 // I'm not sure if <see> is the same as <seealso> or if it
5081 // should you link a member without producing a section. The
5082 // C# specification is extremely vague about this (but what else
5083 // can we expect from Microsoft...)
5084 {
5085 QCString cref;
5086 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5087 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5088 {
5089 unescapeCRef(cref);
5090 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5091 {
5092 bool inSeeBlock = parser()->context.inSeeBlock;
5093 parser()->context.token->name = cref;
5096 parser()->context.inSeeBlock = inSeeBlock;
5097 }
5098 else // <see cref="...">...</see> style
5099 {
5100 //DocRef *ref = new DocRef(this,cref);
5101 //children().append(ref);
5102 //ref->parse();
5105 DocLink *lnk = children().get_last<DocLink>();
5106 QCString leftOver = lnk->parse(FALSE,TRUE);
5107 if (!leftOver.isEmpty())
5108 {
5109 children().append<DocWord>(parser(),thisVariant(),leftOver);
5110 }
5111 }
5112 }
5113 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5114 {
5115 bool inSeeBlock = parser()->context.inSeeBlock;
5116 parser()->context.token->name = cref;
5121 parser()->context.inSeeBlock = inSeeBlock;
5122 }
5123 else
5124 {
5125 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5126 }
5127 }
5128 break;
5130 {
5132 QCString cref;
5133 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5134 {
5135 unescapeCRef(cref);
5136 // Look for an existing "see" section
5137 DocNodeVariant *vss=nullptr;
5138 for (auto &n : children())
5139 {
5140 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5141 if (candidate && candidate->type()==DocSimpleSect::See)
5142 {
5143 vss = &n;
5144 }
5145 }
5146
5147 if (!vss) // start new section
5148 {
5150 vss = &children().back();
5151 }
5152
5153 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5154 retval = Token::make_RetVal_OK();
5155 }
5156 else
5157 {
5158 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5159 }
5160 }
5161 break;
5163 {
5164 QCString type;
5165 findAttribute(tagHtmlAttribs,"type",&type);
5167 HtmlAttribList emptyList;
5168 if (type=="number")
5169 {
5170 listType=DocHtmlList::Ordered;
5171 }
5172 if (type=="table")
5173 {
5174 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5175 retval=children().get_last<DocHtmlTable>()->parseXml();
5176 }
5177 else
5178 {
5179 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5180 retval=children().get_last<DocHtmlList>()->parseXml();
5181 }
5182 }
5183 break;
5186 // These tags are defined in .Net but are currently unsupported
5188 break;
5190 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5191 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5192 break;
5195 break;
5196 default:
5197 // we should not get here!
5198 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5199 ASSERT(0);
5200 break;
5201 }
5202 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5203 return retval;
5204}
5205
5207{
5208 AUTO_TRACE("tagName={}",tagName);
5209 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5210 Token retval = Token::make_RetVal_OK();
5211 switch (tagId)
5212 {
5214 if (!insideUL(thisVariant()))
5215 {
5216 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5217 }
5218 else
5219 {
5220 retval = Token::make_RetVal_EndList();
5221 }
5222 break;
5224 if (!insideOL(thisVariant()))
5225 {
5226 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5227 }
5228 else
5229 {
5230 retval = Token::make_RetVal_EndList();
5231 }
5232 break;
5234 if (!insideLI(thisVariant()))
5235 {
5236 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5237 }
5238 else
5239 {
5240 // ignore </li> tags
5241 }
5242 break;
5244 if (!insideDetails(thisVariant()))
5245 {
5246 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5247 }
5248 else
5249 {
5250 retval = Token::make_RetVal_EndHtmlDetails();
5251 }
5252 break;
5255 {
5256 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5257 }
5258 else
5259 {
5260 retval = Token::make_RetVal_EndBlockQuote();
5261 }
5262 break;
5265 break;
5268 break;
5271 break;
5274 break;
5277 break;
5280 break;
5283 break;
5286 break;
5289 break;
5292 break;
5295 break;
5298 break;
5301 break;
5304 break;
5307 break;
5310 break;
5313 break;
5318 break;
5320 retval = Token::make_TK_NEWPARA();
5321 break;
5323 retval = Token::make_RetVal_EndDesc();
5324 break;
5326 // ignore </dt> tag
5327 break;
5329 // ignore </dd> tag
5330 break;
5332 retval = Token::make_RetVal_EndTable();
5333 break;
5335 // ignore </tr> tag
5336 break;
5338 // ignore </td> tag
5339 break;
5341 // ignore </th> tag
5342 break;
5346 // for time being ignore </t....> tag
5347 break;
5349 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5350 break;
5352 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5353 break;
5355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5356 break;
5358 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5359 break;
5361 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5362 break;
5364 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5365 break;
5367 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5368 break;
5370 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5371 break;
5373 break;
5375 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5376 break;
5378 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5379 // ignore </a> tag (can be part of <a name=...></a>
5380 break;
5381
5383 break;
5385 retval = Token::make_TK_NEWPARA();
5386 break;
5399 retval = Token::make_RetVal_CloseXml();
5400 break;
5401 case HtmlTagType::XML_C:
5403 break;
5411 // These tags are defined in .Net but are currently unsupported
5412 break;
5414 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5415 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5416 break;
5417 default:
5418 // we should not get here!
5419 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5420 ASSERT(0);
5421 break;
5422 }
5423 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5424 return retval;
5425}
5426
5428{
5429 // expected hierarchy:
5430 // 1. DocAutoListItem <- n
5431 // 2. DocAutoList <- parent(n)
5432 // 3. DocPara <- parent(parent(n))
5433
5434 // step 1
5435 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5436 {
5437 return false;
5438 }
5439
5440 // step 2
5441 n = parent(n);
5442 int indent = 0;
5443 const auto docAutoList = std::get_if<DocAutoList>(n);
5444 if (docAutoList) // capture indent
5445 {
5446 indent = docAutoList->indent();
5447 }
5448 else
5449 {
5450 return false;
5451 }
5452
5453 // step 3
5454 n = parent(n);
5455 const auto docPara = std::get_if<DocPara>(n);
5456 if (docPara)
5457 {
5458 QCString tagNameLower = QCString(parser->context.token->name).lower();
5459 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5460 {
5461 return std::get<DocStyleChange>(*stack.top());
5462 };
5463
5464 if (parser->context.styleStack.empty() || // no style change
5465 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5466 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5467 )
5468 {
5469 // insert an artificial 'end of autolist' marker and parse again
5470 QCString indentStr;
5471 indentStr.fill(' ',indent);
5472 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5473 return true;
5474 }
5475 }
5476 return false;
5477}
5478
5480{
5481 AUTO_TRACE();
5482 auto ns = AutoNodeStack(parser(),thisVariant());
5483 // handle style commands "inherited" from the previous paragraph
5485 Token tok=parser()->tokenizer.lex();
5486 Token retval = Token::make_TK_NONE();
5487 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5488 {
5489reparsetoken:
5490 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5491 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5492 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5493 )
5494 {
5495 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5496 }
5497 switch(tok.value())
5498 {
5499 case TokenRetval::TK_WORD:
5501 break;
5502 case TokenRetval::TK_LNKWORD:
5504 break;
5505 case TokenRetval::TK_URL:
5507 break;
5508 case TokenRetval::TK_WHITESPACE:
5509 {
5510 // prevent leading whitespace and collapse multiple whitespace areas
5511 if (insidePRE(thisVariant()) || // all whitespace is relevant
5512 (
5513 // remove leading whitespace
5514 !children().empty() &&
5515 // and whitespace after certain constructs
5519 )
5520 )
5521 {
5523 }
5524 }
5525 break;
5526 case TokenRetval::TK_LISTITEM:
5527 {
5528 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5529 const DocNodeVariant *n=parent();
5530 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5531 const DocAutoList *al = std::get_if<DocAutoList>(n);
5532 if (al) // we found an auto list up in the hierarchy
5533 {
5534 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5535 if (al->indent()>=parser()->context.token->indent)
5536 // new item at the same or lower indent level
5537 {
5538 retval = Token::make_TK_LISTITEM();
5539 goto endparagraph;
5540 }
5541 }
5542
5543 // determine list depth
5544 int depth = 0;
5545 n=parent();
5546 while (n)
5547 {
5548 al = std::get_if<DocAutoList>(n);
5549 if (al && al->isEnumList()) depth++;
5550 n=::parent(n);
5551 }
5552
5553 // first item or sub list => create new list
5554 do
5555 {
5558 parser()->context.token->isEnumList,depth,
5560 al = children().get_last<DocAutoList>();
5561 retval = children().get_last<DocAutoList>()->parse();
5562 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5563 al->indent()==parser()->context.token->indent // at same indent level
5564 );
5565
5566 // check the return value
5567 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5568 {
5569 // Reparse the token that ended the section at this level,
5570 // so a new simple section will be started at this level.
5571 // This is the same as unputting the last read token and continuing.
5573 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5574 {
5577 tok = Token::make_TK_RCSTAG();
5578 }
5579 else // other section
5580 {
5581 tok = Token::make_TK_COMMAND_BS();
5582 }
5583 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5584 goto reparsetoken;
5585 }
5586 else if (retval.is(TokenRetval::TK_ENDLIST))
5587 {
5588 if (al->indent()>parser()->context.token->indent) // end list
5589 {
5590 goto endparagraph;
5591 }
5592 else // continue with current paragraph
5593 {
5594 }
5595 }
5596 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5597 {
5598 goto endparagraph;
5599 }
5600 }
5601 break;
5602 case TokenRetval::TK_ENDLIST:
5603 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5604 if (std::get_if<DocAutoListItem>(parent()))
5605 {
5606 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5607 if (al && al->indent()>=parser()->context.token->indent)
5608 {
5609 // end of list marker ends this paragraph
5610 retval = Token::make_TK_ENDLIST();
5611 goto endparagraph;
5612 }
5613 else
5614 {
5615 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5616 "has invalid indent level");
5617 }
5618 }
5619 else
5620 {
5621 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5622 "list items");
5623 }
5624 break;
5625 case TokenRetval::TK_COMMAND_AT:
5626 // fall through
5627 case TokenRetval::TK_COMMAND_BS:
5628 {
5629 // see if we have to start a simple section
5630 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5631 const DocNodeVariant *n=parent();
5632 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5633 !std::holds_alternative<DocParamSect>(*n))
5634 {
5635 n=::parent(n);
5636 }
5638 {
5639 if (n) // already in a simple section
5640 {
5641 // simple section cannot start in this paragraph, need
5642 // to unwind the stack and remember the command.
5644 retval = Token::make_RetVal_SimpleSec();
5645 goto endparagraph;
5646 }
5647 }
5648 // see if we are in a simple list
5649 n=parent();
5650 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5651 if (n)
5652 {
5653 if (cmd==CommandType::CMD_LI)
5654 {
5655 retval = Token::make_RetVal_ListItem();
5656 goto endparagraph;
5657 }
5658 }
5659
5660 // handle the command
5661 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5662 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5663
5664 // check the return value
5665 if (retval.is(TokenRetval::RetVal_SimpleSec))
5666 {
5667 // Reparse the token that ended the section at this level,
5668 // so a new simple section will be started at this level.
5669 // This is the same as unputting the last read token and continuing.
5671 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5672 {
5675 tok = Token::make_TK_RCSTAG();
5676 }
5677 else // other section
5678 {
5679 tok = Token::make_TK_COMMAND_BS();
5680 }
5681 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5682 goto reparsetoken;
5683 }
5684 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5685 {
5686 // the command ended with a new command, reparse this token
5687 tok = retval;
5688 goto reparsetoken;
5689 }
5690 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5691 // or some auto list marker
5692 {
5693 goto endparagraph;
5694 }
5695 }
5696 break;
5697 case TokenRetval::TK_HTMLTAG:
5698 {
5699 if (!parser()->context.token->endTag) // found a start tag
5700 {
5701 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5702 }
5703 else // found an end tag
5704 {
5706 {
5707 break; // new code has been pushed back to the scanner, need to reparse
5708 }
5709 retval = handleHtmlEndTag(parser()->context.token->name);
5710 }
5711 if (!retval.is(TokenRetval::RetVal_OK))
5712 {
5713 goto endparagraph;
5714 }
5715 }
5716 break;
5717 case TokenRetval::TK_SYMBOL:
5718 {
5719 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5721 {
5723 }
5724 else
5725 {
5727 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5728 parser()->context.token->name);
5729 }
5730 break;
5731 }
5732 case TokenRetval::TK_NEWPARA:
5733 retval = Token::make_TK_NEWPARA();
5734 goto endparagraph;
5735 case TokenRetval::TK_RCSTAG:
5736 {
5737 const DocNodeVariant *n=parent();
5738 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5739 !std::holds_alternative<DocParamSect>(*n))
5740 {
5741 n=::parent(n);
5742 }
5743 if (n) // already in a simple section
5744 {
5745 // simple section cannot start in this paragraph, need
5746 // to unwind the stack and remember the command.
5749 retval = Token::make_RetVal_SimpleSec();
5750 goto endparagraph;
5751 }
5752
5753 // see if we are in a simple list
5755 children().get_last<DocSimpleSect>()->parseRcs();
5756 }
5757 break;
5758 default:
5759 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5760 "Found unexpected token (id={})",tok.to_string());
5761 break;
5762 }
5763 tok=parser()->tokenizer.lex();
5764 }
5765 retval=Token::make_TK_NONE();
5766endparagraph:
5768 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5769 if (!parser()->context.token->endTag && par &&
5770 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5771 {
5772 par->setAttribs(parser()->context.token->attribs);
5773 }
5774 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
5775 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
5776 );
5777
5778 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5779 return retval;
5780}
5781
5782//--------------------------------------------------------------------------
5783
5785{
5786 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
5787 Token retval = Token::make_RetVal_OK();
5788 auto ns = AutoNodeStack(parser(),thisVariant());
5789
5790 if (!m_id.isEmpty())
5791 {
5793 if (sec)
5794 {
5795 m_file = sec->fileName();
5796 m_anchor = sec->label();
5797 QCString titleStr = sec->title();
5798 if (titleStr.isEmpty()) titleStr = sec->label();
5800 DocTitle *title = &std::get<DocTitle>(*m_title);
5801 title->parseFromString(thisVariant(),titleStr);
5802 }
5803 }
5804
5805 // first parse any number of paragraphs
5806 bool isFirst=TRUE;
5807 DocPara *lastPar=nullptr;
5808 do
5809 {
5811 DocPara *par = children().get_last<DocPara>();
5812 if (isFirst) { par->markFirst(); isFirst=FALSE; }
5813 retval=par->parse();
5814 if (!par->isEmpty())
5815 {
5816 if (lastPar) lastPar->markLast(FALSE);
5817 lastPar = par;
5818 }
5819 else
5820 {
5821 children().pop_back();
5822 }
5823 if (retval.is(TokenRetval::TK_LISTITEM))
5824 {
5825 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
5826 }
5827 if (retval.is(TokenRetval::RetVal_Internal))
5828 {
5830 retval = children().get_last<DocInternal>()->parse(m_level+1);
5831 if (retval.is(TokenRetval::RetVal_EndInternal))
5832 {
5833 retval = Token::make_RetVal_OK();
5834 }
5835 }
5836 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
5837 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
5838 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
5839 );
5840
5841 if (lastPar) lastPar->markLast();
5842
5843 while (true)
5844 {
5845 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
5846 {
5847 // then parse any number of nested sections
5848 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
5849 {
5851 2,
5853 retval = children().get_last<DocSection>()->parse();
5854 }
5855 break;
5856 }
5857 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
5858 {
5859 if ((m_level <= 1) &&
5860 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5861 {
5862 warn_doc_error(parser()->context.fileName,
5863 parser()->tokenizer.getLineNr(),
5864 "Unexpected subsubsection command found inside {}!",
5866 }
5867 // then parse any number of nested sections
5868 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
5869 {
5871 3,
5873 retval = children().get_last<DocSection>()->parse();
5874 }
5875 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
5876 }
5877 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
5878 {
5879 if ((m_level <= 2) &&
5880 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5881 {
5882 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5883 "Unexpected paragraph command found inside {}!",
5885 }
5886 // then parse any number of nested sections
5887 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
5888 {
5890 4,
5892 retval = children().get_last<DocSection>()->parse();
5893 }
5894 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
5895 }
5896 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
5897 {
5898 if ((m_level <= 3) &&
5899 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5900 {
5901 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5902 "Unexpected subparagraph command found inside {}!",
5904 }
5905 // then parse any number of nested sections
5906 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
5907 {
5909 5,
5911 retval = children().get_last<DocSection>()->parse();
5912 }
5913 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
5914 }
5915 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
5916 {
5917 if ((m_level <= 4) &&
5918 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5919 {
5920 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5921 "Unexpected subsubparagraph command found inside {}!",
5923 }
5924 // then parse any number of nested sections
5925 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
5926 {
5928 6,
5930 retval = children().get_last<DocSection>()->parse();
5931 }
5932 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
5933 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
5934 }
5935 else
5936 {
5937 break;
5938 }
5939 }
5940
5941 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
5942 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
5943 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
5944 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
5945 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
5946 );
5947
5948 AUTO_TRACE_EXIT("retval={}", retval.to_string());
5949 return retval;
5950}
5951
5952//--------------------------------------------------------------------------
5953
5955{
5956 AUTO_TRACE();
5957 auto ns = AutoNodeStack(parser(),thisVariant());
5959
5960 Token tok = parser()->tokenizer.lex();
5961 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5962 {
5963 switch(tok.value())
5964 {
5965 case TokenRetval::TK_WORD:
5967 break;
5968 case TokenRetval::TK_WHITESPACE:
5970 break;
5971 case TokenRetval::TK_SYMBOL:
5972 {
5973 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5975 {
5977 }
5978 else
5979 {
5980 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5981 parser()->context.token->name);
5982 }
5983 }
5984 break;
5985 case TokenRetval::TK_COMMAND_AT:
5986 // fall through
5987 case TokenRetval::TK_COMMAND_BS:
5988 switch (Mappers::cmdMapper->map(parser()->context.token->name))
5989 {
5992 break;
5995 break;
5998 break;
6001 break;
6004 break;
6007 break;
6010 break;
6013 break;
6016 break;
6020 break;
6025 break;
6028 break;
6031 break;
6034 break;
6037 break;
6040 break;
6043 break;
6046 break;
6047 default:
6048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6049 parser()->context.token->name);
6050 break;
6051 }
6052 break;
6053 default:
6054 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6055 tok.to_string());
6056 break;
6057 }
6058 tok = parser()->tokenizer.lex();
6059 }
6060
6062
6063}
6064
6065
6066//--------------------------------------------------------------------------
6067
6069{
6070 AUTO_TRACE();
6071 auto ns = AutoNodeStack(parser(),thisVariant());
6073 Token retval = Token::make_TK_NONE();
6074
6075 // first parse any number of paragraphs
6076 bool isFirst=TRUE;
6077 DocPara *lastPar = nullptr;
6078 do
6079 {
6080 {
6082 DocPara *par = children().get_last<DocPara>();
6083 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6084 retval=par->parse();
6085 if (par->isEmpty() && par->attribs().empty())
6086 {
6087 children().pop_back();
6088 }
6089 else
6090 {
6091 lastPar = par;
6092 }
6093 }
6094 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6095 if (retval == t)
6096 {
6097 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6098 {
6099 warn_doc_error(parser()->context.fileName,
6100 parser()->tokenizer.getLineNr(),
6101 "found {} command (id: '{}') outside of {} context!",
6102 sectionType,parser()->context.token->sectionId,parentSectionType);
6103 }
6104 while (retval==t)
6105 {
6106 if (!parser()->context.token->sectionId.isEmpty())
6107 {
6108 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6109 if (sec)
6110 {
6112 level,
6114 retval = children().get_last<DocSection>()->parse();
6115 }
6116 else
6117 {
6118 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6119 sectionType,parser()->context.token->sectionId,sectionType);
6120 retval = Token::make_TK_NONE();
6121 }
6122 }
6123 else
6124 {
6125 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6126 retval = Token::make_TK_NONE();
6127 }
6128 }
6129 }
6130 };
6131 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6132 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6133 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6134 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6135 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6136
6137 if (retval.is(TokenRetval::TK_LISTITEM))
6138 {
6139 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6140 }
6141 if (retval.is(TokenRetval::RetVal_Internal))
6142 {
6144 retval = children().get_last<DocInternal>()->parse(1);
6145 }
6146 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6147 if (lastPar) lastPar->markLast();
6148
6149 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6150 // then parse any number of level1 sections
6151 while (retval.is(TokenRetval::RetVal_Section))
6152 {
6153 if (!parser()->context.token->sectionId.isEmpty())
6154 {
6155 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6156 if (sec)
6157 {
6159 1,
6161 retval = children().get_last<DocSection>()->parse();
6162 }
6163 else
6164 {
6165 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6166 retval = Token::make_TK_NONE();
6167 }
6168 }
6169 else
6170 {
6171 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6172 retval = Token::make_TK_NONE();
6173 }
6174 }
6175
6177}
bool isAliasCmd(std::string_view aliasCmd)
Definition aliases.cpp:528
static AnchorGenerator & instance()
Returns the singleton instance.
Definition anchor.cpp:38
Citation manager class.
Definition cite.h:40
QCString anchorPrefix() const
Definition cite.cpp:122
const CiteInfo * find(const QCString &label) const
Return the citation info for a given label.
Definition cite.cpp:96
static CitationManager & instance()
Definition cite.cpp:80
QCString fileName() const
Definition cite.cpp:117
Class representing a Boolean type option.
Definition configimpl.h:255
QCString * valueStringRef()
Definition configimpl.h:265
Class representing an enum type option.
Definition configimpl.h:157
QCString * valueRef()
Definition configimpl.h:169
static ConfigImpl * instance()
Definition configimpl.h:351
ConfigOption * get(const QCString &name) const
Definition configimpl.h:400
Class representing an integer type option.
Definition configimpl.h:220
QCString * valueStringRef()
Definition configimpl.h:232
Class representing a list type option.
Definition configimpl.h:125
Abstract base class for any configuration option.
Definition configimpl.h:39
@ O_Disabled
Disabled compile time option.
Definition configimpl.h:55
@ O_List
A list of items.
Definition configimpl.h:49
@ O_Enum
A fixed set of items.
Definition configimpl.h:50
@ O_Bool
A boolean value.
Definition configimpl.h:53
@ O_String
A single item.
Definition configimpl.h:51
@ O_Obsolete
An obsolete option.
Definition configimpl.h:54
@ O_Int
An integer value.
Definition configimpl.h:52
@ O_Info
A section header.
Definition configimpl.h:48
OptionType kind() const
Definition configimpl.h:70
Class representing a string type option.
Definition configimpl.h:188
QCString * valueRef()
Definition configimpl.h:201
The common base class of all entity definitions found in the sources.
Definition definition.h:76
virtual bool isLinkable() const =0
virtual DefType definitionType() const =0
virtual QCString briefDescription(bool abbreviate=FALSE) const =0
virtual QCString getReference() const =0
virtual QCString getSourceFileBase() const =0
virtual QCString documentation() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
virtual const QCString & name() const =0
DocAnchor(DocParser *parser, DocNodeVariant *parent, const QCString &id, bool newAnchor)
Definition docnode.cpp:209
QCString m_anchor
Definition docnode.h:237
QCString m_file
Definition docnode.h:238
Node representing an auto List.
Definition docnode.h:567
int m_depth
Definition docnode.h:586
bool isCheckedList() const
Definition docnode.h:578
bool isEnumList() const
Definition docnode.h:576
int depth() const
Definition docnode.h:579
int m_indent
Definition docnode.h:583
Token parse()
Definition docnode.cpp:2826
bool m_isCheckedList
Definition docnode.h:585
int indent() const
Definition docnode.h:577
DocAutoList(DocParser *parser, DocNodeVariant *parent, int indent, bool isEnumList, int depth, bool isCheckedList)
Definition docnode.cpp:2819
bool m_isEnumList
Definition docnode.h:584
Node representing an item of a auto list.
Definition docnode.h:591
DocAutoListItem(DocParser *parser, DocNodeVariant *parent, int indent, int num)
Definition docnode.cpp:2779
Node representing a citation of some bibliographic reference.
Definition docnode.h:244
QCString m_anchor
Definition docnode.h:257
DocCite(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context)
Definition docnode.cpp:900
QCString m_relPath
Definition docnode.h:255
QCString m_ref
Definition docnode.h:256
QCString m_file
Definition docnode.h:254
QCString m_text
Definition docnode.h:258
DocNodeList & children()
Definition docnode.h:142
DocCompoundNode(DocParser *parser, DocNodeVariant *parent)
Definition docnode.h:140
bool parse()
Definition docnode.cpp:1151
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1144
QCString srcFile() const
Definition docnode.h:686
std::unique_ptr< Private > p
Definition docnode.h:703
int srcLine() const
Definition docnode.h:687
DocDiagramFileBase(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.h:676
QCString context() const
Definition docnode.h:685
QCString name() const
Definition docnode.h:679
bool parse()
Definition docnode.cpp:1073
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1066
Node representing an emoji.
Definition docnode.h:337
DocEmoji(DocParser *parser, DocNodeVariant *parent, const QCString &symName)
Definition docnode.cpp:160
int m_index
Definition docnode.h:345
QCString m_symName
Definition docnode.h:344
Node representing an item of a cross-referenced list.
Definition docnode.h:525
QCString m_relPath
Definition docnode.h:542
QCString m_text
Definition docnode.h:541
int id() const
Definition docnode.h:531
QCString m_name
Definition docnode.h:540
DocFormula(DocParser *parser, DocNodeVariant *parent, int id)
Definition docnode.cpp:515
QCString relPath() const
Definition docnode.h:530
Token parse()
Definition docnode.cpp:1465
Node representing a horizontal ruler.
Definition docnode.h:215
Node representing an HTML blockquote.
Definition docnode.h:1286
HtmlAttribList m_attribs
Definition docnode.h:1233
bool m_hasCaptionId
Definition docnode.h:1234
DocHtmlCaption(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs)
Definition docnode.cpp:1672
QCString m_file
Definition docnode.h:1235
const HtmlAttribList & attribs() const
Definition docnode.h:1226
QCString m_anchor
Definition docnode.h:1236
Node representing a HTML table cell.
Definition docnode.h:1188
Valignment valignment() const
Definition docnode.cpp:1876
void setColumnIndex(uint32_t idx)
Definition docnode.h:1212
bool isFirst() const
Definition docnode.h:1196
Token parseXml()
Definition docnode.cpp:1780
void setRowIndex(uint32_t idx)
Definition docnode.h:1211
void markLast(bool v=TRUE)
Definition docnode.h:1199
uint32_t rowSpan() const
Definition docnode.cpp:1814
void markFirst(bool v=TRUE)
Definition docnode.h:1198
Alignment alignment() const
Definition docnode.cpp:1838
bool isHeading() const
Definition docnode.h:1195
const HtmlAttribList & attribs() const
Definition docnode.h:1200
Token parse()
Definition docnode.cpp:1746
uint32_t colSpan() const
Definition docnode.cpp:1826
Node representing a HTML description data.
Definition docnode.h:1176
HtmlAttribList m_attribs
Definition docnode.h:1183
Node representing a Html description list.
Definition docnode.h:896
Node representing a Html description item.
Definition docnode.h:883
Node Html details.
Definition docnode.h:852
const HtmlAttribList & attribs() const
Definition docnode.h:856
void parseSummary(DocNodeVariant *, HtmlAttribList &attribs)
Definition docnode.cpp:1455
const DocNodeVariant * summary() const
Definition docnode.h:859
std::unique_ptr< DocNodeVariant > m_summary
Definition docnode.h:863
Node Html heading.
Definition docnode.h:868
Token parse()
Definition docnode.cpp:1280
Node representing a Html list.
Definition docnode.h:995
Type m_type
Definition docnode.h:1006
Token parseXml()
Definition docnode.cpp:2626
Token parse()
Definition docnode.cpp:2551
Node representing a HTML list item.
Definition docnode.h:1160
Node representing a HTML table row.
Definition docnode.h:1241
Token parseXml(bool header)
Definition docnode.cpp:1978
void setVisibleCells(uint32_t n)
Definition docnode.h:1251
bool isHeading() const
Definition docnode.cpp:1898
void setRowIndex(uint32_t idx)
Definition docnode.h:1256
Token parse()
Definition docnode.cpp:1913
Node Html summary.
Definition docnode.h:839
Node representing a HTML table.
Definition docnode.h:1264
Token parseXml()
Definition docnode.cpp:2136
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1279
Token parse()
Definition docnode.cpp:2058
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2193
size_t m_numCols
Definition docnode.h:1281
const DocNodeVariant * caption() const
Definition docnode.cpp:2044
bool hasCaption() const
Definition docnode.cpp:2039
const DocNodeVariant * firstRow() const
Definition docnode.cpp:2049
const HtmlAttribList & attribs() const
Definition docnode.h:651
QCString relPath() const
Definition docnode.h:647
QCString name() const
Definition docnode.h:643
QCString url() const
Definition docnode.h:648
DocImage(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs, const QCString &name, Type t, const QCString &url=QCString(), bool inlineImage=TRUE)
Definition docnode.cpp:1257
std::unique_ptr< Private > p
Definition docnode.h:670
void parse()
Definition docnode.cpp:1272
bool isSVG() const
Definition docnode.cpp:1263
Node representing a include/dontinclude operator block.
Definition docnode.h:473
bool m_stripCodeComments
Definition docnode.h:517
const char * typeAsString() const
Definition docnode.h:482
QCString m_includeFileName
Definition docnode.h:520
QCString context() const
Definition docnode.h:497
Type type() const
Definition docnode.h:481
QCString m_pattern
Definition docnode.h:513
void markLast(bool v=TRUE)
Definition docnode.h:501
QCString m_text
Definition docnode.h:512
bool m_showLineNo
Definition docnode.h:511
Node representing an included text block from file.
Definition docnode.h:431
void parse()
Definition docnode.cpp:268
QCString m_text
Definition docnode.h:461
Type m_type
Definition docnode.h:462
@ LatexInclude
Definition docnode.h:433
@ SnippetWithLines
Definition docnode.h:434
@ DontIncWithLines
Definition docnode.h:435
@ IncWithLines
Definition docnode.h:434
@ HtmlInclude
Definition docnode.h:433
@ VerbInclude
Definition docnode.h:433
@ DontInclude
Definition docnode.h:433
@ DocbookInclude
Definition docnode.h:435
QCString m_blockId
Definition docnode.h:468
bool m_stripCodeComments
Definition docnode.h:463
QCString context() const
Definition docnode.h:449
QCString m_file
Definition docnode.h:459
Node representing an entry in the index.
Definition docnode.h:548
QCString m_entry
Definition docnode.h:558
Token parse()
Definition docnode.cpp:1575
Node representing an internal section of documentation.
Definition docnode.h:964
Token parse(int)
Definition docnode.cpp:1515
QCString m_file
Definition docnode.h:811
QCString m_anchor
Definition docnode.h:813
DocInternalRef(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:670
QCString relPath() const
Definition docnode.h:807
QCString m_relPath
Definition docnode.h:812
Node representing a line break.
Definition docnode.h:201
QCString m_word
Definition docnode.h:177
QCString m_anchor
Definition docnode.h:181
QCString file() const
Definition docnode.h:170
QCString relPath() const
Definition docnode.h:171
QCString ref() const
Definition docnode.h:172
QCString word() const
Definition docnode.h:169
QCString m_file
Definition docnode.h:179
QCString anchor() const
Definition docnode.h:173
QCString m_ref
Definition docnode.h:178
QCString m_relPath
Definition docnode.h:180
DocLinkedWord(DocParser *parser, DocNodeVariant *parent, const QCString &word, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &tooltip)
Definition docnode.cpp:192
QCString m_tooltip
Definition docnode.h:182
QCString tooltip() const
Definition docnode.h:174
DocMscFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1104
bool parse()
Definition docnode.cpp:1111
DocNode(DocParser *parser, DocNodeVariant *parent)
Definition docnode.h:84
void setInsidePreformatted(bool p)
Definition docnode.h:108
DocNodeVariant * thisVariant()
Definition docnode.h:92
DocParser * parser()
Definition docnode.h:97
DocNodeVariant * parent()
Definition docnode.h:89
@ Unknown
Definition docnode.h:109
@ Table
Definition docnode.h:109
@ Section
Definition docnode.h:109
@ Anchor
Definition docnode.h:109
Node representing an block of paragraphs.
Definition docnode.h:974
Token parse()
Definition docnode.cpp:2720
Node representing a paragraph in the documentation tree.
Definition docnode.h:1075
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3248
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3690
void handleInheritDoc()
Definition docnode.cpp:3948
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3301
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3242
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3758
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3985
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3364
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3863
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3651
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3567
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3278
void markLast(bool v=TRUE)
Definition docnode.h:1081
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4735
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3333
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3591
bool isFirst() const
Definition docnode.h:1082
void markFirst(bool v=TRUE)
Definition docnode.h:1080
void handleRef(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3731
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3553
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1110
bool m_isFirst
Definition docnode.h:1113
Token parse()
Definition docnode.cpp:5479
void handleVhdlFlow()
Definition docnode.cpp:3683
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:3894
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3483
bool m_isLast
Definition docnode.h:1114
Token handleXRefItem()
Definition docnode.cpp:3462
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5206
Token handleStartCode()
Definition docnode.cpp:3912
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:3905
DocNodeList m_paramTypes
Definition docnode.h:1139
DocNodeList m_paragraphs
Definition docnode.h:1137
void markFirst(bool b=TRUE)
Definition docnode.h:1129
Token parseXml(const QCString &paramName)
Definition docnode.cpp:3131
void markLast(bool b=TRUE)
Definition docnode.h:1130
Token parse(const QCString &cmdName)
Definition docnode.cpp:3052
DocParamSect::Type m_type
Definition docnode.h:1140
DocNodeList m_params
Definition docnode.h:1138
Node representing a parameter section.
Definition docnode.h:1048
friend class DocParamList
Definition docnode.h:1049
Token parse(const QCString &cmdName, bool xmlContext, Direction d)
Definition docnode.cpp:3199
bool m_hasInOutSpecifier
Definition docnode.h:1069
Type type() const
Definition docnode.h:1063
bool defaultHandleToken(DocNodeVariant *parent, Token tok, DocNodeList &children, bool handleWord=TRUE)
void handleLinkedWord(DocNodeVariant *parent, DocNodeList &children, bool ignoreAutoLinkFlag=FALSE)
DocTokenizer tokenizer
void handleInternalRef(DocNodeVariant *parent, DocNodeList &children)
void handleParameterType(DocNodeVariant *parent, DocNodeList &children, const QCString &paramTypes)
void checkRetvalName()
void readTextFileByName(const QCString &file, QCString &text)
Token handleAHref(DocNodeVariant *parent, DocNodeList &children, const HtmlAttribList &tagHtmlAttribs)
Token internalValidatingParseDoc(DocNodeVariant *parent, DocNodeList &children, const QCString &doc)
void handleInitialStyleCommands(DocNodeVariant *parent, DocNodeList &children)
void handleStyleLeave(DocNodeVariant *parent, DocNodeList &children, DocStyleChange::Style s, const QCString &tagName)
void handlePendingStyleCommands(DocNodeVariant *parent, DocNodeList &children)
void popContext()
Definition docparser.cpp:74
void handleImage(DocNodeVariant *parent, DocNodeList &children)
void handleStyleEnter(DocNodeVariant *parent, DocNodeList &children, DocStyleChange::Style s, const QCString &tagName, const HtmlAttribList *attribs)
void handlePrefix(DocNodeVariant *parent, DocNodeList &children)
Token handleStyleArgument(DocNodeVariant *parent, DocNodeList &children, const QCString &cmdName)
void checkArgumentName()
DocParserContext context
void handleAnchor(DocNodeVariant *parent, DocNodeList &children)
void handleImg(DocNodeVariant *parent, DocNodeList &children, const HtmlAttribList &tagHtmlAttribs)
void defaultHandleTitleAndSize(const CommandType cmd, DocNodeVariant *parent, DocNodeList &children, QCString &width, QCString &height)
void handleUnclosedStyleCommands()
void pushContext()
Definition docparser.cpp:60
void errorHandleDefaultToken(DocNodeVariant *parent, Token tok, DocNodeList &children, const QCString &txt)
DocPlantUmlFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1183
Node representing a reference to some item.
Definition docnode.h:773
QCString anchor() const
Definition docnode.h:780
QCString m_file
Definition docnode.h:793
SectionType m_sectionType
Definition docnode.h:791
QCString m_text
Definition docnode.h:797
void parse()
Definition docnode.cpp:854
QCString m_ref
Definition docnode.h:795
QCString m_relPath
Definition docnode.h:794
DocRef(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context)
Definition docnode.cpp:705
RefType m_refType
Definition docnode.h:790
QCString m_anchor
Definition docnode.h:796
bool m_isSubPage
Definition docnode.h:792
void parse()
Definition docnode.cpp:6068
Node representing a reference to a section.
Definition docnode.h:930
QCString m_file
Definition docnode.h:946
QCString m_target
Definition docnode.h:943
QCString relPath() const
Definition docnode.h:936
bool m_isSubPage
Definition docnode.h:945
QCString m_anchor
Definition docnode.h:949
QCString target() const
Definition docnode.h:933
QCString m_ref
Definition docnode.h:948
DocSecRefItem(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:534
QCString m_relPath
Definition docnode.h:947
RefType m_refType
Definition docnode.h:944
Node representing a list of section references.
Definition docnode.h:954
Node representing a normal section.
Definition docnode.h:909
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:923
QCString m_id
Definition docnode.h:922
QCString m_file
Definition docnode.h:925
Token parse()
Definition docnode.cpp:5784
DocSection(DocParser *parser, DocNodeVariant *parent, int level, const QCString &id)
Definition docnode.h:911
const DocNodeVariant * title() const
Definition docnode.h:914
QCString m_anchor
Definition docnode.h:924
int m_level
Definition docnode.h:921
Node representing a simple list.
Definition docnode.h:985
Token parse()
Definition docnode.cpp:2764
Node representing a simple list item.
Definition docnode.h:1148
std::unique_ptr< DocNodeVariant > m_paragraph
Definition docnode.h:1155
DocSimpleListItem(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:2745
Node representing a simple section.
Definition docnode.h:1012
QCString typeString() const
Definition docnode.cpp:3023
Type type() const
Definition docnode.h:1021
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:2913
Token parseRcs()
Definition docnode.cpp:2950
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:2903
const DocNodeVariant * title() const
Definition docnode.h:1028
Token parseXml()
Definition docnode.cpp:2967
void appendLinkWord(const QCString &word)
Definition docnode.cpp:3003
bool hasTitle() const
Definition docnode.cpp:2908
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:1032
Node representing a separator between two simple sections of the same type.
Definition docnode.h:1039
Node representing a style change.
Definition docnode.h:264
const char * styleString() const
Definition docnode.cpp:125
Style m_style
Definition docnode.h:314
Node representing a special symbol.
Definition docnode.h:324
static HtmlEntityMapper::SymType decodeSymbol(const QCString &symName)
Definition docnode.cpp:153
void parse()
Definition docnode.cpp:5954
Node representing a simple section title.
Definition docnode.h:604
void parse()
Definition docnode.cpp:2872
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:2890
void setStateILiteralOpt()
void setStateILiteral()
void setStateCite()
void setStateSnippet()
void setStateEmoji()
void setStateCode()
void setStatePattern()
void startAutoList()
void setStateSkipTitle()
void setStateParam()
void setStateBlock()
void setStatePlantUMLOpt()
void setStateRtfOnly()
void setStateVerbatim()
void setStateLink()
void setStateTitle()
void setStateFile()
void setStateLatexOnly()
void setStateManOnly()
void setStateShowDate()
void setInsidePre(bool b)
void setStateXRefItem()
void setStateText()
void setStateXmlCode()
void unputString(const QCString &tag)
void setStateDbOnly()
void setStateHtmlOnly()
void setStateILine()
void setStateICode()
void setStateOptions()
void setStateDoxyConfig()
void setStateQuotedString()
void setStatePara()
int getLineNr(void)
void setStatePlantUML()
void setStateIVerbatim()
void setStateXmlOnly()
void setStateSetScope()
void pushBackHtmlTag(const QCString &tag)
Node representing a URL (or email address)
Definition docnode.h:187
Node representing a verbatim, unparsed text fragment.
Definition docnode.h:372
DocVerbatim(DocParser *parser, DocNodeVariant *parent, const QCString &context, const QCString &text, Type t, bool isExample, const QCString &exampleFile, bool isBlock=FALSE, const QCString &lang=QCString())
Definition docnode.cpp:258
std::unique_ptr< Private > p
Definition docnode.h:425
bool isBlock() const
Definition docnode.h:385
bool isExample() const
Definition docnode.h:381
QCString context() const
Definition docnode.h:380
QCString text() const
Definition docnode.h:379
QCString exampleFile() const
Definition docnode.h:382
QCString relPath() const
Definition docnode.h:383
void setEngine(const QCString &e)
Definition docnode.h:398
@ JavaDocLiteral
Definition docnode.h:374
Node representing a VHDL flow chart.
Definition docnode.h:744
DocVhdlFlow(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:1227
void parse()
Definition docnode.cpp:1231
Node representing some amount of white space.
Definition docnode.h:350
Node representing a word.
Definition docnode.h:152
DocWord(DocParser *parser, DocNodeVariant *parent, const QCString &word)
Definition docnode.cpp:180
QCString m_word
Definition docnode.h:158
QCString word() const
Definition docnode.h:155
Node representing an item of a cross-referenced list.
Definition docnode.h:616
QCString m_anchor
Definition docnode.h:630
DocXRefItem(DocParser *parser, DocNodeVariant *parent, int id, const QCString &key)
Definition docnode.cpp:473
QCString key() const
Definition docnode.h:623
QCString relPath() const
Definition docnode.h:622
QCString m_file
Definition docnode.h:629
QCString m_key
Definition docnode.h:628
QCString m_title
Definition docnode.h:631
bool parse()
Definition docnode.cpp:478
QCString m_relPath
Definition docnode.h:632
static FileNameLinkedMap * plantUmlFileNameLinkedMap
Definition doxygen.h:110
static FileNameLinkedMap * dotFileNameLinkedMap
Definition doxygen.h:107
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
static FileNameLinkedMap * mscFileNameLinkedMap
Definition doxygen.h:108
static FileNameLinkedMap * diaFileNameLinkedMap
Definition doxygen.h:109
static QCString htmlFileExtension
Definition doxygen.h:122
static PageLinkedMap * pageLinkedMap
Definition doxygen.h:100
static SearchIndexIntf searchIndex
Definition doxygen.h:124
static EmojiEntityMapper & instance()
Returns the one and only instance of the Emoji entity mapper.
Definition emoji.cpp:1978
int symbol2index(const std::string &symName) const
Returns a code for the requested Emoji entity name.
Definition emoji.cpp:1990
A model of a file symbol.
Definition filedef.h:99
virtual QCString absFilePath() const =0
Class representing a LaTeX formula as found in the documentation.
Definition formula.h:29
QCString text() const
Definition formula.h:37
const Formula * findFormula(int formulaId) const
Definition formula.cpp:705
static FormulaManager & instance()
Definition formula.cpp:54
void clear()
clears the contents
Definition growvector.h:143
size_t size() const
returns the number of elements
Definition growvector.h:93
iterator end()
returns an iterator to the end
Definition growvector.h:88
T & back()
access the last element
Definition growvector.h:135
void pop_back()
removes the last element
Definition growvector.h:115
bool empty() const
checks whether the container is empty
Definition growvector.h:140
void emplace_back(Args &&...args)
Definition growvector.h:108
T & front()
access the first element
Definition growvector.h:130
Class representing a list of HTML attributes.
Definition htmlattrib.h:33
static HtmlEntityMapper & instance()
Returns the one and only instance of the HTML entity mapper.
SymType name2sym(const QCString &symName) const
Give code of the requested HTML entity name.
const T * find(const std::string &key) const
Definition linkedmap.h:47
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
virtual const ClassDef * getClassDef() const =0
virtual const MemberDef * reimplements() const =0
virtual QCString objCMethodName(bool localLink, bool showStatic) const =0
A model of a page symbol.
Definition pagedef.h:26
virtual bool hasParentPage() const =0
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
bool startsWith(const char *s) const
Definition qcstring.h:492
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:226
QCString lower() const
Definition qcstring.h:234
bool endsWith(const char *s) const
Definition qcstring.h:509
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:578
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
const std::string & str() const
Definition qcstring.h:537
QCString & append(char c)
Definition qcstring.h:381
QCString right(size_t len) const
Definition qcstring.h:219
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
std::string_view view() const
Definition qcstring.h:161
QCString left(size_t len) const
Definition qcstring.h:214
This struct represents an item in the list of references.
Definition reflist.h:32
QCString text() const
Definition reflist.h:45
QCString anchor() const
Definition reflist.h:46
List of cross-referenced items.
Definition reflist.h:80
QCString sectionTitle() const
Definition reflist.h:104
QCString fileName() const
Definition reflist.h:102
RefItem * find(int itemId)
Definition reflist.cpp:40
bool isEnabled() const
Definition reflist.cpp:46
static RefListManager & instance()
Definition reflist.h:121
class that provide information about a section.
Definition section.h:57
QCString label() const
Definition section.h:68
QCString ref() const
Definition section.h:71
QCString fileName() const
Definition section.h:73
QCString title() const
Definition section.h:69
SectionType type() const
Definition section.h:70
static SectionManager & instance()
returns a reference to the singleton
Definition section.h:175
static constexpr int Anchor
Definition section.h:40
static constexpr int Table
Definition section.h:41
constexpr int level() const
Definition section.h:45
static constexpr int Page
Definition section.h:31
bool is(TokenRetval rv) const
TOKEN_SPECIFICATIONS RETVAL_SPECIFICATIONS const char * to_string() const
TokenRetval value() const
bool is_any_of(ARGS... args) const
char command_to_char() const
static void createFlowChart(const MemberDef *)
Class representing a regular expression.
Definition regex.h:39
Class to iterate through matches.
Definition regex.h:232
CommandType
Definition cmdmapper.h:29
@ CMD_ENDSECREFLIST
Definition cmdmapper.h:53
@ CMD_ENDLATEXONLY
Definition cmdmapper.h:51
@ CMD_ENDVERBATIM
Definition cmdmapper.h:54
@ CMD_DONTINCLUDE
Definition cmdmapper.h:46
@ CMD_SUBSUBSECTION
Definition cmdmapper.h:89
@ CMD_SUBSUBPARAGRAPH
Definition cmdmapper.h:161
@ CMD_INTERNALREF
Definition cmdmapper.h:65
@ CMD_ENDHTMLONLY
Definition cmdmapper.h:50
@ CMD_VERBINCLUDE
Definition cmdmapper.h:98
@ CMD_DOCBOOKINCLUDE
Definition cmdmapper.h:145
@ CMD_HTMLINCLUDE
Definition cmdmapper.h:60
@ CMD_SNIPWITHLINES
Definition cmdmapper.h:141
HtmlTagType
Definition cmdmapper.h:169
#define Config_getList(name)
Definition config.h:38
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
std::unordered_set< std::string > StringUnorderedSet
Definition containers.h:29
std::vector< std::string > StringVector
Definition containers.h:33
QCString formatDateTime(const QCString &format, const std::tm &dt, int &formatUsed)
Return a string representation for a given std::tm value that is formatted according to the pattern g...
Definition datetime.cpp:175
QCString dateTimeFromString(const QCString &spec, std::tm &dt, int &format)
Returns the filled in std::tm for a given string representing a date and/or time.
Definition datetime.cpp:134
constexpr const char * SF_bit2str(int bitNumber)
Helper function that returns the name related one of the SF bits.
Definition datetime.h:32
constexpr int SF_NumBits
number of bits in SF vector
Definition datetime.h:27
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
#define AUTO_TRACE_ADD(...)
Definition docnode.cpp:47
static const char * g_sectionLevelToName[]
Definition docnode.cpp:56
#define AUTO_TRACE(...)
Definition docnode.cpp:46
static QCString stripKnownExtensions(const QCString &text)
Definition docnode.cpp:103
static void unescapeCRef(QCString &s)
Definition docnode.cpp:81
static const StringUnorderedSet g_plantumlEngine
Definition docnode.cpp:69
#define INTERNAL_ASSERT(x)
Definition docnode.cpp:51
static void flattenParagraphs(DocNodeVariant *root, DocNodeList &children)
Definition docnode.cpp:822
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4719
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2187
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:118
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5427
std::variant< DocWord, DocLinkedWord, DocURL, DocLineBreak, DocHorRuler, DocAnchor, DocCite, DocStyleChange, DocSymbol, DocEmoji, DocWhiteSpace, DocSeparator, DocVerbatim, DocInclude, DocIncOperator, DocFormula, DocIndexEntry, DocAutoList, DocAutoListItem, DocTitle, DocXRefItem, DocImage, DocDotFile, DocMscFile, DocDiaFile, DocVhdlFlow, DocLink, DocRef, DocInternalRef, DocHRef, DocHtmlHeader, DocHtmlDescTitle, DocHtmlDescList, DocSection, DocSecRefItem, DocSecRefList, DocInternal, DocParBlock, DocSimpleList, DocHtmlList, DocSimpleSect, DocSimpleSectSep, DocParamSect, DocPara, DocParamList, DocSimpleListItem, DocHtmlListItem, DocHtmlDescData, DocHtmlCell, DocHtmlCaption, DocHtmlRow, DocHtmlTable, DocHtmlBlockQuote, DocText, DocRoot, DocHtmlDetails, DocHtmlSummary, DocPlantUmlFile > DocNodeVariant
Definition docnode.h:66
constexpr bool holds_one_of_alternatives(const DocNodeVariant &v)
returns true iff v holds one of types passed as template parameters
Definition docnode.h:1361
DocNodeList * call_method_children(DocNodeVariant *v)
Definition docnode.h:1380
constexpr DocNodeVariant * parent(DocNodeVariant *n)
returns the parent node of a given node n or nullptr if the node has no parent.
Definition docnode.h:1325
std::unique_ptr< DocNodeVariant > createDocNode(Args &&...args)
Definition docnode.h:1486
Private header shared between docparser.cpp and docnode.cpp.
bool insideUL(const DocNodeVariant *n)
bool insideTable(const DocNodeVariant *n)
IterableStack< const DocNodeVariant * > DocStyleChangeStack
Definition docparser_p.h:55
bool insidePRE(const DocNodeVariant *n)
bool insideLI(const DocNodeVariant *n)
bool insideDL(const DocNodeVariant *n)
bool insideBlockQuote(const DocNodeVariant *n)
bool insideDetails(const DocNodeVariant *n)
bool insideOL(const DocNodeVariant *n)
FileDef * toFileDef(Definition *d)
Definition filedef.cpp:1932
GroupDef * toGroupDef(Definition *d)
Translator * theTranslator
Definition language.cpp:71
QCString markdownFileNameToId(const QCString &fileName)
processes string s and converts markdown into doxygen/html commands.
MemberDef * toMemberDef(Definition *d)
#define warn(file, line, fmt,...)
Definition message.h:97
#define err(fmt,...)
Definition message.h:127
#define warn_doc_error(file, line, fmt,...)
Definition message.h:112
const Mapper< HtmlTagType > * htmlTagMapper
const Mapper< CommandType > * cmdMapper
QCString trunc(const QCString &s, size_t numChars=15)
Definition trace.h:56
Definition message.h:144
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:672
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
#define ASSERT(x)
Definition qcstring.h:39
uint32_t rowsLeft
Definition docnode.cpp:2182
uint32_t column
Definition docnode.cpp:2183
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2181
Citation-related data.
Definition cite.h:27
virtual QCString text() const =0
virtual QCString label() const =0
void move_append(DocNodeList &l)
moves the element of list l at the end of this list.
Definition docnode.cpp:813
void append(Args &&... args)
Append a new DocNodeVariant to the list by constructing it with type T and parameters Args.
Definition docnode.h:1394
T * get_last()
Returns a pointer to the last element in the list if that element exists and holds a T,...
Definition docnode.h:1405
StringMultiSet retvalsFound
Definition docparser_p.h:75
bool includeFileShowLineNo
Definition docparser_p.h:89
DocStyleChangeStack styleStack
Definition docparser_p.h:67
size_t includeFileLength
Definition docparser_p.h:87
QCString fileName
Definition docparser_p.h:70
DocNodeStack nodeStack
Definition docparser_p.h:66
StringMultiSet paramsFound
Definition docparser_p.h:76
DefinitionStack copyStack
Definition docparser_p.h:69
QCString exampleName
Definition docparser_p.h:79
const Definition * scope
Definition docparser_p.h:61
QCString includeFileText
Definition docparser_p.h:85
TokenInfo * token
Definition docparser_p.h:92
QCString includeFileName
Definition docparser_p.h:84
size_t includeFileOffset
Definition docparser_p.h:86
const MemberDef * memberDef
Definition docparser_p.h:77
QCString verb
bool isEnumList
QCString text
QCString sectionId
QCString chars
HtmlAttribList attribs
bool isCheckedList
QCString simpleSectText
QCString name
QCString attribsStr
bool isEMailAddr
QCString simpleSectName
QCString linkToText(SrcLangExt lang, const QCString &link, bool isFileName)
Definition util.cpp:3219
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5721
QCString stripIndentation(const QCString &s, bool skipFirstLine)
Definition util.cpp:6428
std::string_view word
Definition util.cpp:980
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3541
bool found
Definition util.cpp:984
QCString stripScope(const QCString &name)
Definition util.cpp:4295
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, SrcLangExt lang, const QCString &prefix)
Definition util.cpp:3245
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:4020
if(strLen >35 &&floatingIndex >30 &&autoBreak)
Definition util.cpp:949
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:7095
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5540
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:3415
A bunch of utility functions.