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 }
147 return "<invalid>";
148}
149
150//----------- DocSymbol
151
156
157//----------- DocEmoji
158
160 DocNode(parser,parent), m_symName(symName), m_index(-1)
161{
162 QCString locSymName = symName;
163 size_t len=locSymName.length();
164 if (len>0)
165 {
166 if (locSymName.at(len-1)!=':') locSymName.append(":");
167 if (locSymName.at(0)!=':') locSymName.prepend(":");
168 }
169 m_symName = locSymName;
171 if (m_index==-1)
172 {
173 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Found unsupported emoji symbol '{}'",m_symName);
174 }
175}
176
177//---------------------------------------------------------------------------
178
181{
182 //printf("new word %s url=%s\n",qPrint(word),qPrint(parser->context.searchUrl));
183 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
184 {
185 Doxygen::searchIndex.addWord(word,false);
186 }
187}
188
189//---------------------------------------------------------------------------
190
192 const QCString &ref,const QCString &file,
193 const QCString &anchor,const QCString &tooltip) :
197{
198 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
199 // qPrint(word),qPrint(parser->context.searchUrl),qPrint(tooltip));
200 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
201 {
202 Doxygen::searchIndex.addWord(word,false);
203 }
204}
205
206//---------------------------------------------------------------------------
207
209{
210 if (id.isEmpty())
211 {
212 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Empty anchor label");
213 return;
214 }
215
217 QCString anchorPrefix = ct.anchorPrefix();
218 if (id.left(anchorPrefix.length()) == anchorPrefix)
219 {
220 const CiteInfo *cite = ct.find(id.mid(anchorPrefix.length()));
221 if (cite)
222 {
224 m_anchor = id;
225 }
226 else
227 {
228 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid cite anchor id '{}'",id);
229 m_anchor = "invalid";
230 m_file = "invalid";
231 }
232 }
233 else if (newAnchor) // found <a name="label">
234 {
235 m_anchor = id;
236 }
237 else // found \anchor label
238 {
239 const SectionInfo *sec = SectionManager::instance().find(id);
240 if (sec)
241 {
242 //printf("Found anchor %s\n",qPrint(id));
243 m_file = sec->fileName();
244 m_anchor = sec->label();
245 }
246 else
247 {
248 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid anchor id '{}'",id);
249 m_anchor = "invalid";
250 m_file = "invalid";
251 }
252 }
253}
254
255//---------------------------------------------------------------------------
256
263
264
265//---------------------------------------------------------------------------
266
268{
269 AUTO_TRACE("file={} text={}",m_file,Trace::trunc(m_text));
270 switch(m_type)
271 {
272 case DontIncWithLines:
273 // fall through
274 case IncWithLines:
275 // fall through
276 case Include:
277 // fall through
278 case DontInclude:
287 //printf("parser->context.includeFile=<<%s>>\n",qPrint(parser->context.includeFileText));
288 break;
289 case VerbInclude:
290 // fall through
291 case HtmlInclude:
292 case LatexInclude:
298 break;
299 case Snippet:
300 case SnippetWithLines:
302 // check here for the existence of the blockId inside the file, so we
303 // only generate the warning once.
304 int count = 0;
305 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
306 {
307 warn_doc_error(parser()->context.fileName,
308 parser()->tokenizer.getLineNr(),
309 "block marked with {} for \\snippet should appear twice in file {}, found it {:d} times",
310 m_blockId,m_file,count);
311 }
312 break;
313 }
314}
315
316//---------------------------------------------------------------------------
317
319{
320 if (parser()->context.includeFileName.isEmpty())
321 {
322 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
323 "No previous '\\include' or '\\dontinclude' command for '\\{}' present",
324 typeAsString());
325 }
326 bool found = false;
327
329 const char *p = parser()->context.includeFileText.data();
330 size_t l = parser()->context.includeFileLength;
331 size_t o = parser()->context.includeFileOffset;
332 int il = parser()->context.includeFileLine;
333 AUTO_TRACE("text={} off={} len={}",Trace::trunc(p),o,l);
334 size_t so = o, bo = 0;
335 bool nonEmpty = FALSE;
336 switch(type())
337 {
338 case Line:
339 while (o<l)
340 {
341 char c = p[o];
342 if (c=='\n')
343 {
345 if (nonEmpty) break; // we have a pattern to match
346 so=o+1; // no pattern, skip empty line
347 }
348 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
349 {
350 nonEmpty=TRUE;
351 }
352 o++;
353 }
354 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
355 {
356 m_line = il;
358 found = true;
359 AUTO_TRACE_ADD("\\line {}",Trace::trunc(m_text));
360 }
361 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
364 break;
365 case SkipLine:
366 while (o<l)
367 {
368 so=o;
369 while (o<l)
370 {
371 char c = p[o];
372 if (c=='\n')
373 {
375 if (nonEmpty) break; // we have a pattern to match
376 so=o+1; // no pattern, skip empty line
377 }
378 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
379 {
380 nonEmpty=TRUE;
381 }
382 o++;
383 }
384 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
385 {
386 m_line = il;
388 found = true;
389 AUTO_TRACE_ADD("\\skipline {}",Trace::trunc(m_text));
390 break;
391 }
392 o++; // skip new line
393 }
394 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
397 break;
398 case Skip:
399 while (o<l)
400 {
401 so=o;
402 while (o<l)
403 {
404 char c = p[o];
405 if (c=='\n')
406 {
408 if (nonEmpty) break; // we have a pattern to match
409 so=o+1; // no pattern, skip empty line
410 }
411 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
412 {
413 nonEmpty=TRUE;
414 }
415 o++;
416 }
417 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
418 {
419 found = true;
420 break;
421 }
422 o++; // skip new line
423 }
424 parser()->context.includeFileOffset = so; // set pointer to start of new line
427 break;
428 case Until:
429 bo=o;
430 while (o<l)
431 {
432 so=o;
433 while (o<l)
434 {
435 char c = p[o];
436 if (c=='\n')
437 {
439 if (nonEmpty) break; // we have a pattern to match
440 so=o+1; // no pattern, skip empty line
441 }
442 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
443 {
444 nonEmpty=TRUE;
445 }
446 o++;
447 }
448 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
449 {
450 m_line = il;
452 found = true;
453 AUTO_TRACE_ADD("\\until {}",Trace::trunc(m_text));
454 break;
455 }
456 o++; // skip new line
457 }
458 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
461 break;
462 }
463 if (!found)
464 {
465 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
466 "referenced pattern '{}' for command '\\{}' not found",m_pattern,typeAsString());
467 }
468}
469
470//---------------------------------------------------------------------------
471
476
478{
480 if (refList && refList->isEnabled())
481 {
482 RefItem *item = refList->find(m_id);
483 ASSERT(item!=nullptr);
484 if (item)
485 {
486 if (parser()->context.memberDef && parser()->context.memberDef->name().at(0)=='@')
487 {
488 m_file = "@"; // can't cross reference anonymous enum
489 m_anchor = "@";
490 }
491 else
492 {
493 m_file = refList->fileName();
494 m_anchor = item->anchor();
495 }
496 m_title = refList->sectionTitle();
497 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
498 // qPrint(m_file),qPrint(m_anchor),qPrint(m_title));
499
500 if (!item->text().isEmpty())
501 {
502 parser()->pushContext();
504 parser()->popContext();
505 }
506 }
507 return TRUE;
508 }
509 return FALSE;
510}
511
512//---------------------------------------------------------------------------
513
515 m_relPath(parser->context.relPath)
516{
517 const Formula *formula = FormulaManager::instance().findFormula(id);
518 if (formula && !formula->text().isEmpty())
519 {
520 m_id = id;
521 m_name.sprintf("form_%d",m_id);
522 m_text = formula->text();
523 }
524 else // wrong \_form#<n> command
525 {
526 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Wrong formula id {:d}",id);
527 m_id = -1;
528 }
529}
530
531//---------------------------------------------------------------------------
532
537
539{
540 AUTO_TRACE();
541 auto ns = AutoNodeStack(parser(),thisVariant());
542
544 Token tok = parser()->tokenizer.lex();
545 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
546 {
547 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
548 {
549 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\refitem");
550 }
551 tok = parser()->tokenizer.lex();
552 }
555
556 if (!m_target.isEmpty())
557 {
559 if (sec==nullptr && parser()->context.lang==SrcLangExt::Markdown) // lookup as markdown file
560 {
562 }
563 if (sec) // ref to section or anchor
564 {
565 // set defaults
566 m_ref = sec->ref();
569 m_anchor = sec->label();
570 m_isSubPage = false;
571 // adjust if needed
572 switch (sec->type().level())
573 {
575 {
577 m_isSubPage = pd && pd->hasParentPage();
578 if (!m_isSubPage)
579 {
580 m_anchor="";
581 }
582 }
583 break;
586 break;
589 break;
590 default:
591 break;
592 }
593 //printf("m_ref=%s,m_file=%s,type=%d\n",
594 // qPrint(m_ref),qPrint(m_file),m_refType);
595 }
596 else
597 {
598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to unknown section {}",m_target);
599 }
600 }
601 else
602 {
603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to empty target");
604 }
605}
606
607//---------------------------------------------------------------------------
608
610{
611 AUTO_TRACE();
612 auto ns = AutoNodeStack(parser(),thisVariant());
613
614 Token tok=parser()->tokenizer.lex();
615 // skip white space
616 while (tok.is_any_of(TokenRetval::TK_WHITESPACE, TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
617 // handle items
618 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
619 {
620 if (tok.is_any_of(TokenRetval::TK_COMMAND_AT, TokenRetval::TK_COMMAND_BS))
621 {
622 switch (Mappers::cmdMapper->map(parser()->context.token->name))
623 {
625 {
626 tok=parser()->tokenizer.lex();
627 if (!tok.is(TokenRetval::TK_WHITESPACE))
628 {
629 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\refitem command");
630 break;
631 }
632 tok=parser()->tokenizer.lex();
633 if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
634 {
635 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\refitem",
636 tok.to_string());
637 break;
638 }
639
642 }
643 break;
645 return;
646 default:
647 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\secreflist",
648 tok.command_to_char(),qPrint(parser()->context.token->name));
649 return;
650 }
651 }
652 else if (tok.is(TokenRetval::TK_WHITESPACE))
653 {
654 // ignore whitespace
655 }
656 else
657 {
658 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} inside section reference list",
659 tok.to_string());
660 return;
661 }
662 tok=parser()->tokenizer.lex();
663 }
664
665}
666
667//---------------------------------------------------------------------------
668
671{
672 int i=ref.find('#');
673 if (i!=-1)
674 {
675 m_anchor = ref.right(static_cast<int>(ref.length())-i-1);
676 m_file = ref.left(i);
677 }
678 else
679 {
680 m_file = ref;
681 }
682}
683
685{
686 AUTO_TRACE();
687 auto ns = AutoNodeStack(parser(),thisVariant());
688
689 Token tok = parser()->tokenizer.lex();
690 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
691 {
692 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
693 {
695 }
696 tok=parser()->tokenizer.lex();
697 }
698
700}
701
702//---------------------------------------------------------------------------
703
706{
707 const Definition *compound = nullptr;
709 AUTO_TRACE("target='{}',context='{}'",target,context);
710 ASSERT(!target.isEmpty());
711 m_relPath = parser->context.relPath;
712 auto lang = parser->context.lang;
713 const SectionInfo *sec = SectionManager::instance().find(parser->context.prefix+target);
714 if (sec==nullptr && getLanguageFromFileName(target)==SrcLangExt::Markdown) // lookup as markdown file
715 {
717 }
718 if (sec) // ref to section or anchor
719 {
720 PageDef *pd = nullptr;
721 int secLevel = sec->type().level();
722 if (secLevel==SectionType::Page)
723 {
724 pd = Doxygen::pageLinkedMap->find(target);
725 }
726 m_text = sec->title();
727 if (m_text.isEmpty()) m_text = sec->label();
728
729 m_ref = sec->ref();
731 if (secLevel==SectionType::Anchor)
732 {
734 }
735 else if (secLevel==SectionType::Table)
736 {
738 }
739 else
740 {
742 }
743 m_isSubPage = pd && pd->hasParentPage();
744 if (secLevel!=SectionType::Page || m_isSubPage) m_anchor = sec->label();
745 m_sectionType = sec->type();
746 //printf("m_text=%s,m_ref=%s,m_file=%s,type=%d\n",
747 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),m_refType);
748 AUTO_TRACE_EXIT("section");
749 return;
750 }
751 else if (resolveLink(context,target,true,&compound,anchor,lang,parser->context.prefix))
752 {
753 bool isFile = compound ?
754 (compound->definitionType()==Definition::TypeFile ||
756 FALSE;
757 m_text = linkToText(lang,target,isFile);
759 if (compound && compound->isLinkable()) // ref to compound
760 {
761 if (anchor.isEmpty() && /* compound link */
762 compound->definitionType()==Definition::TypeGroup && /* is group */
763 !toGroupDef(compound)->groupTitle().isEmpty() /* with title */
764 )
765 {
766 m_text=(toGroupDef(compound))->groupTitle(); // use group's title as link
767 }
768 else if (compound->definitionType()==Definition::TypeMember &&
769 toMemberDef(compound)->isObjCMethod())
770 {
771 // Objective C Method
772 const MemberDef *member = toMemberDef(compound);
773 bool localLink = parser->context.memberDef ? member->getClassDef()==parser->context.memberDef->getClassDef() : FALSE;
774 m_text = member->objCMethodName(localLink,parser->context.inSeeBlock);
775 }
776 else if (Config_getBool(HIDE_SCOPE_NAMES))
777 {
779 }
780
781 m_file = compound->getOutputFileBase();
782 m_ref = compound->getReference();
783 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
784 // compound->definitionType());
785 AUTO_TRACE_EXIT("compound");
786 return;
787 }
788 else if (compound && compound->definitionType()==Definition::TypeFile &&
789 toFileDef(compound)->generateSourceFile()
790 ) // undocumented file that has source code we can link to
791 {
792 m_file = compound->getSourceFileBase();
793 m_ref = compound->getReference();
794 AUTO_TRACE_EXIT("source");
795 return;
796 }
797 else
798 {
799 AUTO_TRACE_EXIT("compound '{}' not linkable",compound?compound->name():"none");
800 }
801 }
802 m_text = target;
803 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\ref command",
804 target);
805}
806
808{
809 for (auto &&elem : elements)
810 {
811 emplace_back(std::move(elem));
812 }
813 elements.clear();
814}
815
816static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
817{
818 DocNodeList newChildren;
819 for (auto &dn : children)
820 {
821 DocPara *para = std::get_if<DocPara>(&dn);
822 if (para)
823 {
824 //// move the children of the paragraph to the end of the newChildren list
825 newChildren.move_append(para->children());
826 }
827 }
828
829 // replace the children list by the newChildren list
830 children.clear();
831 children.move_append(newChildren);
832 // reparent the children
833 for (auto &cn : children)
834 {
835 setParent(&cn,root);
836 // we also need to set the parent for each child of cn, as cn's address may have changed.
837 auto opt_children = call_method_children(&cn);
838 if (opt_children)
839 {
840 for (auto &ccn : *opt_children)
841 {
842 setParent(&ccn,&cn);
843 }
844 }
845 }
846}
847
849{
850 AUTO_TRACE();
851 auto ns = AutoNodeStack(parser(),thisVariant());
852
853 Token tok = parser()->tokenizer.lex();
854 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
855 {
856 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
857 {
858 switch (tok.value())
859 {
860 case TokenRetval::TK_HTMLTAG:
861 break;
862 default:
864 break;
865 }
866 }
867 tok=parser()->tokenizer.lex();
868 }
869
870 if (children().empty() && !m_text.isEmpty())
871 {
872 QCString text = m_text;
873 if (parser()->context.insideHtmlLink)
874 {
875 // we already in a link/title only output anchor
876 text = m_anchor;
877 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
878 "Potential recursion while resolving \\ref command!");
879 }
881 parser()->pushContext();
883 parser()->popContext();
887 }
888
890}
891
892//---------------------------------------------------------------------------
893
895{
896 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
897 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
898 ASSERT(!target.isEmpty());
899 m_relPath = parser->context.relPath;
901 const CiteInfo *cite = ct.find(target);
902 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
903 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
904 {
905 m_text = cite->text();
906 m_ref = "";
907 m_anchor = ct.anchorPrefix()+cite->label();
909 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
910 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
911 return;
912 }
913 m_text = target;
914 if (numBibFiles==0)
915 {
916 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
917 }
918 else if (cite==nullptr)
919 {
920 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\cite command",
921 target);
922 }
923 else
924 {
925 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '{}' does not have an associated number",
926 target);
927 }
928}
929
930//---------------------------------------------------------------------------
931
933{
934 const Definition *compound = nullptr;
936 m_refText = target;
937 m_relPath = parser->context.relPath;
938 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
939 {
940 m_refText = m_refText.right(m_refText.length()-1);
941 }
942 if (resolveLink(parser->context.context,stripKnownExtensions(target),
943 parser->context.inSeeBlock,&compound,anchor,
944 parser->context.lang,parser->context.prefix))
945 {
946 m_anchor = anchor;
947 if (compound && compound->isLinkable())
948 {
949 m_file = compound->getOutputFileBase();
950 m_ref = compound->getReference();
951 }
952 else if (compound && compound->definitionType()==Definition::TypeFile &&
953 (toFileDef(compound))->generateSourceFile()
954 ) // undocumented file that has source code we can link to
955 {
956 m_file = compound->getSourceFileBase();
957 m_ref = compound->getReference();
958 }
959 return;
960 }
961
962 // bogus link target
963 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '{}' for \\link command",
964 target);
965}
966
967
968QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
969{
970 AUTO_TRACE();
971 QCString result;
972 auto ns = AutoNodeStack(parser(),thisVariant());
973
974 Token tok = parser()->tokenizer.lex();
975 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
976 {
977 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
978 {
979 switch (tok.value())
980 {
981 case TokenRetval::TK_COMMAND_AT:
982 // fall through
983 case TokenRetval::TK_COMMAND_BS:
984 switch (Mappers::cmdMapper->map(parser()->context.token->name))
985 {
987 if (isJavaLink)
988 {
989 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{{@link...' ended with '{:c}{}' command",
990 tok.command_to_char(),parser()->context.token->name);
991 }
992 goto endlink;
993 default:
994 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\link",
995 tok.command_to_char(),parser()->context.token->name);
996 break;
997 }
998 break;
999 case TokenRetval::TK_SYMBOL:
1000 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a \\link",
1001 parser()->context.token->name);
1002 break;
1003 case TokenRetval::TK_HTMLTAG:
1004 if (parser()->context.token->name!="see" || !isXmlLink)
1005 {
1006 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command {} found as part of a \\link",
1007 parser()->context.token->name);
1008 }
1009 goto endlink;
1010 case TokenRetval::TK_LNKWORD:
1011 case TokenRetval::TK_WORD:
1012 if (isJavaLink) // special case to detect closing }
1013 {
1015 int p = 0;
1016 if (w=="}")
1017 {
1018 goto endlink;
1019 }
1020 else if ((p=w.find('}'))!=-1)
1021 {
1022 int l = static_cast<int>(w.length());
1024 if (p<l-1) // something left after the } (for instance a .)
1025 {
1026 result=w.right(l-p-1);
1027 }
1028 goto endlink;
1029 }
1030 }
1032 break;
1033 default:
1034 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",tok.to_string());
1035 break;
1036 }
1037 }
1038 tok = parser()->tokenizer.lex();
1039 }
1040 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1041 {
1042 warn_doc_error(parser()->context.fileName,
1043 parser()->tokenizer.getLineNr(),
1044 "Unexpected end of comment while inside link command");
1045 }
1046endlink:
1047
1048 if (children().empty()) // no link text
1049 {
1051 }
1052
1054 return result;
1055}
1056
1057
1058//---------------------------------------------------------------------------
1059
1066
1068{
1069 bool ok = false;
1071
1072 bool ambig = false;
1074 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1075 {
1076 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1077 }
1078 if (fd)
1079 {
1080 p->file = fd->absFilePath();
1081 ok = true;
1082 if (ambig)
1083 {
1084 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '{}' is ambiguous.\n"
1085 "Possible candidates:\n{}",p->name,
1087 );
1088 }
1089 }
1090 else
1091 {
1092 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '{}' is not found "
1093 "in any of the paths specified via DOTFILE_DIRS!",p->name);
1094 }
1095 return ok;
1096}
1097
1104
1106{
1107 bool ok = false;
1109
1110 bool ambig = false;
1112 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1113 {
1114 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1115 }
1116 if (fd)
1117 {
1118 p->file = fd->absFilePath();
1119 ok = true;
1120 if (ambig)
1121 {
1122 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '{}' is ambiguous.\n"
1123 "Possible candidates:\n{}",qPrint(p->name),
1125 );
1126 }
1127 }
1128 else
1129 {
1130 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '{}' is not found "
1131 "in any of the paths specified via MSCFILE_DIRS!",p->name);
1132 }
1133 return ok;
1134}
1135
1136//---------------------------------------------------------------------------
1137
1144
1146{
1147 bool ok = false;
1149
1150 bool ambig = false;
1152 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1153 {
1154 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
1155 }
1156 if (fd)
1157 {
1158 p->file = fd->absFilePath();
1159 ok = true;
1160 if (ambig)
1161 {
1162 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file name '{}' is ambiguous.\n"
1163 "Possible candidates:\n{}",p->name,
1165 );
1166 }
1167 }
1168 else
1169 {
1170 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file '{}' is not found "
1171 "in any of the paths specified via DIAFILE_DIRS!",p->name);
1172 }
1173 return ok;
1174}
1175//---------------------------------------------------------------------------
1176
1183
1185{
1186 bool ok = false;
1188
1189 bool ambig = false;
1191 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1192 {
1193 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1194 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1195 {
1196 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1197 }
1198 }
1199 if (fd)
1200 {
1201 p->file = fd->absFilePath();
1202 ok = true;
1203 if (ambig)
1204 {
1205 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '{}' is ambiguous.\n"
1206 "Possible candidates:\n{}",p->name,
1208 );
1209 }
1210 }
1211 else
1212 {
1213 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '{}' is not found "
1214 "in any of the paths specified via PLANTUMLFILE_DIRS!",p->name);
1215 }
1216 return ok;
1217}
1218
1219//---------------------------------------------------------------------------
1220
1224
1226{
1227 AUTO_TRACE();
1228 auto ns = AutoNodeStack(parser(),thisVariant());
1229
1231 Token tok = parser()->tokenizer.lex();
1232 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1233 {
1234 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1235 {
1236 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1237 }
1238 tok = parser()->tokenizer.lex();
1239 }
1240 parser()->tokenizer.lex();
1241
1244
1245 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1246}
1247
1248
1249//---------------------------------------------------------------------------
1250
1252 Type t,const QCString &url, bool inlineImage) :
1253 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1254{
1255}
1256
1258{
1259 QCString locName = p->url.isEmpty() ? p->name : p->url;
1260 int len = static_cast<int>(locName.length());
1261 int fnd = locName.find('?'); // ignore part from ? until end
1262 if (fnd==-1) fnd=len;
1263 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1264}
1265
1270
1271
1272//---------------------------------------------------------------------------
1273
1275{
1276 AUTO_TRACE();
1277 Token retval(TokenRetval::RetVal_OK);
1278 auto ns = AutoNodeStack(parser(),thisVariant());
1279
1280 Token tok = parser()->tokenizer.lex();
1281 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1282 {
1283 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1284 {
1285 switch (tok.value())
1286 {
1287 case TokenRetval::TK_HTMLTAG:
1288 {
1289 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1290 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1291 {
1292 if (m_level!=1)
1293 {
1294 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h1>",
1295 m_level);
1296 }
1297 goto endheader;
1298 }
1299 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1300 {
1301 if (m_level!=2)
1302 {
1303 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h2>",
1304 m_level);
1305 }
1306 goto endheader;
1307 }
1308 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1309 {
1310 if (m_level!=3)
1311 {
1312 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h3>",
1313 m_level);
1314 }
1315 goto endheader;
1316 }
1317 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1318 {
1319 if (m_level!=4)
1320 {
1321 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h4>",
1322 m_level);
1323 }
1324 goto endheader;
1325 }
1326 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1327 {
1328 if (m_level!=5)
1329 {
1330 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h5>",
1331 m_level);
1332 }
1333 goto endheader;
1334 }
1335 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1336 {
1337 if (m_level!=6)
1338 {
1339 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h6>",
1340 m_level);
1341 }
1342 goto endheader;
1343 }
1344 else if (tagId==HtmlTagType::HTML_A)
1345 {
1346 if (!parser()->context.token->endTag)
1347 {
1348 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1349 }
1350 }
1351 else if (tagId==HtmlTagType::HTML_BR)
1352 {
1354 }
1355 else
1356 {
1357 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <h{:d}> context",
1358 parser()->context.token->endTag?"/":"",parser()->context.token->name,m_level);
1359 }
1360 }
1361 break;
1362 default:
1363 char tmp[20];
1364 qsnprintf(tmp,20,"<h%d>tag",m_level);
1366 }
1367 }
1368 tok = parser()->tokenizer.lex();
1369 }
1370 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1371 {
1372 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1373 " <h{:d}> tag",m_level);
1374 }
1375endheader:
1377 return retval;
1378}
1379//---------------------------------------------------------------------------
1380
1382{
1383 AUTO_TRACE();
1384 auto ns = AutoNodeStack(parser(),thisVariant());
1386 Token tok = parser()->tokenizer.lex();
1387 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1388 {
1390 // check of </summary>
1391 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1392 (tagId=Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1393 parser()->context.token->endTag
1394 )
1395 {
1396 break;
1397 }
1398 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1399 {
1400 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1401 }
1402 tok = parser()->tokenizer.lex();
1403 }
1405 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1406 {
1407 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1408 " <summary> tag");
1409 }
1410}
1411
1412//---------------------------------------------------------------------------
1413
1415{
1416 AUTO_TRACE();
1417 Token retval(TokenRetval::TK_NONE);
1418 auto ns = AutoNodeStack(parser(),thisVariant());
1419
1420 // parse one or more paragraphs
1421 bool isFirst=TRUE;
1422 DocPara *par=nullptr;
1423 do
1424 {
1426 par = children().get_last<DocPara>();
1427 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1428 retval=par->parse();
1429 }
1430 while (retval.is(TokenRetval::TK_NEWPARA));
1431 if (par) par->markLast();
1432
1433 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1434 {
1435 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1436 }
1437
1438 if (!summary())
1439 {
1440 HtmlAttribList summaryAttribs;
1442 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1443 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1444 }
1445 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1446 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1447}
1448
1456
1457//---------------------------------------------------------------------------
1458
1460{
1461 AUTO_TRACE();
1462 Token retval(TokenRetval::RetVal_OK);
1463 auto ns = AutoNodeStack(parser(),thisVariant());
1464
1465 Token tok = parser()->tokenizer.lex();
1466 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1467 {
1468 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1469 {
1470 switch (tok.value())
1471 {
1472 case TokenRetval::TK_HTMLTAG:
1473 {
1474 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1475 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1476 {
1477 goto endhref;
1478 }
1479 else if (tagId==HtmlTagType::HTML_BR)
1480 {
1482 }
1483 else
1484 {
1485 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <a href=...> context",
1486 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1487 }
1488 }
1489 break;
1490 default:
1491 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1492 break;
1493 }
1494 }
1495 tok = parser()->tokenizer.lex();
1496 }
1497 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1498 {
1499 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1500 " <a href=...> tag");
1501 }
1502endhref:
1504 return retval;
1505}
1506
1507//---------------------------------------------------------------------------
1508
1510{
1511 AUTO_TRACE();
1512 Token retval(TokenRetval::RetVal_OK);
1513 auto ns = AutoNodeStack(parser(),thisVariant());
1514
1515 // first parse any number of paragraphs
1516 bool isFirst=TRUE;
1517 DocPara *lastPar=nullptr;
1518 do
1519 {
1521 DocPara *par = children().get_last<DocPara>();
1522 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1523 retval=par->parse();
1524 if (!par->isEmpty())
1525 {
1526 if (lastPar) lastPar->markLast(FALSE);
1527 lastPar=par;
1528 }
1529 else
1530 {
1531 children().pop_back();
1532 }
1533 if (retval.is(TokenRetval::TK_LISTITEM))
1534 {
1535 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1536 }
1537 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1538 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1539 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1540 TokenRetval::RetVal_EndInternal));
1541 if (lastPar) lastPar->markLast();
1542
1543 // then parse any number of level-n sections
1544 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1545 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1546 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1547 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1548 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1549 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1550 )
1551 {
1553 level,
1555 retval = children().get_last<DocSection>()->parse();
1556 }
1557
1558 if (retval.is(TokenRetval::RetVal_Internal))
1559 {
1560 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1561 }
1562
1563 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1564 return retval;
1565}
1566
1567//---------------------------------------------------------------------------
1568
1570{
1571 AUTO_TRACE();
1572 Token retval(TokenRetval::RetVal_OK);
1573 auto ns = AutoNodeStack(parser(),thisVariant());
1574 Token tok=parser()->tokenizer.lex();
1575 if (!tok.is(TokenRetval::TK_WHITESPACE))
1576 {
1577 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1578 goto endindexentry;
1579 }
1581 m_entry="";
1582 tok = parser()->tokenizer.lex();
1583 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1584 {
1585 switch (tok.value())
1586 {
1587 case TokenRetval::TK_WHITESPACE:
1588 m_entry+=" ";
1589 break;
1590 case TokenRetval::TK_WORD:
1591 case TokenRetval::TK_LNKWORD:
1593 break;
1594 case TokenRetval::TK_SYMBOL:
1595 {
1596 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1597 switch (s)
1598 {
1599 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1600 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1601 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1602 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1603 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1604 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1605 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1606 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1607 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1608 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1609 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1610 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1611 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1612 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1613 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1614 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1615 default:
1616 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '{}' found as argument of \\addindex",parser()->context.token->name);
1617 break;
1618 }
1619 }
1620 break;
1621 case TokenRetval::TK_COMMAND_AT:
1622 // fall through
1623 case TokenRetval::TK_COMMAND_BS:
1624 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1625 {
1626 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1627 case CommandType::CMD_AT: m_entry+='@'; break;
1628 case CommandType::CMD_LESS: m_entry+='<'; break;
1629 case CommandType::CMD_GREATER: m_entry+='>'; break;
1630 case CommandType::CMD_AMP: m_entry+='&'; break;
1631 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1632 case CommandType::CMD_HASH: m_entry+='#'; break;
1633 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1634 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1635 case CommandType::CMD_NDASH: m_entry+="--"; break;
1636 case CommandType::CMD_MDASH: m_entry+="---"; break;
1637 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1638 case CommandType::CMD_PUNT: m_entry+='.'; break;
1639 case CommandType::CMD_PLUS: m_entry+='+'; break;
1640 case CommandType::CMD_MINUS: m_entry+='-'; break;
1641 case CommandType::CMD_EQUAL: m_entry+='='; break;
1642 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1643 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1644 default:
1645 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command {} found as argument of \\addindex",
1646 parser()->context.token->name);
1647 break;
1648 }
1649 break;
1650 default:
1651 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
1652 tok.to_string());
1653 break;
1654 }
1655 tok = parser()->tokenizer.lex();
1656 }
1658 m_entry = m_entry.stripWhiteSpace();
1659endindexentry:
1660 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1661 return retval;
1662}
1663
1664//---------------------------------------------------------------------------
1665
1668{
1670 for (const auto &opt : attribs)
1671 {
1672 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1673 {
1674 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1675 if (sec)
1676 {
1677 //printf("Found anchor %s\n",qPrint(id));
1678 m_file = sec->fileName();
1679 m_anchor = sec->label();
1681 }
1682 else
1683 {
1684 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '{}'",opt.value);
1685 }
1686 }
1687 else // copy attribute
1688 {
1689 m_attribs.push_back(opt);
1690 }
1691 }
1692}
1693
1695{
1696 AUTO_TRACE();
1697 Token retval = Token::make_TK_NONE();
1698 auto ns = AutoNodeStack(parser(),thisVariant());
1699 Token tok = parser()->tokenizer.lex();
1700 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1701 {
1702 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1703 {
1704 switch (tok.value())
1705 {
1706 case TokenRetval::TK_HTMLTAG:
1707 {
1708 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1709 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1710 {
1711 retval = Token::make_RetVal_OK();
1712 goto endcaption;
1713 }
1714 else
1715 {
1716 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <caption> context",
1717 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1718 }
1719 }
1720 break;
1721 default:
1722 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1723 break;
1724 }
1725 }
1726 tok = parser()->tokenizer.lex();
1727 }
1728 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1729 {
1730 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1731 " <caption> tag");
1732 }
1733endcaption:
1735 return retval;
1736}
1737
1738//---------------------------------------------------------------------------
1739
1741{
1742 AUTO_TRACE();
1743 Token retval = Token::make_RetVal_OK();
1744 auto ns = AutoNodeStack(parser(),thisVariant());
1745
1746 // parse one or more paragraphs
1747 bool isFirst=TRUE;
1748 DocPara *par=nullptr;
1749 do
1750 {
1752 par = children().get_last<DocPara>();
1753 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1754 retval=par->parse();
1755 if (retval.is(TokenRetval::TK_HTMLTAG))
1756 {
1757 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1758 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1759 {
1760 retval = Token::make_TK_NEWPARA(); // ignore the tag
1761 }
1762 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1763 {
1764 retval = Token::make_TK_NEWPARA(); // ignore the tag
1765 }
1766 }
1767 }
1768 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1769 if (par) par->markLast();
1770
1771 return retval;
1772}
1773
1775{
1776 AUTO_TRACE();
1777 Token retval = Token::make_RetVal_OK();
1778 auto ns = AutoNodeStack(parser(),thisVariant());
1779
1780 // parse one or more paragraphs
1781 bool isFirst=TRUE;
1782 DocPara *par=nullptr;
1783 do
1784 {
1786 par = children().get_last<DocPara>();
1787 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1788 retval=par->parse();
1789 if (retval.is(TokenRetval::TK_HTMLTAG))
1790 {
1791 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1792 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1793 {
1794 retval = Token::make_TK_NEWPARA(); // ignore the tag
1795 }
1796 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1797 {
1798 retval = Token::make_TK_NEWPARA(); // ignore the tag
1799 }
1800 }
1801 }
1802 while (retval.is(TokenRetval::TK_NEWPARA));
1803 if (par) par->markLast();
1804
1805 return retval;
1806}
1807
1808uint32_t DocHtmlCell::rowSpan() const
1809{
1810 for (const auto &attr : attribs())
1811 {
1812 if (attr.name.lower()=="rowspan")
1813 {
1814 return attr.value.toUInt();
1815 }
1816 }
1817 return 0;
1818}
1819
1820uint32_t DocHtmlCell::colSpan() const
1821{
1822 for (const auto &attr : attribs())
1823 {
1824 if (attr.name.lower()=="colspan")
1825 {
1826 return std::max(1u,attr.value.toUInt());
1827 }
1828 }
1829 return 1;
1830}
1831
1833{
1834 for (const auto &attr : attribs())
1835 {
1836 QCString attrName = attr.name.lower();
1837 QCString attrValue = attr.value.lower();
1838 if (attrName=="align")
1839 {
1840 if (attrValue=="center")
1841 return Center;
1842 else if (attrValue=="right")
1843 return Right;
1844 else return Left;
1845 }
1846 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1847 {
1848 if (attrValue=="markdowntableheadcenter")
1849 return Center;
1850 else if (attrValue=="markdowntableheadright")
1851 return Right;
1852 else if (attrValue=="markdowntableheadleft")
1853 return Left;
1854 else if (attrValue=="markdowntableheadnone")
1855 return Center;
1856 else if (attrValue=="markdowntablebodycenter")
1857 return Center;
1858 else if (attrValue=="markdowntablebodyright")
1859 return Right;
1860 else if (attrValue=="markdowntablebodyleft")
1861 return Left;
1862 else if (attrValue=="markdowntablebodynone")
1863 return Left;
1864 else return Left;
1865 }
1866 }
1867 return Left;
1868}
1869
1871{
1872 for (const auto &attr : attribs())
1873 {
1874 QCString attrName = attr.name.lower();
1875 QCString attrValue = attr.value.lower();
1876 if (attrName=="valign")
1877 {
1878 if (attrValue=="top")
1879 return Top;
1880 else if (attrValue=="bottom")
1881 return Bottom;
1882 else if (attrValue=="middle")
1883 return Middle;
1884 else return Middle;
1885 }
1886 }
1887 return Middle;
1888}
1889
1890//---------------------------------------------------------------------------
1891
1893{ // a row is a table heading if all cells are marked as such
1894 bool heading=TRUE;
1895 for (const auto &n : children())
1896 {
1897 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1898 if (cell && !cell->isHeading())
1899 {
1900 heading = FALSE;
1901 break;
1902 }
1903 }
1904 return !children().empty() && heading;
1905}
1906
1908{
1909 AUTO_TRACE();
1910 Token retval = Token::make_RetVal_OK();
1911 auto ns = AutoNodeStack(parser(),thisVariant());
1912
1913 bool isHeading=FALSE;
1914 bool isFirst=TRUE;
1915 DocHtmlCell *cell=nullptr;
1916
1917 // get next token
1918 Token tok=parser()->tokenizer.lex();
1919 // skip whitespace
1920 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
1921 // should find a html tag now
1922 if (tok.is(TokenRetval::TK_HTMLTAG))
1923 {
1924 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1925 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
1926 {
1927 }
1928 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
1929 {
1931 }
1932 else // found some other tag
1933 {
1934 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
1935 "found <{}> instead!",parser()->context.token->name);
1936 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
1937 goto endrow;
1938 }
1939 }
1940 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
1941 {
1942 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
1943 " for a html description title");
1944 goto endrow;
1945 }
1946 else // token other than html token
1947 {
1948 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
1949 tok.to_string());
1950 goto endrow;
1951 }
1952
1953 // parse one or more cells
1954 do
1955 {
1958 isHeading);
1959 cell = children().get_last<DocHtmlCell>();
1960 cell->markFirst(isFirst);
1961 isFirst=FALSE;
1962 retval=cell->parse();
1963 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
1964 }
1965 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
1966 cell->markLast(TRUE);
1967
1968endrow:
1969 return retval;
1970}
1971
1973{
1974 AUTO_TRACE();
1975 Token retval = Token::make_RetVal_OK();
1976 auto ns = AutoNodeStack(parser(),thisVariant());
1977
1978 bool isFirst=TRUE;
1979 DocHtmlCell *cell=nullptr;
1980
1981 // get next token
1982 Token tok=parser()->tokenizer.lex();
1983 // skip whitespace
1984 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
1985 // should find a html tag now
1986 if (tok.is(TokenRetval::TK_HTMLTAG))
1987 {
1988 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1989 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
1990 {
1991 }
1992 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
1993 {
1994 }
1995 else // found some other tag
1996 {
1997 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
1998 "found <{}> instead!",parser()->context.token->name);
1999 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2000 goto endrow;
2001 }
2002 }
2003 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2004 {
2005 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2006 " for a html description title");
2007 goto endrow;
2008 }
2009 else // token other than html token
2010 {
2011 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2012 tok.to_string());
2013 goto endrow;
2014 }
2015
2016 do
2017 {
2019 cell = children().get_last<DocHtmlCell>();
2020 cell->markFirst(isFirst);
2021 isFirst=FALSE;
2022 retval=cell->parseXml();
2023 }
2024 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2025 cell->markLast(TRUE);
2026
2027endrow:
2028 return retval;
2029}
2030
2031//---------------------------------------------------------------------------
2032
2034{
2035 return m_caption!=nullptr;
2036}
2037
2039{
2040 return m_caption.get();
2041}
2042
2044{
2045 if (!children().empty() && std::holds_alternative<DocHtmlRow>(children().front()))
2046 {
2047 return &children().front();
2048 }
2049 return nullptr;
2050}
2051
2053{
2054 AUTO_TRACE();
2055 Token retval = Token::make_RetVal_OK();
2056 auto ns = AutoNodeStack(parser(),thisVariant());
2057
2058getrow:
2059 // get next token
2060 Token tok=parser()->tokenizer.lex();
2061 // skip whitespace
2062 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2063 // should find a html tag now
2064 if (tok.is(TokenRetval::TK_HTMLTAG))
2065 {
2066 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2067 if (tagId==HtmlTagType::HTML_THEAD && !parser()->context.token->endTag) // found <thead> tag
2068 {
2069 goto getrow;
2070 }
2071 else if (tagId==HtmlTagType::HTML_TBODY && !parser()->context.token->endTag) // found <tbody> tag
2072 {
2073 goto getrow;
2074 }
2075 else if (tagId==HtmlTagType::HTML_TFOOT && !parser()->context.token->endTag) // found <tfoot> tag
2076 {
2077 goto getrow;
2078 }
2079 else if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2080 {
2081 // no caption, just rows
2082 retval = Token::make_RetVal_TableRow();
2083 }
2084 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2085 {
2086 if (m_caption)
2087 {
2088 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2089 }
2090 else
2091 {
2092 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2093 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2094
2095 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2096 {
2097 goto getrow;
2098 }
2099 }
2100 }
2101 else // found wrong token
2102 {
2103 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2104 "found <{}{}> instead!", parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2105 }
2106 }
2107 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2108 {
2109 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2110 " for a <tr> or <caption> tag");
2111 }
2112 else // token other than html token
2113 {
2114 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found {} token instead!",
2115 tok.to_string());
2116 }
2117
2118 // parse one or more rows
2119 while (retval.is(TokenRetval::RetVal_TableRow))
2120 {
2122 retval = children().get_last<DocHtmlRow>()->parse();
2123 }
2124
2126
2127 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2128}
2129
2131{
2132 AUTO_TRACE();
2133 Token retval = Token::make_RetVal_OK();
2134 auto ns = AutoNodeStack(parser(),thisVariant());
2135
2136 // get next token
2137 Token tok=parser()->tokenizer.lex();
2138 // skip whitespace
2139 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2140 // should find a html tag now
2142 bool isHeader=FALSE;
2143 if (tok.is(TokenRetval::TK_HTMLTAG))
2144 {
2145 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2146 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2147 {
2148 retval = Token::make_RetVal_TableRow();
2149 }
2150 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2151 {
2152 retval = Token::make_RetVal_TableRow();
2153 isHeader=TRUE;
2154 }
2155 }
2156
2157 // parse one or more rows
2158 while (retval.is(TokenRetval::RetVal_TableRow))
2159 {
2162 retval=tr->parseXml(isHeader);
2163 isHeader=FALSE;
2164 }
2165
2167
2168 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2169 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2170}
2171
2172/** Helper class to compute the grid for an HTML style table */
2174{
2175 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2176 uint32_t rowsLeft;
2177 uint32_t column;
2178};
2179
2180/** List of ActiveRowSpan classes. */
2181typedef std::vector<ActiveRowSpan> RowSpanList;
2182
2183/** determines the location of all cells in a grid, resolving row and
2184 column spans. For each the total number of visible cells is computed,
2185 and the total number of visible columns over all rows is stored.
2186 */
2188{
2189 //printf("computeTableGrid()\n");
2190 RowSpanList rowSpans;
2191 uint32_t maxCols=0;
2192 uint32_t rowIdx=1;
2193 for (auto &rowNode : children())
2194 {
2195 uint32_t colIdx=1;
2196 uint32_t cells=0;
2197 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2198 if (row)
2199 {
2200 for (auto &cellNode : row->children())
2201 {
2202 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2203 if (cell)
2204 {
2205 uint32_t rs = cell->rowSpan();
2206 uint32_t cs = cell->colSpan();
2207
2208 for (size_t i=0;i<rowSpans.size();i++)
2209 {
2210 if (rowSpans[i].rowsLeft>0 &&
2211 rowSpans[i].column==colIdx)
2212 {
2213 colIdx=rowSpans[i].column+1;
2214 cells++;
2215 }
2216 }
2217 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2218 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2219 cell->setRowIndex(rowIdx);
2220 cell->setColumnIndex(colIdx);
2221 colIdx+=cs;
2222 cells++;
2223 }
2224 }
2225 for (size_t i=0;i<rowSpans.size();i++)
2226 {
2227 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2228 }
2229 row->setVisibleCells(cells);
2230 row->setRowIndex(rowIdx);
2231 rowIdx++;
2232 }
2233 if (colIdx-1>maxCols) maxCols=colIdx-1;
2234 }
2235 m_numCols = maxCols;
2236}
2237
2238//---------------------------------------------------------------------------
2239
2241{
2242 AUTO_TRACE();
2243 Token retval = Token::make_TK_NONE();
2244 auto ns = AutoNodeStack(parser(),thisVariant());
2245
2246 Token tok = parser()->tokenizer.lex();
2247 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2248 {
2249 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2250 {
2251 switch (tok.value())
2252 {
2253 case TokenRetval::TK_COMMAND_AT:
2254 // fall through
2255 case TokenRetval::TK_COMMAND_BS:
2256 {
2257 QCString cmdName=parser()->context.token->name;
2258 bool isJavaLink=FALSE;
2259 switch (Mappers::cmdMapper->map(cmdName))
2260 {
2262 {
2263 tok=parser()->tokenizer.lex();
2264 if (!tok.is(TokenRetval::TK_WHITESPACE))
2265 {
2266 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
2267 tok.command_to_char(),cmdName);
2268 }
2269 else
2270 {
2272 tok=parser()->tokenizer.lex(); // get the reference id
2273 if (!tok.is(TokenRetval::TK_WORD))
2274 {
2275 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}' command",
2276 tok.to_string(),tok.command_to_char(),cmdName);
2277 }
2278 else
2279 {
2281 children().get_last<DocRef>()->parse();
2282 }
2284 }
2285 }
2286 break;
2288 isJavaLink=TRUE;
2289 // fall through
2291 {
2292 tok=parser()->tokenizer.lex();
2293 if (!tok.is(TokenRetval::TK_WHITESPACE))
2294 {
2295 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
2296 cmdName);
2297 }
2298 else
2299 {
2301 tok=parser()->tokenizer.lex();
2302 if (!tok.is(TokenRetval::TK_WORD))
2303 {
2304 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\{} command",
2305 tok.to_string(),cmdName);
2306 }
2307 else
2308 {
2311 DocLink *lnk = children().get_last<DocLink>();
2312 QCString leftOver = lnk->parse(isJavaLink);
2313 if (!leftOver.isEmpty())
2314 {
2315 children().append<DocWord>(parser(),thisVariant(),leftOver);
2316 }
2317 }
2318 }
2319 }
2320
2321 break;
2322 default:
2323 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' found as part of a <dt> tag",
2324 tok.command_to_char(),cmdName);
2325 }
2326 }
2327 break;
2328 case TokenRetval::TK_SYMBOL:
2329 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a <dt> tag",
2330 parser()->context.token->name);
2331 break;
2332 case TokenRetval::TK_HTMLTAG:
2333 {
2334 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2335 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2336 {
2337 retval = Token::make_RetVal_DescData();
2338 goto endtitle;
2339 }
2340 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2341 {
2342 // ignore </dt> tag.
2343 }
2344 else if (tagId==HtmlTagType::HTML_DT)
2345 {
2346 // missing <dt> tag.
2347 retval = Token::make_RetVal_DescTitle();
2348 goto endtitle;
2349 }
2350 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2351 {
2352 retval = Token::make_RetVal_EndDesc();
2353 goto endtitle;
2354 }
2355 else if (tagId==HtmlTagType::HTML_A)
2356 {
2357 if (!parser()->context.token->endTag)
2358 {
2359 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2360 }
2361 }
2362 else
2363 {
2364 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <dt> context",
2365 parser()->context.token->endTag?"/":"",parser()->context.token->name);
2366 }
2367 }
2368 break;
2369 default:
2370 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} found as part of a <dt> tag",
2371 tok.to_string());
2372 break;
2373 }
2374 }
2375 tok = parser()->tokenizer.lex();
2376 }
2377 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2378 {
2379 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2380 " <dt> tag");
2381 }
2382endtitle:
2384 return retval;
2385}
2386
2387//---------------------------------------------------------------------------
2388
2390{
2391 AUTO_TRACE();
2393 Token retval = Token::make_TK_NONE();
2394 auto ns = AutoNodeStack(parser(),thisVariant());
2395
2396 bool isFirst=TRUE;
2397 DocPara *par=nullptr;
2398 do
2399 {
2401 par = children().get_last<DocPara>();
2402 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2403 retval=par->parse();
2404 }
2405 while (retval.is(TokenRetval::TK_NEWPARA));
2406 if (par) par->markLast();
2407
2408 return retval;
2409}
2410
2411//---------------------------------------------------------------------------
2412
2414{
2415 AUTO_TRACE();
2416 Token retval = Token::make_RetVal_OK();
2417 auto ns = AutoNodeStack(parser(),thisVariant());
2418
2419 // get next token
2420 Token tok=parser()->tokenizer.lex();
2421 // skip whitespace
2422 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2423 // should find a html tag now
2424 if (tok.is(TokenRetval::TK_HTMLTAG))
2425 {
2426 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2427 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2428 {
2429 // continue
2430 }
2431 else // found some other tag
2432 {
2433 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2434 "found <{}> instead!",parser()->context.token->name);
2435 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2436 goto enddesclist;
2437 }
2438 }
2439 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2440 {
2441 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2442 " for a html description title");
2443 goto enddesclist;
2444 }
2445 else // token other than html token
2446 {
2447 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found {} token instead!",
2448 tok.to_string());
2449 goto enddesclist;
2450 }
2451
2452 do
2453 {
2458 retval=dt->parse();
2459 if (retval.is(TokenRetval::RetVal_DescData))
2460 {
2461 retval=dd->parse();
2462 while (retval.is(TokenRetval::RetVal_DescData))
2463 {
2466 retval=dd->parse();
2467 }
2468 }
2469 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2470 {
2471 // error
2472 break;
2473 }
2474 } while (retval.is(TokenRetval::RetVal_DescTitle));
2475
2476 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2477 {
2478 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2479 }
2480
2481enddesclist:
2482
2483 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2484}
2485
2486//---------------------------------------------------------------------------
2487
2489{
2490 AUTO_TRACE();
2491 Token retval = Token::make_TK_NONE();
2492 auto ns = AutoNodeStack(parser(),thisVariant());
2493
2494 // parse one or more paragraphs
2495 bool isFirst=TRUE;
2496 DocPara *par=nullptr;
2497 do
2498 {
2500 par = children().get_last<DocPara>();
2501 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2502 retval=par->parse();
2503 }
2504 while (retval.is(TokenRetval::TK_NEWPARA));
2505 if (par) par->markLast();
2506
2507 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2508 return retval;
2509}
2510
2512{
2513 AUTO_TRACE();
2514 Token retval = Token::make_TK_NONE();
2515 auto ns = AutoNodeStack(parser(),thisVariant());
2516
2517 // parse one or more paragraphs
2518 bool isFirst=TRUE;
2519 DocPara *par=nullptr;
2520 do
2521 {
2523 par = children().get_last<DocPara>();
2524 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2525 retval=par->parse();
2526 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2527
2528 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2529 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2530 if (retval.is(TokenRetval::RetVal_ListItem))
2531 {
2532 break;
2533 }
2534 }
2535 while (!retval.is(TokenRetval::RetVal_CloseXml));
2536
2537 if (par) par->markLast();
2538
2539 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2540 return retval;
2541}
2542
2543//---------------------------------------------------------------------------
2544
2546{
2547 AUTO_TRACE();
2548 Token retval = Token::make_RetVal_OK();
2549 int num=1;
2550 auto ns = AutoNodeStack(parser(),thisVariant());
2551
2552 // get next token
2553 Token tok=parser()->tokenizer.lex();
2554 // skip whitespace and paragraph breaks
2555 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2556 // should find a html tag now
2557 if (tok.is(TokenRetval::TK_HTMLTAG))
2558 {
2559 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2560 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2561 {
2562 // ok, we can go on.
2563 }
2564 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2566 ) && parser()->context.token->endTag
2567 ) // found empty list
2568 {
2569 // add dummy item to obtain valid HTML
2571 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2572 retval = Token::make_RetVal_EndList();
2573 goto endlist;
2574 }
2575 else // found some other tag
2576 {
2577 // add dummy item to obtain valid HTML
2579 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2580 "found <{}{}> instead!",parser()->context.token->endTag?"/":"",parser()->context.token->name);
2581 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2582 goto endlist;
2583 }
2584 }
2585 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2586 {
2587 // add dummy item to obtain valid HTML
2589 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2590 " for a html list item");
2591 goto endlist;
2592 }
2593 else // token other than html token
2594 {
2595 // add dummy item to obtain valid HTML
2597 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found {} token instead!",
2598 tok.to_string());
2599 goto endlist;
2600 }
2601
2602 do
2603 {
2606 retval=li->parse();
2607 } while (retval.is(TokenRetval::RetVal_ListItem));
2608
2609 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2610 {
2611 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <{:c}l> block",
2612 m_type==Unordered ? 'u' : 'o');
2613 }
2614
2615endlist:
2616 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2617 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2618}
2619
2621{
2622 AUTO_TRACE();
2623 Token retval = Token::make_RetVal_OK();
2624 int num=1;
2625 auto ns = AutoNodeStack(parser(),thisVariant());
2626
2627 // get next token
2628 Token tok=parser()->tokenizer.lex();
2629 // skip whitespace and paragraph breaks
2630 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2631 // should find a html tag now
2632 if (tok.is(TokenRetval::TK_HTMLTAG))
2633 {
2634 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2635 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2636 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2637 {
2638 // ok, we can go on.
2639 }
2640 else // found some other tag
2641 {
2642 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2643 "found <{}> instead!",parser()->context.token->name);
2644 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2645 goto endlist;
2646 }
2647 }
2648 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2649 {
2650 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2651 " for a html list item");
2652 goto endlist;
2653 }
2654 else // token other than html token
2655 {
2656 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found {} token instead!",
2657 tok.to_string());
2658 goto endlist;
2659 }
2660
2661 do
2662 {
2665 retval=li->parseXml();
2666 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2667 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2668 } while (retval.is(TokenRetval::RetVal_ListItem));
2669
2670 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2671 {
2672 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"{}\"> block",
2673 m_type==Unordered ? "bullet" : "number");
2674 }
2675
2676endlist:
2677 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2678 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2679 Token::make_RetVal_OK() : retval;
2680}
2681
2682//--------------------------------------------------------------------------
2683
2685{
2686 AUTO_TRACE();
2687 Token retval = Token::make_TK_NONE();
2688 auto ns = AutoNodeStack(parser(),thisVariant());
2689
2690 // parse one or more paragraphs
2691 bool isFirst=TRUE;
2692 DocPara *par=nullptr;
2693 do
2694 {
2696 par = children().get_last<DocPara>();
2697 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2698 retval=par->parse();
2699 }
2700 while (retval.is(TokenRetval::TK_NEWPARA));
2701 if (par) par->markLast();
2702
2703 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2704 {
2705 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2706 }
2707
2708 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2709 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2710}
2711
2712//---------------------------------------------------------------------------
2713
2715{
2716 AUTO_TRACE();
2717 Token retval = Token::make_TK_NONE();
2718 auto ns = AutoNodeStack(parser(),thisVariant());
2719
2720 // parse one or more paragraphs
2721 bool isFirst=TRUE;
2722 DocPara *par=nullptr;
2723 do
2724 {
2726 par = children().get_last<DocPara>();
2727 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2728 retval=par->parse();
2729 }
2730 while (retval.is(TokenRetval::TK_NEWPARA));
2731 if (par) par->markLast();
2732
2733 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2734 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2735}
2736
2737//---------------------------------------------------------------------------
2738
2743
2744
2746{
2747 auto ns = AutoNodeStack(parser(),thisVariant());
2749 DocPara *par = &std::get<DocPara>(*m_paragraph);
2750 Token rv=par->parse();
2751 par->markFirst();
2752 par->markLast();
2753 return rv;
2754}
2755
2756//--------------------------------------------------------------------------
2757
2759{
2760 auto ns = AutoNodeStack(parser(),thisVariant());
2761 Token rv = Token::make_TK_NONE();
2762 do
2763 {
2766 rv=li->parse();
2767 } while (rv.is(TokenRetval::RetVal_ListItem));
2768 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2769}
2770
2771//--------------------------------------------------------------------------
2772
2777
2779{
2780 AUTO_TRACE();
2781 Token retval = Token::make_RetVal_OK();
2782 auto ns = AutoNodeStack(parser(),thisVariant());
2783
2784 // first parse any number of paragraphs
2785 bool isFirst=TRUE;
2786 DocPara *lastPar=nullptr;
2787 do
2788 {
2790 DocPara *par = children().get_last<DocPara>();
2791 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2792 retval=par->parse();
2793 if (!par->isEmpty())
2794 {
2795 if (lastPar) lastPar->markLast(FALSE);
2796 lastPar=par;
2797 }
2798 else
2799 {
2800 children().pop_back();
2801 }
2802 // next paragraph should be more indented than the - marker to belong
2803 // to this item
2804 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2805 if (lastPar) lastPar->markLast();
2806
2807 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2808 return retval;
2809}
2810
2811//--------------------------------------------------------------------------
2812
2819
2821{
2822 AUTO_TRACE();
2823 Token retval = Token::make_RetVal_OK();
2824 int num=1;
2825 auto ns = AutoNodeStack(parser(),thisVariant());
2827 // first item or sub list => create new list
2828 do
2829 {
2830 switch (parser()->context.token->id)
2831 {
2832 case -1:
2833 break;
2834 case DocAutoList::Unchecked: // unchecked
2835 case DocAutoList::Checked_x: // checked with x
2836 case DocAutoList::Checked_X: // checked with X
2837 num = parser()->context.token->id;
2838 break;
2839 default: // explicitly numbered list
2840 num=parser()->context.token->id; // override num with real number given
2841 break;
2842 }
2843
2845 retval = children().get_last<DocAutoListItem>()->parse();
2846 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
2847 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
2848 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
2849 // qPrint(parser()->context.token->name));
2850 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
2851 }
2852 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
2853 m_indent==parser()->context.token->indent && // at same indent level
2854 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
2855 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
2856 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
2857 );
2858
2860 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2861 return retval;
2862}
2863
2864//--------------------------------------------------------------------------
2865
2867{
2868 AUTO_TRACE();
2869 auto ns = AutoNodeStack(parser(),thisVariant());
2871 Token tok = parser()->tokenizer.lex();
2872 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2873 {
2874 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2875 {
2876 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
2877 }
2878 tok = parser()->tokenizer.lex();
2879 }
2882}
2883
2885{
2887 parser()->pushContext(); // this will create a new parser->context.token
2889 parser()->popContext(); // this will restore the old parser->context.token
2893}
2894
2895//--------------------------------------------------------------------------
2896
2901
2903{
2904 return m_title && std::get<DocTitle>(*m_title).hasTitle();
2905}
2906
2907Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
2908{
2909 AUTO_TRACE();
2910 auto ns = AutoNodeStack(parser(),thisVariant());
2911
2912 // handle case for user defined title
2913 if (userTitle)
2914 {
2916 std::get_if<DocTitle>(m_title.get())->parse();
2917 }
2918
2919 // add new paragraph as child
2920 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
2921 {
2922 std::get<DocPara>(children().back()).markLast(FALSE);
2923 }
2924 bool markFirst = children().empty();
2925 if (needsSeparator)
2926 {
2928 }
2930 DocPara *par = children().get_last<DocPara>();
2931 if (markFirst)
2932 {
2933 par->markFirst();
2934 }
2935 par->markLast();
2936
2937 // parse the contents of the paragraph
2938 Token retval = par->parse();
2939
2940 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2941 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
2942}
2943
2945{
2946 AUTO_TRACE();
2947 auto ns = AutoNodeStack(parser(),thisVariant());
2948
2950 DocTitle *title = &std::get<DocTitle>(*m_title);
2951 title->parseFromString(thisVariant(),parser()->context.token->name);
2952
2953 QCString text = parser()->context.token->text;
2954 parser()->pushContext(); // this will create a new parser->context.token
2956 parser()->popContext(); // this will restore the old parser->context.token
2957
2958 return Token::make_RetVal_OK();
2959}
2960
2962{
2963 AUTO_TRACE();
2964 auto ns = AutoNodeStack(parser(),thisVariant());
2965
2966 Token retval = Token::make_RetVal_OK();
2967 for (;;)
2968 {
2969 // add new paragraph as child
2970 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
2971 {
2972 std::get<DocPara>(children().back()).markLast(false);
2973 }
2974 bool markFirst = children().empty();
2976 DocPara *par = children().get_last<DocPara>();
2977 if (markFirst)
2978 {
2979 par->markFirst();
2980 }
2981 par->markLast();
2982
2983 // parse the contents of the paragraph
2984 retval = par->parse();
2985 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2986 if (retval.is(TokenRetval::RetVal_CloseXml))
2987 {
2988 retval = Token::make_RetVal_OK();
2989 break;
2990 }
2991 }
2992
2993 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2994 return retval;
2995}
2996
2998{
2999 DocPara *p=nullptr;
3000 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
3001 {
3003 p = children().get_last<DocPara>();
3004 }
3005 else
3006 {
3007 // Comma-separate <seealso> links.
3008 p->injectToken(Token::make_TK_WORD(),",");
3009 p->injectToken(Token::make_TK_WHITESPACE()," ");
3010 }
3011
3013 p->injectToken(Token::make_TK_LNKWORD(),word);
3015}
3016
3018{
3019 switch (m_type)
3020 {
3021 case Unknown: break;
3022 case See: return "see";
3023 case Return: return "return";
3024 case Author: // fall through
3025 case Authors: return "author";
3026 case Version: return "version";
3027 case Since: return "since";
3028 case Date: return "date";
3029 case Note: return "note";
3030 case Warning: return "warning";
3031 case Pre: return "pre";
3032 case Post: return "post";
3033 case Copyright: return "copyright";
3034 case Invar: return "invariant";
3035 case Remark: return "remark";
3036 case Attention: return "attention";
3037 case Important: return "important";
3038 case User: return "user";
3039 case Rcs: return "rcs";
3040 }
3041 return "unknown";
3042}
3043
3044//--------------------------------------------------------------------------
3045
3047{
3048 AUTO_TRACE();
3049 Token retval = Token::make_RetVal_OK();
3050 auto ns = AutoNodeStack(parser(),thisVariant());
3051 DocPara *par=nullptr;
3052 QCString saveCmdName = cmdName;
3053
3054 Token tok=parser()->tokenizer.lex();
3055 if (!tok.is(TokenRetval::TK_WHITESPACE))
3056 {
3057 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3058 saveCmdName);
3059 retval = Token::make_RetVal_EndParBlock();
3060 goto endparamlist;
3061 }
3063 tok=parser()->tokenizer.lex();
3064 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3065 {
3067 {
3068 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3069 if (typeSeparator!=-1)
3070 {
3071 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3072 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3075 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3076 {
3077 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3078 }
3079 }
3080 else
3081 {
3084 }
3085 }
3086 else if (m_type==DocParamSect::RetVal)
3087 {
3090 }
3091 //m_params.append(parser()->context.token->name);
3093 tok=parser()->tokenizer.lex();
3094 }
3096 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3097 {
3098 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3099 "argument of command {}",saveCmdName);
3100 retval = Token::make_RetVal_EndParBlock();
3101 goto endparamlist;
3102 }
3103 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3104 {
3105 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3106 {
3107 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3108 "argument of command {}",tok.to_string(),saveCmdName);
3109 }
3110 retval = Token::make_RetVal_EndParBlock();
3111 goto endparamlist;
3112 }
3113
3115 par = m_paragraphs.get_last<DocPara>();
3116 retval = par->parse();
3117 par->markFirst();
3118 par->markLast();
3119
3120endparamlist:
3121 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3122 return retval;
3123}
3124
3126{
3127 AUTO_TRACE();
3128 Token retval = Token::make_RetVal_OK();
3129 auto ns = AutoNodeStack(parser(),thisVariant());
3130
3131 parser()->context.token->name = paramName;
3133 {
3136 }
3137 else if (m_type==DocParamSect::RetVal)
3138 {
3141 }
3142
3144
3145 do
3146 {
3148 DocPara *par = m_paragraphs.get_last<DocPara>();
3149 retval = par->parse();
3150 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3151 // after </para> and before </param>
3152 {
3153 m_paragraphs.pop_back();
3154 break;
3155 }
3156 else // append the paragraph to the list
3157 {
3158 if (!m_paragraphs.empty())
3159 {
3160 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3161 }
3162 bool markFirst = m_paragraphs.empty();
3163 par = &std::get<DocPara>(m_paragraphs.back());
3164 if (markFirst)
3165 {
3166 par->markFirst();
3167 }
3168 par->markLast();
3169 }
3170
3171 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3172
3173 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3174 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3175 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3176 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3177
3178 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3179 {
3180 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3181 }
3182 else
3183 {
3184 retval = Token::make_RetVal_OK();
3185 }
3186
3187 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3188 return retval;
3189}
3190
3191//--------------------------------------------------------------------------
3192
3193Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3194{
3195 AUTO_TRACE();
3196 Token retval = Token::make_RetVal_OK();
3197 auto ns = AutoNodeStack(parser(),thisVariant());
3198
3199 if (d!=Unspecified)
3200 {
3202 }
3203
3204 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3205 {
3206 DocParamList &lastPl = std::get<DocParamList>(children().back());
3207 lastPl.markLast(false);
3208 }
3209 bool markFirst = children().empty();
3212 if (markFirst)
3213 {
3214 pl->markFirst();
3215 }
3216 pl->markLast();
3217 if (xmlContext)
3218 {
3219 retval = pl->parseXml(cmdName);
3220 }
3221 else
3222 {
3223 retval = pl->parse(cmdName);
3224 }
3225 if (retval.is(TokenRetval::RetVal_EndParBlock))
3226 {
3227 retval = Token::make_RetVal_OK();
3228 }
3229
3230 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3231 return retval;
3232}
3233
3234//--------------------------------------------------------------------------
3235
3241
3243{
3244 AUTO_TRACE();
3245 DocSimpleSect *ss=nullptr;
3246 bool needsSeparator = FALSE;
3247 if (!children().empty() && // has previous element
3248 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3249 ss->type()==t && // of same type
3250 t!=DocSimpleSect::User) // but not user defined
3251 {
3252 // append to previous section
3253 needsSeparator = TRUE;
3254 }
3255 else // start new section
3256 {
3259 }
3260 Token rv = Token::make_RetVal_OK();
3261 if (xmlContext)
3262 {
3263 return ss->parseXml();
3264 }
3265 else
3266 {
3267 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3268 }
3269 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3270}
3271
3274 bool xmlContext=FALSE,
3275 int direction=DocParamSect::Unspecified)
3276{
3277 AUTO_TRACE();
3278 DocParamSect *ps = nullptr;
3279 if (!children().empty() && // previous element
3280 (ps=children().get_last<DocParamSect>()) && // was a param sect
3281 ps->type()==t) // of same type
3282 { // append to previous section ps
3283 }
3284 else // start new section
3285 {
3287 ps = children().get_last<DocParamSect>();
3288 }
3289 Token rv=ps->parse(cmdName,xmlContext,
3290 static_cast<DocParamSect::Direction>(direction));
3291 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3292 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3293}
3294
3295void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3296{
3297 AUTO_TRACE();
3298 // get the argument of the cite command.
3299 Token tok=parser()->tokenizer.lex();
3300 if (!tok.is(TokenRetval::TK_WHITESPACE))
3301 {
3302 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3303 cmdChar,cmdName);
3304 return;
3305 }
3307 tok=parser()->tokenizer.lex();
3308 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3309 {
3310 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3311 "argument of command '{:c}{}'",cmdChar,cmdName);
3312 return;
3313 }
3314 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3315 {
3316 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3317 tok.to_string(),cmdChar,cmdName);
3318 return;
3319 }
3323
3325}
3326
3327void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3328{
3329 AUTO_TRACE();
3330 // get the argument of the emoji command.
3331 Token tok=parser()->tokenizer.lex();
3332 if (!tok.is(TokenRetval::TK_WHITESPACE))
3333 {
3334 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3335 cmdChar,cmdName);
3336 return;
3337 }
3339 tok=parser()->tokenizer.lex();
3340 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3341 {
3342 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3343 "argument of command '{:c}{}'",cmdChar,cmdName);
3345 return;
3346 }
3347 else if (!tok.is(TokenRetval::TK_WORD))
3348 {
3349 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3350 tok.to_string(),cmdChar,cmdName);
3352 return;
3353 }
3356}
3357
3358void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3359{
3360 // get the argument of the cite command.
3361 Token tok=parser()->tokenizer.lex();
3362 if (!tok.is(TokenRetval::TK_WHITESPACE))
3363 {
3364 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3365 cmdChar,cmdName);
3366 return;
3367 }
3369 tok=parser()->tokenizer.lex();
3370 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3371 {
3372 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3373 "argument of command '{:c}{}'",cmdChar,cmdName);
3374 return;
3375 }
3376 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3377 {
3378 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3379 tok.to_string(),cmdChar,cmdName);
3380 return;
3381 }
3382 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3383 if (opt)
3384 {
3385 QCString optionValue;
3386 switch (opt->kind())
3387 {
3389 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3390 break;
3392 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3393 break;
3395 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3396 break;
3398 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3399 break;
3401 {
3402 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3403 optionValue="";
3404 if (!lst->empty())
3405 {
3406 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3407 static const reg::Ex marker(R"(@(\d+))");
3408 reg::Iterator it(lstFormat,marker);
3410 size_t index=0;
3411 // now replace all markers with the real text
3412 for ( ; it!=end ; ++it)
3413 {
3414 const auto &match = *it;
3415 size_t newIndex = match.position();
3416 size_t matchLen = match.length();
3417 optionValue += lstFormat.substr(index,newIndex-index);
3418 unsigned long entryIndex = std::stoul(match[1].str());
3419 if (entryIndex<(unsigned long)lst->size())
3420 {
3421 optionValue += lst->at(entryIndex);
3422 }
3423 index=newIndex+matchLen;
3424 }
3425 optionValue+=lstFormat.substr(index);
3426 }
3427 }
3428 break;
3430 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3431 cmdChar,cmdName,parser()->context.token->name);
3432 break;
3434 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3435 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3436 cmdChar,cmdName,parser()->context.token->name);
3437 break;
3439 // nothing to show here
3440 break;
3441 }
3442 if (!optionValue.isEmpty())
3443 {
3444 children().append<DocWord>(parser(),thisVariant(),optionValue);
3445 }
3446 }
3447 else
3448 {
3449 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3450 cmdChar,cmdName,parser()->context.token->name);
3452 }
3454}
3455
3457{
3458 AUTO_TRACE();
3459 Token retval=parser()->tokenizer.lex();
3460 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3462 retval=parser()->tokenizer.lex();
3463 if (retval.is(TokenRetval::RetVal_OK))
3464 {
3468 if (!ref->parse())
3469 {
3470 children().pop_back();
3471 }
3472 }
3474 return retval;
3475}
3476
3477void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3478{
3479 AUTO_TRACE();
3480 QCString fmt;
3481 QCString date;
3482 Token tok=parser()->tokenizer.lex();
3483 if (!tok.is(TokenRetval::TK_WHITESPACE))
3484 {
3485 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3486 cmdChar,cmdName);
3487 return;
3488 }
3490 tok = parser()->tokenizer.lex();
3491 if (!tok.is(TokenRetval::TK_WORD))
3492 {
3493 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3494 cmdChar,cmdName);
3496 return;
3497 }
3498 fmt = parser()->context.token->name;
3499
3501 tok = parser()->tokenizer.lex();
3502
3503 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3504 QCString specDate = specDateRaw.stripWhiteSpace();
3505 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3506 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3507 {
3508 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3509 cmdChar,cmdName);
3511 return;
3512 }
3513
3514 std::tm dat{};
3515 int specFormat=0;
3516 QCString err = dateTimeFromString(specDate,dat,specFormat);
3517 if (!err.isEmpty())
3518 {
3519 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3520 cmdChar,cmdName,err);
3522 return;
3523 }
3524
3525 int usedFormat=0;
3526 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3527
3528 // warn the user if the format contains markers that are not explicitly filled in
3529 for (int i=0;i<SF_NumBits;i++)
3530 {
3531 int bitMask = 1<<i;
3532 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3533 {
3534 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.",
3535 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3536 }
3537 }
3538
3539 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3540 if (specDateOnlyWS) // specDate is only whitespace
3541 {
3543 }
3545}
3546
3547void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3548{
3549 AUTO_TRACE();
3551 Token tok = parser()->tokenizer.lex();
3552 if (!tok.is(TokenRetval::TK_WORD))
3553 {
3554 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
3555 cmdChar,cmdName);
3556 return;
3557 }
3559}
3560
3561void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3562{
3563 AUTO_TRACE();
3564 Token tok=parser()->tokenizer.lex();
3565 if (!tok.is(TokenRetval::TK_WHITESPACE))
3566 {
3567 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3568 cmdChar,cmdName);
3569 return;
3570 }
3572 tok=parser()->tokenizer.lex();
3574 if (!tok.is(TokenRetval::TK_WORD))
3575 {
3576 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3577 tok.to_string(),cmdChar,cmdName);
3578 return;
3579 }
3582}
3583
3584
3586{
3587 AUTO_TRACE("cmdName={}",cmdName);
3588 QCString saveCmdName = cmdName;
3589 Token tok=parser()->tokenizer.lex();
3590 if (!tok.is(TokenRetval::TK_WHITESPACE))
3591 {
3592 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3593 saveCmdName);
3594 return;
3595 }
3597 tok=parser()->tokenizer.lex();
3599 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3600 {
3601 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3602 "argument of command {}", saveCmdName);
3603 return;
3604 }
3605 else if (!tok.is(TokenRetval::TK_WORD))
3606 {
3607 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3608 tok.to_string(),saveCmdName);
3609 return;
3610 }
3611 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3612 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3613 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3614 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3615 //TODO get from context the stripCodeComments()
3616 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3620 stripCodeComments,
3623 );
3625 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3626 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3627 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3628 bool isFirst = !n1 || // no last node
3629 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3630 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3631 op->markFirst(isFirst);
3632 op->markLast(true);
3633 if (n1_docIncOp)
3634 {
3635 n1_docIncOp->markLast(false);
3636 }
3637 else if (n1_docWs && n2_docIncOp)
3638 {
3639 n2_docIncOp->markLast(false);
3640 }
3641 op->parse();
3642}
3643
3644template<class T>
3645void DocPara::handleFile(const QCString &cmdName)
3646{
3647 AUTO_TRACE("cmdName={}",cmdName);
3648 QCString saveCmdName = cmdName;
3649 Token tok=parser()->tokenizer.lex();
3650 if (!tok.is(TokenRetval::TK_WHITESPACE))
3651 {
3652 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3653 saveCmdName);
3654 return;
3655 }
3657 tok=parser()->tokenizer.lex();
3659 if (!tok.is(TokenRetval::TK_WORD))
3660 {
3661 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3662 tok.to_string(),saveCmdName);
3663 return;
3664 }
3665 QCString name = parser()->context.token->name;
3666 children().append<T>(parser(),thisVariant(),name,
3670 auto df = children().get_last<T>();
3671 if (!df->parse())
3672 {
3673 children().pop_back();
3674 }
3675}
3676
3683
3684void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3685{
3686 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3687 QCString saveCmdName = cmdName;
3688 Token tok=parser()->tokenizer.lex();
3689 if (!tok.is(TokenRetval::TK_WHITESPACE))
3690 {
3691 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3692 saveCmdName);
3693 return;
3694 }
3696 tok=parser()->tokenizer.lex();
3697 if (!tok.is(TokenRetval::TK_WORD))
3698 {
3699 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3700 tok.to_string(),saveCmdName);
3701 return;
3702 }
3703 if (saveCmdName == "javalink")
3704 {
3706 parser()->context.nodeStack.size(),
3707 DocStyleChange::Code,cmdName,TRUE);
3708 }
3711 DocLink *lnk = children().get_last<DocLink>();
3712 if (saveCmdName == "javalink")
3713 {
3715 parser()->context.nodeStack.size(),
3716 DocStyleChange::Code,cmdName,FALSE);
3717 }
3718 QCString leftOver = lnk->parse(isJavaLink);
3719 if (!leftOver.isEmpty())
3720 {
3721 children().append<DocWord>(parser(),thisVariant(),leftOver);
3722 }
3723}
3724
3725void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3726{
3727 AUTO_TRACE("cmdName={}",cmdName);
3728 QCString saveCmdName = cmdName;
3729 Token tok=parser()->tokenizer.lex();
3730 if (!tok.is(TokenRetval::TK_WHITESPACE))
3731 {
3732 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3733 cmdChar,qPrint(saveCmdName));
3734 return;
3735 }
3737 tok=parser()->tokenizer.lex(); // get the reference id
3738 if (!tok.is(TokenRetval::TK_WORD))
3739 {
3740 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3741 tok.to_string(),cmdChar,saveCmdName);
3742 goto endref;
3743 }
3747 children().get_last<DocRef>()->parse();
3748endref:
3750}
3751
3753{
3754 AUTO_TRACE("cmdName={}",cmdName);
3755 QCString saveCmdName = cmdName;
3756 Token tok=parser()->tokenizer.lex();
3757 bool isBlock = false;
3758 bool trimLeft = false;
3759 bool localScope = false;
3760 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3761 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3762 {
3764 parser()->tokenizer.lex();
3766 StringVector optList=split(parser()->context.token->name.str(),",");
3767 auto contains = [&optList](const char *kw)
3768 {
3769 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
3770 };
3771 localScope = contains("local");
3772 if (contains("nostrip"))
3773 {
3774 stripCodeComments = false;
3775 }
3776 else if (contains("strip"))
3777 {
3778 stripCodeComments = true;
3779 }
3780 if (t==DocInclude::Snippet && contains("trimleft"))
3781 {
3782 trimLeft = true;
3783 }
3784
3785 if (contains("lineno"))
3786 {
3790 }
3791 tok=parser()->tokenizer.lex();
3792 if (!tok.is(TokenRetval::TK_WHITESPACE))
3793 {
3794 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3795 saveCmdName);
3796 return;
3797 }
3798 }
3799 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
3800 {
3802 parser()->tokenizer.lex();
3803 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
3805 parser()->tokenizer.lex();
3806 }
3807 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3808 {
3809 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3810 saveCmdName);
3811 return;
3812 }
3814 tok=parser()->tokenizer.lex();
3816 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3817 {
3818 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3819 "argument of command {}",saveCmdName);
3820 return;
3821 }
3822 else if (!tok.is(TokenRetval::TK_WORD))
3823 {
3824 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3825 tok.to_string(),saveCmdName);
3826 return;
3827 }
3828 QCString fileName = parser()->context.token->name;
3829 QCString blockId;
3831 {
3832 if (fileName == "this") fileName=parser()->context.fileName;
3834 tok=parser()->tokenizer.lex();
3836 if (!tok.is(TokenRetval::TK_WORD))
3837 {
3838 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
3839 tok.to_string(),saveCmdName);
3840 return;
3841 }
3842 blockId = "["+parser()->context.token->name+"]";
3843 }
3844
3846 thisVariant(),
3847 fileName,
3848 localScope ? parser()->context.context : "",
3849 t,
3850 stripCodeComments,
3853 blockId,isBlock,trimLeft);
3855}
3856
3857void DocPara::handleSection(char cmdChar,const QCString &cmdName)
3858{
3859 AUTO_TRACE("cmdName={}",cmdName);
3860 QCString saveCmdName = cmdName;
3861 // get the argument of the section command.
3862 Token tok=parser()->tokenizer.lex();
3863 if (!tok.is(TokenRetval::TK_WHITESPACE))
3864 {
3865 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3866 cmdChar,saveCmdName);
3867 return;
3868 }
3869 tok=parser()->tokenizer.lex();
3870 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3871 {
3872 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3873 "argument of command '{:c}{}'", cmdChar,saveCmdName);
3874 return;
3875 }
3876 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3877 {
3878 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3879 tok.to_string(),cmdChar,saveCmdName);
3880 return;
3881 }
3884 parser()->tokenizer.lex();
3886}
3887
3888Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
3889{
3890 AUTO_TRACE();
3891 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
3892 Token retval = children().get_last<DocHtmlHeader>()->parse();
3893 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
3894}
3895
3896// For XML tags whose content is stored in attributes rather than
3897// contained within the element, we need a way to inject the attribute
3898// text into the current paragraph.
3899bool DocPara::injectToken(Token tok,const QCString &tokText)
3900{
3901 AUTO_TRACE();
3902 parser()->context.token->name = tokText;
3903 return parser()->defaultHandleToken(thisVariant(),tok,children());
3904}
3905
3907{
3908 AUTO_TRACE();
3909 Token retval = parser()->tokenizer.lex();
3910 QCString lang = parser()->context.token->name;
3911 if (!lang.isEmpty() && lang.at(0)!='.')
3912 {
3913 lang="."+lang;
3914 }
3915 if (parser()->context.xmlComment)
3916 {
3917 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
3918 }
3919 // search for the first non-whitespace line, index is stored in li
3920 size_t i=0,li=0,l=parser()->context.token->verb.length();
3921 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
3922 {
3923 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
3924 i++;
3925 }
3928 stripIndentation(parser()->context.token->verb.mid(li)),
3932 FALSE,lang);
3933 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3934 {
3935 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
3936 }
3938 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3939 return retval;
3940}
3941
3943{
3944 if (parser()->context.memberDef) // inheriting docs from a member
3945 {
3946 const MemberDef *reMd = parser()->context.memberDef->reimplements();
3947 if (reMd) // member from which was inherited.
3948 {
3949 const MemberDef *thisMd = parser()->context.memberDef;
3950 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
3951 parser()->pushContext();
3952 parser()->context.scope=reMd->getOuterScope();
3953 if (parser()->context.scope!=Doxygen::globalScope)
3954 {
3956 }
3957 parser()->context.memberDef=reMd;
3958 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
3959 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
3960 parser()->context.copyStack.push_back(reMd);
3963 parser()->context.copyStack.pop_back();
3964 auto hasParamCommand = parser()->context.hasParamCommand;
3965 auto hasReturnCommand = parser()->context.hasReturnCommand;
3966 auto retvalsFound = parser()->context.retvalsFound;
3967 auto paramsFound = parser()->context.paramsFound;
3968 parser()->popContext();
3969 parser()->context.hasParamCommand = hasParamCommand;
3970 parser()->context.hasReturnCommand = hasReturnCommand;
3971 parser()->context.retvalsFound = retvalsFound;
3972 parser()->context.paramsFound = paramsFound;
3973 parser()->context.memberDef = thisMd;
3974 }
3975 }
3976}
3977
3978
3979Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
3980{
3981 AUTO_TRACE("cmdName={}",cmdName);
3982 Token retval = Token::make_RetVal_OK();
3983 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
3984 switch (cmdId)
3985 {
3987 {
3988 std::string str{cmdChar};
3989 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
3990 if (isAliasCmd(cmdName.view()))
3991 {
3992 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
3993 }
3994 else
3995 {
3996 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
3997 }
3998 }
3999 break;
4002 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4004 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
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 break;
4023 break;
4026 break;
4029 break;
4032 break;
4035 break;
4038 break;
4041 break;
4044 break;
4047 break;
4051 break;
4056 break;
4059 break;
4062 break;
4065 break;
4068 break;
4071 break;
4074 break;
4077 break;
4082 break;
4086 break;
4089 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;
4133 {
4135 retval = children().get_last<DocSimpleList>()->parse();
4136 }
4137 break;
4139 {
4140 handleSection(cmdChar,cmdName);
4141 retval = Token::make_RetVal_Section();
4142 }
4143 break;
4145 {
4146 handleSection(cmdChar,cmdName);
4147 retval = Token::make_RetVal_Subsection();
4148 }
4149 break;
4151 {
4152 handleSection(cmdChar,cmdName);
4153 retval = Token::make_RetVal_Subsubsection();
4154 }
4155 break;
4157 {
4158 handleSection(cmdChar,cmdName);
4159 retval = Token::make_RetVal_Paragraph();
4160 }
4161 break;
4163 {
4164 handleSection(cmdChar,cmdName);
4165 retval = Token::make_RetVal_SubParagraph();
4166 }
4167 break;
4169 {
4170 handleSection(cmdChar,cmdName);
4171 retval = Token::make_RetVal_SubSubParagraph();
4172 }
4173 break;
4175 {
4177 retval = handleStartCode();
4178 }
4179 break;
4181 {
4183 retval = handleStartCode();
4184 }
4185 break;
4187 {
4189 retval = parser()->tokenizer.lex();
4191 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4192 {
4193 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4194 }
4196 }
4197 break;
4199 {
4201 retval = parser()->tokenizer.lex();
4203 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4204 {
4205 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4206 }
4208 }
4209 break;
4211 {
4213 retval = parser()->tokenizer.lex();
4215 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4216 {
4217 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4218 }
4220 }
4221 break;
4223 {
4225 retval = parser()->tokenizer.lex();
4227 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4228 {
4229 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4230 }
4232 }
4233 break;
4235 {
4237 retval = parser()->tokenizer.lex();
4239 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4240 {
4241 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4242 }
4244 }
4245 break;
4247 {
4249 retval = parser()->tokenizer.lex();
4251 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4252 {
4253 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4254 }
4256 }
4257 break;
4259 {
4262 parser()->tokenizer.lex();
4263
4264 QCString fullMatch = parser()->context.token->verb;
4265 int idx = fullMatch.find('{');
4266 int idxEnd = fullMatch.find("}",idx+1);
4267 StringVector optList;
4268 if (idx != -1) // options present
4269 {
4270 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4271 optList = split(optStr.str(),",");
4272 for (const auto &opt : optList)
4273 {
4274 if (opt.empty()) continue;
4275 QCString locOpt(opt);
4276 locOpt = locOpt.stripWhiteSpace().lower();
4277 if (locOpt == "code")
4278 {
4280 }
4281 else if (!locOpt.isEmpty())
4282 {
4283 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4284 }
4285 }
4286 }
4287
4289 retval = parser()->tokenizer.lex();
4291 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4292 {
4293 if (t == DocVerbatim::JavaDocCode)
4294 {
4295 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4296 }
4297 else
4298 {
4299 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4300 }
4301 }
4303 }
4304 break;
4307 {
4308 if (cmdId == CommandType::CMD_VERBATIM)
4309 {
4311 }
4312 else
4313 {
4315 }
4316 retval = parser()->tokenizer.lex();
4318 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4319 {
4320 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4321 }
4323 }
4324 break;
4326 {
4335 QCString width,height;
4336 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4338 retval = parser()->tokenizer.lex();
4339 dv->setText(parser()->context.token->verb);
4340 dv->setWidth(width);
4341 dv->setHeight(height);
4342 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4343 if (!Config_getBool(HAVE_DOT))
4344 {
4345 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4346 children().pop_back();
4347 }
4348 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4349 {
4350 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4351 }
4353 }
4354 break;
4356 {
4365 QCString width,height;
4366 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4368 retval = parser()->tokenizer.lex();
4369 dv->setText(parser()->context.token->verb);
4370 dv->setWidth(width);
4371 dv->setHeight(height);
4372 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4373 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4374 {
4375 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4376 }
4378 }
4379 break;
4381 {
4382 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4384 parser()->tokenizer.lex();
4385 QCString fullMatch = parser()->context.token->sectionId;
4386 QCString sectionId = "";
4387 int idx = fullMatch.find('{');
4388 int idxEnd = fullMatch.find("}",idx+1);
4389 StringVector optList;
4390 QCString engine;
4391 if (idx != -1) // options present
4392 {
4393 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4394 optList = split(optStr.str(),",");
4395 for (const auto &opt : optList)
4396 {
4397 if (opt.empty()) continue;
4398 bool found = false;
4399 QCString locOpt(opt);
4400 locOpt = locOpt.stripWhiteSpace().lower();
4401 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4402 {
4403 if (!engine.isEmpty())
4404 {
4405 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4406 }
4407 engine = locOpt;
4408 found = true;
4409 }
4410 if (!found)
4411 {
4412 if (sectionId.isEmpty())
4413 {
4414 sectionId = opt;
4415 }
4416 else
4417 {
4418 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4419 }
4420 }
4421 }
4422 }
4423 else
4424 {
4425 sectionId = parser()->context.token->sectionId;
4426 }
4427 if (engine.isEmpty()) engine = "uml";
4428
4429 if (sectionId.isEmpty())
4430 {
4432 retval = parser()->tokenizer.lex();
4433 assert(retval.is(TokenRetval::RetVal_OK));
4434
4435 sectionId = parser()->context.token->sectionId;
4436 sectionId = sectionId.stripWhiteSpace();
4437 }
4438
4439 QCString plantFile(sectionId);
4444 FALSE,plantFile);
4446 dv->setEngine(engine);
4448 QCString width,height;
4449 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4451 retval = parser()->tokenizer.lex();
4452 int line = 0;
4453 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4454 if (engine == "ditaa")
4455 {
4456 dv->setUseBitmap(true);
4457 }
4458 else if (engine == "uml")
4459 {
4460 int i = trimmedVerb.find('\n');
4461 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4462 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4463 }
4464 dv->setText(trimmedVerb);
4465 dv->setWidth(width);
4466 dv->setHeight(height);
4467 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4468 if (jarPath.isEmpty())
4469 {
4470 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4471 children().pop_back();
4472 }
4473 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4474 {
4475 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4476 }
4478 }
4479 break;
4481 retval = Token::make_RetVal_EndParBlock();
4482 break;
4498 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4499 break;
4501 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4502 break;
4504 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4505 break;
4507 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4508 break;
4511 break;
4513 retval = handleXRefItem();
4514 break;
4516 {
4518 }
4519 break;
4522 {
4524 }
4525 break;
4527 {
4529 }
4530 break;
4532 {
4536 retval = children().get_last<DocIndexEntry>()->parse();
4537 }
4538 break;
4540 retval = Token::make_RetVal_Internal();
4541 break;
4543 retval = Token::make_RetVal_EndInternal();
4544 break;
4546 {
4548 retval = children().get_last<DocParBlock>()->parse();
4549 }
4550 break;
4551 case CommandType::CMD_COPYDOC: // fall through
4552 case CommandType::CMD_COPYBRIEF: // fall through
4554 //retval = Token::make_RetVal_CopyDoc();
4555 // these commands should already be resolved by processCopyDoc()
4556 break;
4559 break;
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;
4609 if (!Config_getBool(HAVE_DOT))
4610 {
4611 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4612 "ignoring \\dotfile command because HAVE_DOT is not set");
4613 }
4614 else
4615 {
4616 handleFile<DocDotFile>(cmdName);
4617 }
4618 break;
4621 break;
4623 handleFile<DocMscFile>(cmdName);
4624 break;
4626 handleFile<DocDiaFile>(cmdName);
4627 break;
4630 break;
4632 handleLink(cmdName,FALSE);
4633 break;
4635 handleLink(cmdName,TRUE);
4636 break;
4638 handleCite(cmdChar,cmdName);
4639 break;
4641 handleEmoji(cmdChar,cmdName);
4642 break;
4644 handleDoxyConfig(cmdChar,cmdName);
4645 break;
4646 case CommandType::CMD_REF: // fall through
4648 handleRef(cmdChar,cmdName);
4649 break;
4651 {
4654 }
4655 break;
4657 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4658 break;
4660 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4661 break;
4663 {
4665 }
4666 break;
4667 //case CommandType::CMD_LANGSWITCH:
4668 // retval = handleLanguageSwitch();
4669 // break;
4671 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4672 {
4675 }
4676 break;
4679 break;
4681 handleShowDate(cmdChar,cmdName);
4682 break;
4684 handleILine(cmdChar,cmdName);
4685 break;
4687 handleIFile(cmdChar,cmdName);
4688 break;
4690 {
4692 (void)parser()->tokenizer.lex();
4694 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4696 }
4697 break;
4698 default:
4699 // we should not get here!
4700 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4701 break;
4702 }
4703 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4704 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4705 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4706 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4707 TokenRetval::RetVal_EndInternal)
4708 );
4709 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4710 return retval;
4711}
4712
4713static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4714 const char *attrName,
4715 QCString *result)
4716{
4717
4718 for (const auto &opt : tagHtmlAttribs)
4719 {
4720 if (opt.name==attrName)
4721 {
4722 *result = opt.value;
4723 return TRUE;
4724 }
4725 }
4726 return FALSE;
4727}
4728
4729Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4730{
4731 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4732 Token retval = Token::make_RetVal_OK();
4733 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4734 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4737 {
4738 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4739 tagName);
4740 }
4741 switch (tagId)
4742 {
4744 if (!parser()->context.token->emptyTag)
4745 {
4747 tagHtmlAttribs,DocHtmlList::Unordered);
4748 retval=children().get_last<DocHtmlList>()->parse();
4749 }
4750 break;
4752 if (!parser()->context.token->emptyTag)
4753 {
4755 tagHtmlAttribs,DocHtmlList::Ordered);
4756 retval=children().get_last<DocHtmlList>()->parse();
4757 }
4758 break;
4760 if (parser()->context.token->emptyTag) break;
4762 {
4763 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4764 }
4765 else
4766 {
4767 retval = Token::make_RetVal_ListItem();
4768 }
4769 break;
4771 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
4772 break;
4774 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
4775 break;
4777 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
4778 break;
4780 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
4781 break;
4783 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
4784 break;
4786 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
4787 break;
4789 if (parser()->context.token->emptyTag) break;
4790 if (parser()->context.xmlComment)
4791 // for C# source or inside a <summary> or <remark> section we
4792 // treat <code> as an XML tag (so similar to @code)
4793 {
4795 retval = handleStartCode();
4796 }
4797 else // normal HTML markup
4798 {
4799 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4800 }
4801 break;
4803 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
4804 break;
4806 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
4807 break;
4809 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
4810 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
4811 break;
4813 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
4814 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
4815 break;
4817 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
4818 break;
4820 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
4821 break;
4823 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
4824 break;
4826 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
4827 break;
4829 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
4830 break;
4832 if (parser()->context.token->emptyTag) break;
4833 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
4836 break;
4838 retval = Token::make_TK_NEWPARA();
4839 break;
4841 if (!parser()->context.token->emptyTag)
4842 {
4843 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
4844 retval=children().get_last<DocHtmlDescList>()->parse();
4845 }
4846 break;
4848 if (insideDL(thisVariant()))
4849 {
4850 retval = Token::make_RetVal_DescTitle();
4851 }
4852 else
4853 {
4854 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
4855 }
4856 break;
4858 if (insideDL(thisVariant()))
4859 {
4860 retval = Token::make_RetVal_DescData();
4861 }
4862 else
4863 {
4864 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
4865 }
4866 break;
4868 if (!parser()->context.token->emptyTag)
4869 {
4870 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
4871 retval=children().get_last<DocHtmlTable>()->parse();
4872 }
4873 break;
4875 retval = Token::make_RetVal_TableRow();
4876 break;
4878 retval = Token::make_RetVal_TableCell();
4879 break;
4881 retval = Token::make_RetVal_TableHCell();
4882 break;
4886 // for time being ignore </t....> tag
4887 break;
4889 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
4890 break;
4892 {
4893 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
4894 }
4895 break;
4897 {
4898 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
4899 }
4900 break;
4902 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
4903 break;
4905 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
4906 break;
4908 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
4909 break;
4911 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
4912 break;
4914 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
4915 break;
4917 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
4918 break;
4920 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
4921 break;
4923 {
4924 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
4925 }
4926 break;
4928 if (!parser()->context.token->emptyTag)
4929 {
4930 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
4931 retval=children().get_last<DocHtmlDetails>()->parse();
4932 }
4933 break;
4935 if (!parser()->context.token->emptyTag)
4936 {
4937 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
4938 retval = children().get_last<DocHtmlBlockQuote>()->parse();
4939 }
4940 break;
4941
4944 {
4945 if (!parser()->context.token->emptyTag)
4946 {
4948 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
4949 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
4950 if (d)
4951 {
4952 if (!d->summary()) // details section does not have a summary yet
4953 {
4954 d->parseSummary(n,parser()->context.token->attribs);
4955 }
4956 else
4957 {
4958 retval = Token::make_TK_NEWPARA();
4959 }
4960 }
4961 }
4962 }
4963 break;
4967 // fall through
4970 if (!children().empty())
4971 {
4972 retval = Token::make_TK_NEWPARA();
4973 }
4974 break;
4976 if (insideTable(thisVariant()))
4977 {
4978 retval = Token::make_RetVal_TableCell();
4979 }
4980 break;
4981 case HtmlTagType::XML_C:
4982 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4983 break;
4986 {
4988 QCString paramName;
4989 if (findAttribute(tagHtmlAttribs,"name",&paramName))
4990 {
4991 if (paramName.isEmpty())
4992 {
4993 if (Config_getBool(WARN_NO_PARAMDOC))
4994 {
4995 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
4996 }
4997 }
4998 else
4999 {
5000 retval = handleParamSection(paramName,
5002 TRUE);
5003 }
5004 }
5005 else
5006 {
5007 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5008 }
5009 }
5010 break;
5013 {
5014 QCString paramName;
5015 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5016 {
5017 //printf("paramName=%s\n",qPrint(paramName));
5019 children().append<DocWord>(parser(),thisVariant(),paramName);
5021 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5022 }
5023 else
5024 {
5025 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5026 }
5027 }
5028 break;
5030 {
5032 QCString exceptName;
5033 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5034 {
5035 unescapeCRef(exceptName);
5036 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5037 }
5038 else
5039 {
5040 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5041 }
5042 }
5043 break;
5046 if (insideTable(thisVariant()))
5047 {
5048 retval = Token::make_RetVal_TableRow();
5049 }
5050 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5051 {
5052 retval = Token::make_RetVal_ListItem();
5053 }
5054 else
5055 {
5056 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5057 }
5058 break;
5063 break;
5065 if (insideTable(thisVariant()))
5066 {
5067 retval = Token::make_RetVal_TableCell();
5068 }
5069 break;
5071 // I'm not sure if <see> is the same as <seealso> or if it
5072 // should you link a member without producing a section. The
5073 // C# specification is extremely vague about this (but what else
5074 // can we expect from Microsoft...)
5075 {
5076 QCString cref;
5077 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5078 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5079 {
5080 unescapeCRef(cref);
5081 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5082 {
5083 bool inSeeBlock = parser()->context.inSeeBlock;
5084 parser()->context.token->name = cref;
5087 parser()->context.inSeeBlock = inSeeBlock;
5088 }
5089 else // <see cref="...">...</see> style
5090 {
5091 //DocRef *ref = new DocRef(this,cref);
5092 //children().append(ref);
5093 //ref->parse();
5096 DocLink *lnk = children().get_last<DocLink>();
5097 QCString leftOver = lnk->parse(FALSE,TRUE);
5098 if (!leftOver.isEmpty())
5099 {
5100 children().append<DocWord>(parser(),thisVariant(),leftOver);
5101 }
5102 }
5103 }
5104 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5105 {
5106 bool inSeeBlock = parser()->context.inSeeBlock;
5107 parser()->context.token->name = cref;
5112 parser()->context.inSeeBlock = inSeeBlock;
5113 }
5114 else
5115 {
5116 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5117 }
5118 }
5119 break;
5121 {
5123 QCString cref;
5124 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5125 {
5126 unescapeCRef(cref);
5127 // Look for an existing "see" section
5128 DocNodeVariant *vss=nullptr;
5129 for (auto &n : children())
5130 {
5131 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5132 if (candidate && candidate->type()==DocSimpleSect::See)
5133 {
5134 vss = &n;
5135 }
5136 }
5137
5138 if (!vss) // start new section
5139 {
5141 vss = &children().back();
5142 }
5143
5144 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5145 retval = Token::make_RetVal_OK();
5146 }
5147 else
5148 {
5149 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5150 }
5151 }
5152 break;
5154 {
5155 QCString type;
5156 findAttribute(tagHtmlAttribs,"type",&type);
5158 HtmlAttribList emptyList;
5159 if (type=="number")
5160 {
5161 listType=DocHtmlList::Ordered;
5162 }
5163 if (type=="table")
5164 {
5165 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5166 retval=children().get_last<DocHtmlTable>()->parseXml();
5167 }
5168 else
5169 {
5170 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5171 retval=children().get_last<DocHtmlList>()->parseXml();
5172 }
5173 }
5174 break;
5177 // These tags are defined in .Net but are currently unsupported
5179 break;
5181 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5182 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5183 break;
5186 break;
5187 default:
5188 // we should not get here!
5189 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5190 ASSERT(0);
5191 break;
5192 }
5193 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5194 return retval;
5195}
5196
5198{
5199 AUTO_TRACE("tagName={}",tagName);
5200 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5201 Token retval = Token::make_RetVal_OK();
5202 switch (tagId)
5203 {
5205 if (!insideUL(thisVariant()))
5206 {
5207 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5208 }
5209 else
5210 {
5211 retval = Token::make_RetVal_EndList();
5212 }
5213 break;
5215 if (!insideOL(thisVariant()))
5216 {
5217 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5218 }
5219 else
5220 {
5221 retval = Token::make_RetVal_EndList();
5222 }
5223 break;
5225 if (!insideLI(thisVariant()))
5226 {
5227 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5228 }
5229 else
5230 {
5231 // ignore </li> tags
5232 }
5233 break;
5235 if (!insideDetails(thisVariant()))
5236 {
5237 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5238 }
5239 else
5240 {
5241 retval = Token::make_RetVal_EndHtmlDetails();
5242 }
5243 break;
5246 {
5247 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5248 }
5249 else
5250 {
5251 retval = Token::make_RetVal_EndBlockQuote();
5252 }
5253 break;
5256 break;
5259 break;
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;
5306 break;
5308 retval = Token::make_TK_NEWPARA();
5309 break;
5311 retval = Token::make_RetVal_EndDesc();
5312 break;
5314 // ignore </dt> tag
5315 break;
5317 // ignore </dd> tag
5318 break;
5320 retval = Token::make_RetVal_EndTable();
5321 break;
5323 // ignore </tr> tag
5324 break;
5326 // ignore </td> tag
5327 break;
5329 // ignore </th> tag
5330 break;
5334 // for time being ignore </t....> tag
5335 break;
5337 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5338 break;
5340 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5341 break;
5343 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5344 break;
5346 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5347 break;
5349 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5350 break;
5352 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5353 break;
5355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5356 break;
5358 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5359 break;
5361 break;
5363 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5364 break;
5366 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5367 // ignore </a> tag (can be part of <a name=...></a>
5368 break;
5369
5371 break;
5373 retval = Token::make_TK_NEWPARA();
5374 break;
5387 retval = Token::make_RetVal_CloseXml();
5388 break;
5389 case HtmlTagType::XML_C:
5391 break;
5399 // These tags are defined in .Net but are currently unsupported
5400 break;
5402 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5403 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5404 break;
5405 default:
5406 // we should not get here!
5407 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5408 ASSERT(0);
5409 break;
5410 }
5411 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5412 return retval;
5413}
5414
5416{
5417 // expected hierarchy:
5418 // 1. DocAutoListItem <- n
5419 // 2. DocAutoList <- parent(n)
5420 // 3. DocPara <- parent(parent(n))
5421
5422 // step 1
5423 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5424 {
5425 return false;
5426 }
5427
5428 // step 2
5429 n = parent(n);
5430 int indent = 0;
5431 const auto docAutoList = std::get_if<DocAutoList>(n);
5432 if (docAutoList) // capture indent
5433 {
5434 indent = docAutoList->indent();
5435 }
5436 else
5437 {
5438 return false;
5439 }
5440
5441 // step 3
5442 n = parent(n);
5443 const auto docPara = std::get_if<DocPara>(n);
5444 if (docPara)
5445 {
5446 QCString tagNameLower = QCString(parser->context.token->name).lower();
5447 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5448 {
5449 return std::get<DocStyleChange>(*stack.top());
5450 };
5451
5452 if (parser->context.styleStack.empty() || // no style change
5453 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5454 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5455 )
5456 {
5457 // insert an artificial 'end of autolist' marker and parse again
5458 QCString indentStr;
5459 indentStr.fill(' ',indent);
5460 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5461 return true;
5462 }
5463 }
5464 return false;
5465}
5466
5468{
5469 AUTO_TRACE();
5470 auto ns = AutoNodeStack(parser(),thisVariant());
5471 // handle style commands "inherited" from the previous paragraph
5473 Token tok=parser()->tokenizer.lex();
5474 Token retval = Token::make_TK_NONE();
5475 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5476 {
5477reparsetoken:
5478 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5479 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5480 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5481 )
5482 {
5483 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5484 }
5485 switch(tok.value())
5486 {
5487 case TokenRetval::TK_WORD:
5489 break;
5490 case TokenRetval::TK_LNKWORD:
5492 break;
5493 case TokenRetval::TK_URL:
5495 break;
5496 case TokenRetval::TK_WHITESPACE:
5497 {
5498 // prevent leading whitespace and collapse multiple whitespace areas
5499 if (insidePRE(thisVariant()) || // all whitespace is relevant
5500 (
5501 // remove leading whitespace
5502 !children().empty() &&
5503 // and whitespace after certain constructs
5507 )
5508 )
5509 {
5511 }
5512 }
5513 break;
5514 case TokenRetval::TK_LISTITEM:
5515 {
5516 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5517 const DocNodeVariant *n=parent();
5518 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5519 const DocAutoList *al = std::get_if<DocAutoList>(n);
5520 if (al) // we found an auto list up in the hierarchy
5521 {
5522 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5523 if (al->indent()>=parser()->context.token->indent)
5524 // new item at the same or lower indent level
5525 {
5526 retval = Token::make_TK_LISTITEM();
5527 goto endparagraph;
5528 }
5529 }
5530
5531 // determine list depth
5532 int depth = 0;
5533 n=parent();
5534 while (n)
5535 {
5536 al = std::get_if<DocAutoList>(n);
5537 if (al && al->isEnumList()) depth++;
5538 n=::parent(n);
5539 }
5540
5541 // first item or sub list => create new list
5542 do
5543 {
5546 parser()->context.token->isEnumList,depth,
5548 al = children().get_last<DocAutoList>();
5549 retval = children().get_last<DocAutoList>()->parse();
5550 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5551 al->indent()==parser()->context.token->indent // at same indent level
5552 );
5553
5554 // check the return value
5555 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5556 {
5557 // Reparse the token that ended the section at this level,
5558 // so a new simple section will be started at this level.
5559 // This is the same as unputting the last read token and continuing.
5561 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5562 {
5565 tok = Token::make_TK_RCSTAG();
5566 }
5567 else // other section
5568 {
5569 tok = Token::make_TK_COMMAND_BS();
5570 }
5571 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5572 goto reparsetoken;
5573 }
5574 else if (retval.is(TokenRetval::TK_ENDLIST))
5575 {
5576 if (al->indent()>parser()->context.token->indent) // end list
5577 {
5578 goto endparagraph;
5579 }
5580 else // continue with current paragraph
5581 {
5582 }
5583 }
5584 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5585 {
5586 goto endparagraph;
5587 }
5588 }
5589 break;
5590 case TokenRetval::TK_ENDLIST:
5591 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5592 if (std::get_if<DocAutoListItem>(parent()))
5593 {
5594 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5595 if (al && al->indent()>=parser()->context.token->indent)
5596 {
5597 // end of list marker ends this paragraph
5598 retval = Token::make_TK_ENDLIST();
5599 goto endparagraph;
5600 }
5601 else
5602 {
5603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5604 "has invalid indent level");
5605 }
5606 }
5607 else
5608 {
5609 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5610 "list items");
5611 }
5612 break;
5613 case TokenRetval::TK_COMMAND_AT:
5614 // fall through
5615 case TokenRetval::TK_COMMAND_BS:
5616 {
5617 // see if we have to start a simple section
5618 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5619 const DocNodeVariant *n=parent();
5620 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5621 !std::holds_alternative<DocParamSect>(*n))
5622 {
5623 n=::parent(n);
5624 }
5626 {
5627 if (n) // already in a simple section
5628 {
5629 // simple section cannot start in this paragraph, need
5630 // to unwind the stack and remember the command.
5632 retval = Token::make_RetVal_SimpleSec();
5633 goto endparagraph;
5634 }
5635 }
5636 // see if we are in a simple list
5637 n=parent();
5638 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5639 if (n)
5640 {
5641 if (cmd==CommandType::CMD_LI)
5642 {
5643 retval = Token::make_RetVal_ListItem();
5644 goto endparagraph;
5645 }
5646 }
5647
5648 // handle the command
5649 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5650 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5651
5652 // check the return value
5653 if (retval.is(TokenRetval::RetVal_SimpleSec))
5654 {
5655 // Reparse the token that ended the section at this level,
5656 // so a new simple section will be started at this level.
5657 // This is the same as unputting the last read token and continuing.
5659 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5660 {
5663 tok = Token::make_TK_RCSTAG();
5664 }
5665 else // other section
5666 {
5667 tok = Token::make_TK_COMMAND_BS();
5668 }
5669 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5670 goto reparsetoken;
5671 }
5672 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5673 {
5674 // the command ended with a new command, reparse this token
5675 tok = retval;
5676 goto reparsetoken;
5677 }
5678 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5679 // or some auto list marker
5680 {
5681 goto endparagraph;
5682 }
5683 }
5684 break;
5685 case TokenRetval::TK_HTMLTAG:
5686 {
5687 if (!parser()->context.token->endTag) // found a start tag
5688 {
5689 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5690 }
5691 else // found an end tag
5692 {
5694 {
5695 break; // new code has been pushed back to the scanner, need to reparse
5696 }
5697 retval = handleHtmlEndTag(parser()->context.token->name);
5698 }
5699 if (!retval.is(TokenRetval::RetVal_OK))
5700 {
5701 goto endparagraph;
5702 }
5703 }
5704 break;
5705 case TokenRetval::TK_SYMBOL:
5706 {
5707 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5709 {
5711 }
5712 else
5713 {
5715 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5716 parser()->context.token->name);
5717 }
5718 break;
5719 }
5720 case TokenRetval::TK_NEWPARA:
5721 retval = Token::make_TK_NEWPARA();
5722 goto endparagraph;
5723 case TokenRetval::TK_RCSTAG:
5724 {
5725 const DocNodeVariant *n=parent();
5726 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5727 !std::holds_alternative<DocParamSect>(*n))
5728 {
5729 n=::parent(n);
5730 }
5731 if (n) // already in a simple section
5732 {
5733 // simple section cannot start in this paragraph, need
5734 // to unwind the stack and remember the command.
5737 retval = Token::make_RetVal_SimpleSec();
5738 goto endparagraph;
5739 }
5740
5741 // see if we are in a simple list
5743 children().get_last<DocSimpleSect>()->parseRcs();
5744 }
5745 break;
5746 default:
5747 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5748 "Found unexpected token (id={})",tok.to_string());
5749 break;
5750 }
5751 tok=parser()->tokenizer.lex();
5752 }
5753 retval=Token::make_TK_NONE();
5754endparagraph:
5756 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5757 if (!parser()->context.token->endTag && par &&
5758 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5759 {
5760 par->setAttribs(parser()->context.token->attribs);
5761 }
5762 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
5763 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
5764 );
5765
5766 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5767 return retval;
5768}
5769
5770//--------------------------------------------------------------------------
5771
5773{
5774 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
5775 Token retval = Token::make_RetVal_OK();
5776 auto ns = AutoNodeStack(parser(),thisVariant());
5777
5778 if (!m_id.isEmpty())
5779 {
5781 if (sec)
5782 {
5783 m_file = sec->fileName();
5784 m_anchor = sec->label();
5785 QCString titleStr = sec->title();
5786 if (titleStr.isEmpty()) titleStr = sec->label();
5788 DocTitle *title = &std::get<DocTitle>(*m_title);
5789 title->parseFromString(thisVariant(),titleStr);
5790 }
5791 }
5792
5793 // first parse any number of paragraphs
5794 bool isFirst=TRUE;
5795 DocPara *lastPar=nullptr;
5796 do
5797 {
5799 DocPara *par = children().get_last<DocPara>();
5800 if (isFirst) { par->markFirst(); isFirst=FALSE; }
5801 retval=par->parse();
5802 if (!par->isEmpty())
5803 {
5804 if (lastPar) lastPar->markLast(FALSE);
5805 lastPar = par;
5806 }
5807 else
5808 {
5809 children().pop_back();
5810 }
5811 if (retval.is(TokenRetval::TK_LISTITEM))
5812 {
5813 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
5814 }
5815 if (retval.is(TokenRetval::RetVal_Internal))
5816 {
5818 retval = children().get_last<DocInternal>()->parse(m_level+1);
5819 if (retval.is(TokenRetval::RetVal_EndInternal))
5820 {
5821 retval = Token::make_RetVal_OK();
5822 }
5823 }
5824 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
5825 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
5826 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
5827 );
5828
5829 if (lastPar) lastPar->markLast();
5830
5831 while (true)
5832 {
5833 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
5834 {
5835 // then parse any number of nested sections
5836 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
5837 {
5839 2,
5841 retval = children().get_last<DocSection>()->parse();
5842 }
5843 break;
5844 }
5845 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
5846 {
5847 if ((m_level <= 1) &&
5848 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5849 {
5850 warn_doc_error(parser()->context.fileName,
5851 parser()->tokenizer.getLineNr(),
5852 "Unexpected subsubsection command found inside {}!",
5854 }
5855 // then parse any number of nested sections
5856 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
5857 {
5859 3,
5861 retval = children().get_last<DocSection>()->parse();
5862 }
5863 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
5864 }
5865 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
5866 {
5867 if ((m_level <= 2) &&
5868 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5869 {
5870 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5871 "Unexpected paragraph command found inside {}!",
5873 }
5874 // then parse any number of nested sections
5875 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
5876 {
5878 4,
5880 retval = children().get_last<DocSection>()->parse();
5881 }
5882 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
5883 }
5884 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
5885 {
5886 if ((m_level <= 3) &&
5887 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5888 {
5889 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5890 "Unexpected subparagraph command found inside {}!",
5892 }
5893 // then parse any number of nested sections
5894 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
5895 {
5897 5,
5899 retval = children().get_last<DocSection>()->parse();
5900 }
5901 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
5902 }
5903 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
5904 {
5905 if ((m_level <= 4) &&
5906 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5907 {
5908 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5909 "Unexpected subsubparagraph command found inside {}!",
5911 }
5912 // then parse any number of nested sections
5913 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
5914 {
5916 6,
5918 retval = children().get_last<DocSection>()->parse();
5919 }
5920 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
5921 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
5922 }
5923 else
5924 {
5925 break;
5926 }
5927 }
5928
5929 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
5930 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
5931 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
5932 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
5933 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
5934 );
5935
5936 AUTO_TRACE_EXIT("retval={}", retval.to_string());
5937 return retval;
5938}
5939
5940//--------------------------------------------------------------------------
5941
5943{
5944 AUTO_TRACE();
5945 auto ns = AutoNodeStack(parser(),thisVariant());
5947
5948 Token tok = parser()->tokenizer.lex();
5949 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5950 {
5951 switch(tok.value())
5952 {
5953 case TokenRetval::TK_WORD:
5955 break;
5956 case TokenRetval::TK_WHITESPACE:
5958 break;
5959 case TokenRetval::TK_SYMBOL:
5960 {
5961 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5963 {
5965 }
5966 else
5967 {
5968 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5969 parser()->context.token->name);
5970 }
5971 }
5972 break;
5973 case TokenRetval::TK_COMMAND_AT:
5974 // fall through
5975 case TokenRetval::TK_COMMAND_BS:
5976 switch (Mappers::cmdMapper->map(parser()->context.token->name))
5977 {
5980 break;
5983 break;
5986 break;
5989 break;
5992 break;
5995 break;
5998 break;
6001 break;
6004 break;
6008 break;
6013 break;
6016 break;
6019 break;
6022 break;
6025 break;
6028 break;
6031 break;
6034 break;
6035 default:
6036 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6037 parser()->context.token->name);
6038 break;
6039 }
6040 break;
6041 default:
6042 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6043 tok.to_string());
6044 break;
6045 }
6046 tok = parser()->tokenizer.lex();
6047 }
6048
6050
6051}
6052
6053
6054//--------------------------------------------------------------------------
6055
6057{
6058 AUTO_TRACE();
6059 auto ns = AutoNodeStack(parser(),thisVariant());
6061 Token retval = Token::make_TK_NONE();
6062
6063 // first parse any number of paragraphs
6064 bool isFirst=TRUE;
6065 DocPara *lastPar = nullptr;
6066 do
6067 {
6068 {
6070 DocPara *par = children().get_last<DocPara>();
6071 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6072 retval=par->parse();
6073 if (par->isEmpty() && par->attribs().empty())
6074 {
6075 children().pop_back();
6076 }
6077 else
6078 {
6079 lastPar = par;
6080 }
6081 }
6082 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6083 if (retval == t)
6084 {
6085 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6086 {
6087 warn_doc_error(parser()->context.fileName,
6088 parser()->tokenizer.getLineNr(),
6089 "found {} command (id: '{}') outside of {} context!",
6090 sectionType,parser()->context.token->sectionId,parentSectionType);
6091 }
6092 while (retval==t)
6093 {
6094 if (!parser()->context.token->sectionId.isEmpty())
6095 {
6096 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6097 if (sec)
6098 {
6100 level,
6102 retval = children().get_last<DocSection>()->parse();
6103 }
6104 else
6105 {
6106 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6107 sectionType,parser()->context.token->sectionId,sectionType);
6108 retval = Token::make_TK_NONE();
6109 }
6110 }
6111 else
6112 {
6113 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6114 retval = Token::make_TK_NONE();
6115 }
6116 }
6117 }
6118 };
6119 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6120 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6121 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6122 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6123 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6124
6125 if (retval.is(TokenRetval::TK_LISTITEM))
6126 {
6127 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6128 }
6129 if (retval.is(TokenRetval::RetVal_Internal))
6130 {
6132 retval = children().get_last<DocInternal>()->parse(1);
6133 }
6134 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6135 if (lastPar) lastPar->markLast();
6136
6137 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6138 // then parse any number of level1 sections
6139 while (retval.is(TokenRetval::RetVal_Section))
6140 {
6141 if (!parser()->context.token->sectionId.isEmpty())
6142 {
6143 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6144 if (sec)
6145 {
6147 1,
6149 retval = children().get_last<DocSection>()->parse();
6150 }
6151 else
6152 {
6153 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6154 retval = Token::make_TK_NONE();
6155 }
6156 }
6157 else
6158 {
6159 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6160 retval = Token::make_TK_NONE();
6161 }
6162 }
6163
6165}
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:208
QCString m_anchor
Definition docnode.h:237
QCString m_file
Definition docnode.h:238
Node representing an auto List.
Definition docnode.h:566
int m_depth
Definition docnode.h:585
bool isCheckedList() const
Definition docnode.h:577
bool isEnumList() const
Definition docnode.h:575
int depth() const
Definition docnode.h:578
int m_indent
Definition docnode.h:582
Token parse()
Definition docnode.cpp:2820
bool m_isCheckedList
Definition docnode.h:584
int indent() const
Definition docnode.h:576
DocAutoList(DocParser *parser, DocNodeVariant *parent, int indent, bool isEnumList, int depth, bool isCheckedList)
Definition docnode.cpp:2813
bool m_isEnumList
Definition docnode.h:583
Node representing an item of a auto list.
Definition docnode.h:590
DocAutoListItem(DocParser *parser, DocNodeVariant *parent, int indent, int num)
Definition docnode.cpp:2773
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:894
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:1145
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1138
QCString srcFile() const
Definition docnode.h:685
std::unique_ptr< Private > p
Definition docnode.h:702
int srcLine() const
Definition docnode.h:686
DocDiagramFileBase(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.h:675
QCString context() const
Definition docnode.h:684
QCString name() const
Definition docnode.h:678
bool parse()
Definition docnode.cpp:1067
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1060
Node representing an emoji.
Definition docnode.h:336
DocEmoji(DocParser *parser, DocNodeVariant *parent, const QCString &symName)
Definition docnode.cpp:159
int m_index
Definition docnode.h:344
QCString m_symName
Definition docnode.h:343
Node representing an item of a cross-referenced list.
Definition docnode.h:524
QCString m_relPath
Definition docnode.h:541
QCString m_text
Definition docnode.h:540
int id() const
Definition docnode.h:530
QCString m_name
Definition docnode.h:539
DocFormula(DocParser *parser, DocNodeVariant *parent, int id)
Definition docnode.cpp:514
QCString relPath() const
Definition docnode.h:529
Token parse()
Definition docnode.cpp:1459
Node representing a horizontal ruler.
Definition docnode.h:215
Node representing an HTML blockquote.
Definition docnode.h:1285
HtmlAttribList m_attribs
Definition docnode.h:1232
bool m_hasCaptionId
Definition docnode.h:1233
DocHtmlCaption(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs)
Definition docnode.cpp:1666
QCString m_file
Definition docnode.h:1234
const HtmlAttribList & attribs() const
Definition docnode.h:1225
QCString m_anchor
Definition docnode.h:1235
Node representing a HTML table cell.
Definition docnode.h:1187
Valignment valignment() const
Definition docnode.cpp:1870
void setColumnIndex(uint32_t idx)
Definition docnode.h:1211
bool isFirst() const
Definition docnode.h:1195
Token parseXml()
Definition docnode.cpp:1774
void setRowIndex(uint32_t idx)
Definition docnode.h:1210
void markLast(bool v=TRUE)
Definition docnode.h:1198
uint32_t rowSpan() const
Definition docnode.cpp:1808
void markFirst(bool v=TRUE)
Definition docnode.h:1197
Alignment alignment() const
Definition docnode.cpp:1832
bool isHeading() const
Definition docnode.h:1194
const HtmlAttribList & attribs() const
Definition docnode.h:1199
Token parse()
Definition docnode.cpp:1740
uint32_t colSpan() const
Definition docnode.cpp:1820
Node representing a HTML description data.
Definition docnode.h:1175
HtmlAttribList m_attribs
Definition docnode.h:1182
Node representing a Html description list.
Definition docnode.h:895
Node representing a Html description item.
Definition docnode.h:882
Node Html details.
Definition docnode.h:851
const HtmlAttribList & attribs() const
Definition docnode.h:855
void parseSummary(DocNodeVariant *, HtmlAttribList &attribs)
Definition docnode.cpp:1449
const DocNodeVariant * summary() const
Definition docnode.h:858
std::unique_ptr< DocNodeVariant > m_summary
Definition docnode.h:862
Node Html heading.
Definition docnode.h:867
Token parse()
Definition docnode.cpp:1274
Node representing a Html list.
Definition docnode.h:994
Type m_type
Definition docnode.h:1005
Token parseXml()
Definition docnode.cpp:2620
Token parse()
Definition docnode.cpp:2545
Node representing a HTML list item.
Definition docnode.h:1159
Node representing a HTML table row.
Definition docnode.h:1240
Token parseXml(bool header)
Definition docnode.cpp:1972
void setVisibleCells(uint32_t n)
Definition docnode.h:1250
bool isHeading() const
Definition docnode.cpp:1892
void setRowIndex(uint32_t idx)
Definition docnode.h:1255
Token parse()
Definition docnode.cpp:1907
Node Html summary.
Definition docnode.h:838
Node representing a HTML table.
Definition docnode.h:1263
Token parseXml()
Definition docnode.cpp:2130
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1278
Token parse()
Definition docnode.cpp:2052
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2187
size_t m_numCols
Definition docnode.h:1280
const DocNodeVariant * caption() const
Definition docnode.cpp:2038
bool hasCaption() const
Definition docnode.cpp:2033
const DocNodeVariant * firstRow() const
Definition docnode.cpp:2043
const HtmlAttribList & attribs() const
Definition docnode.h:650
QCString relPath() const
Definition docnode.h:646
QCString name() const
Definition docnode.h:642
QCString url() const
Definition docnode.h:647
DocImage(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs, const QCString &name, Type t, const QCString &url=QCString(), bool inlineImage=TRUE)
Definition docnode.cpp:1251
std::unique_ptr< Private > p
Definition docnode.h:669
void parse()
Definition docnode.cpp:1266
bool isSVG() const
Definition docnode.cpp:1257
Node representing a include/dontinclude operator block.
Definition docnode.h:472
bool m_stripCodeComments
Definition docnode.h:516
const char * typeAsString() const
Definition docnode.h:481
QCString m_includeFileName
Definition docnode.h:519
QCString context() const
Definition docnode.h:496
Type type() const
Definition docnode.h:480
QCString m_pattern
Definition docnode.h:512
void markLast(bool v=TRUE)
Definition docnode.h:500
QCString m_text
Definition docnode.h:511
bool m_showLineNo
Definition docnode.h:510
Node representing an included text block from file.
Definition docnode.h:430
void parse()
Definition docnode.cpp:267
QCString m_text
Definition docnode.h:460
Type m_type
Definition docnode.h:461
@ LatexInclude
Definition docnode.h:432
@ SnippetWithLines
Definition docnode.h:433
@ DontIncWithLines
Definition docnode.h:434
@ IncWithLines
Definition docnode.h:433
@ HtmlInclude
Definition docnode.h:432
@ VerbInclude
Definition docnode.h:432
@ DontInclude
Definition docnode.h:432
@ DocbookInclude
Definition docnode.h:434
QCString m_blockId
Definition docnode.h:467
bool m_stripCodeComments
Definition docnode.h:462
QCString context() const
Definition docnode.h:448
QCString m_file
Definition docnode.h:458
Node representing an entry in the index.
Definition docnode.h:547
QCString m_entry
Definition docnode.h:557
Token parse()
Definition docnode.cpp:1569
Node representing an internal section of documentation.
Definition docnode.h:963
Token parse(int)
Definition docnode.cpp:1509
QCString m_file
Definition docnode.h:810
QCString m_anchor
Definition docnode.h:812
DocInternalRef(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:669
QCString relPath() const
Definition docnode.h:806
QCString m_relPath
Definition docnode.h:811
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:191
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:1098
bool parse()
Definition docnode.cpp:1105
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:973
Token parse()
Definition docnode.cpp:2714
Node representing a paragraph in the documentation tree.
Definition docnode.h:1074
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3242
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3684
void handleInheritDoc()
Definition docnode.cpp:3942
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3295
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3236
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3752
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3979
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3358
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3857
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3645
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3561
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3272
void markLast(bool v=TRUE)
Definition docnode.h:1080
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4729
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3327
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3585
bool isFirst() const
Definition docnode.h:1081
void markFirst(bool v=TRUE)
Definition docnode.h:1079
void handleRef(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3725
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3547
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1109
bool m_isFirst
Definition docnode.h:1112
Token parse()
Definition docnode.cpp:5467
void handleVhdlFlow()
Definition docnode.cpp:3677
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:3888
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3477
bool m_isLast
Definition docnode.h:1113
Token handleXRefItem()
Definition docnode.cpp:3456
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5197
Token handleStartCode()
Definition docnode.cpp:3906
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:3899
DocNodeList m_paramTypes
Definition docnode.h:1138
DocNodeList m_paragraphs
Definition docnode.h:1136
void markFirst(bool b=TRUE)
Definition docnode.h:1128
Token parseXml(const QCString &paramName)
Definition docnode.cpp:3125
void markLast(bool b=TRUE)
Definition docnode.h:1129
Token parse(const QCString &cmdName)
Definition docnode.cpp:3046
DocParamSect::Type m_type
Definition docnode.h:1139
DocNodeList m_params
Definition docnode.h:1137
Node representing a parameter section.
Definition docnode.h:1047
friend class DocParamList
Definition docnode.h:1048
Token parse(const QCString &cmdName, bool xmlContext, Direction d)
Definition docnode.cpp:3193
bool m_hasInOutSpecifier
Definition docnode.h:1068
Type type() const
Definition docnode.h:1062
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:73
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:59
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:1177
Node representing a reference to some item.
Definition docnode.h:772
QCString anchor() const
Definition docnode.h:779
QCString m_file
Definition docnode.h:792
SectionType m_sectionType
Definition docnode.h:790
QCString m_text
Definition docnode.h:796
void parse()
Definition docnode.cpp:848
QCString m_ref
Definition docnode.h:794
QCString m_relPath
Definition docnode.h:793
DocRef(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context)
Definition docnode.cpp:704
RefType m_refType
Definition docnode.h:789
QCString m_anchor
Definition docnode.h:795
bool m_isSubPage
Definition docnode.h:791
void parse()
Definition docnode.cpp:6056
Node representing a reference to a section.
Definition docnode.h:929
QCString m_file
Definition docnode.h:945
QCString m_target
Definition docnode.h:942
QCString relPath() const
Definition docnode.h:935
bool m_isSubPage
Definition docnode.h:944
QCString m_anchor
Definition docnode.h:948
QCString target() const
Definition docnode.h:932
QCString m_ref
Definition docnode.h:947
DocSecRefItem(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:533
QCString m_relPath
Definition docnode.h:946
RefType m_refType
Definition docnode.h:943
Node representing a list of section references.
Definition docnode.h:953
Node representing a normal section.
Definition docnode.h:908
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:922
QCString m_id
Definition docnode.h:921
QCString m_file
Definition docnode.h:924
Token parse()
Definition docnode.cpp:5772
DocSection(DocParser *parser, DocNodeVariant *parent, int level, const QCString &id)
Definition docnode.h:910
const DocNodeVariant * title() const
Definition docnode.h:913
QCString m_anchor
Definition docnode.h:923
int m_level
Definition docnode.h:920
Node representing a simple list.
Definition docnode.h:984
Token parse()
Definition docnode.cpp:2758
Node representing a simple list item.
Definition docnode.h:1147
std::unique_ptr< DocNodeVariant > m_paragraph
Definition docnode.h:1154
DocSimpleListItem(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:2739
Node representing a simple section.
Definition docnode.h:1011
QCString typeString() const
Definition docnode.cpp:3017
Type type() const
Definition docnode.h:1020
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:2907
Token parseRcs()
Definition docnode.cpp:2944
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:2897
const DocNodeVariant * title() const
Definition docnode.h:1027
Token parseXml()
Definition docnode.cpp:2961
void appendLinkWord(const QCString &word)
Definition docnode.cpp:2997
bool hasTitle() const
Definition docnode.cpp:2902
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:1031
Node representing a separator between two simple sections of the same type.
Definition docnode.h:1038
Node representing a style change.
Definition docnode.h:264
const char * styleString() const
Definition docnode.cpp:125
Style m_style
Definition docnode.h:313
Node representing a special symbol.
Definition docnode.h:323
static HtmlEntityMapper::SymType decodeSymbol(const QCString &symName)
Definition docnode.cpp:152
void parse()
Definition docnode.cpp:5942
Node representing a simple section title.
Definition docnode.h:603
void parse()
Definition docnode.cpp:2866
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:2884
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:371
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:257
std::unique_ptr< Private > p
Definition docnode.h:424
bool isBlock() const
Definition docnode.h:384
bool isExample() const
Definition docnode.h:380
QCString context() const
Definition docnode.h:379
QCString text() const
Definition docnode.h:378
QCString exampleFile() const
Definition docnode.h:381
QCString relPath() const
Definition docnode.h:382
void setEngine(const QCString &e)
Definition docnode.h:397
@ JavaDocLiteral
Definition docnode.h:373
Node representing a VHDL flow chart.
Definition docnode.h:743
DocVhdlFlow(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:1221
void parse()
Definition docnode.cpp:1225
Node representing some amount of white space.
Definition docnode.h:349
Node representing a word.
Definition docnode.h:152
DocWord(DocParser *parser, DocNodeVariant *parent, const QCString &word)
Definition docnode.cpp:179
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:615
QCString m_anchor
Definition docnode.h:629
DocXRefItem(DocParser *parser, DocNodeVariant *parent, int id, const QCString &key)
Definition docnode.cpp:472
QCString key() const
Definition docnode.h:622
QCString relPath() const
Definition docnode.h:621
QCString m_file
Definition docnode.h:628
QCString m_key
Definition docnode.h:627
QCString m_title
Definition docnode.h:630
bool parse()
Definition docnode.cpp:477
QCString m_relPath
Definition docnode.h:631
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
Iterator class to iterator 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:816
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4713
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2181
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:118
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5415
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:1360
DocNodeList * call_method_children(DocNodeVariant *v)
Definition docnode.h:1379
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:1324
std::unique_ptr< DocNodeVariant > createDocNode(Args &&...args)
Definition docnode.h:1485
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:1894
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:2176
uint32_t column
Definition docnode.cpp:2177
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2175
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:807
void append(Args &&... args)
Append a new DocNodeVariant to the list by constructing it with type T and parameters Args.
Definition docnode.h:1393
T * get_last()
Returns a pointer to the last element in the list if that element exists and holds a T,...
Definition docnode.h:1404
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
@ Markdown
Definition types.h:57
QCString linkToText(SrcLangExt lang, const QCString &link, bool isFileName)
Definition util.cpp:3159
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5645
std::string_view word
Definition util.cpp:980
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3474
bool found
Definition util.cpp:984
QCString stripScope(const QCString &name)
Definition util.cpp:4219
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, SrcLangExt lang, const QCString &prefix)
Definition util.cpp:3185
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3944
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:7042
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5464
QCString stripIndentation(const QCString &s)
Definition util.cpp:6378
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:3348
A bunch of utility functions.