Doxygen
Loading...
Searching...
No Matches
docnode.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2022 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include "docnode.h"
17#include "docparser_p.h"
18#include "htmlentity.h"
19#include "configimpl.h"
20#include "configoptions.h"
21#include "emoji.h"
22#include "message.h"
23#include "doxygen.h"
24#include "cite.h"
25#include "util.h"
26#include "formula.h"
27#include "markdown.h"
28#include "pagedef.h"
29#include "namespacedef.h"
30#include "groupdef.h"
31#include "cmdmapper.h"
32#include "config.h"
33#include "vhdldocgen.h"
34#include "doctokenizer.h"
35#include "plantuml.h"
36#include "language.h"
37#include "datetime.h"
38#include "trace.h"
39#include "anchor.h"
40#include "aliases.h"
41
42#if !ENABLE_DOCPARSER_TRACING
43#undef AUTO_TRACE
44#undef AUTO_TRACE_ADD
45#undef AUTO_TRACE_EXIT
46#define AUTO_TRACE(...) (void)0
47#define AUTO_TRACE_ADD(...) (void)0
48#define AUTO_TRACE_EXIT(...) (void)0
49#endif
50
51#define INTERNAL_ASSERT(x) do {} while(0)
52//#define INTERNAL_ASSERT(x) if (!(x)) TRACE("INTERNAL_ASSERT({}) failed retval={:#x}: file={} line={}",#x,retval,__FILE__,__LINE__)
53
54//---------------------------------------------------------------------------
55
56static const char *g_sectionLevelToName[] =
57{
58 "page",
59 "section",
60 "subsection",
61 "subsubsection",
62 "paragraph",
63 "subparagraph"
64};
65
66
67//---------------------------------------------------------------------------
68
70 "uml", "bpm", "wire", "dot", "ditaa",
71 "salt", "math", "latex", "gantt", "mindmap",
72 "wbs", "yaml", "creole", "json", "flow",
73 "board", "git", "hcl", "regex", "ebnf",
74 "files", "chen", "chronology"
75};
76
77//---------------------------------------------------------------------------
78
79// replaces { with < and } with > and also
80// replaces &gt; with < and &gt; with > within string s
81static void unescapeCRef(QCString &s)
82{
83 QCString result;
84 const char *p = s.data();
85 if (p)
86 {
87 char c = 0;
88 while ((c=*p++))
89 {
90 if (c=='{') c='<'; else if (c=='}') c='>';
91 result+=c;
92 }
93 }
94
95 result=substitute(result,"&lt;","<");
96 result=substitute(result,"&gt;",">");
97 s = result;
98}
99
100//---------------------------------------------------------------------------
101
102/*! Strips known html and tex extensions from \a text. */
104{
105 QCString result=text;
106 if (result.endsWith(".tex"))
107 {
108 result=result.left(result.length()-4);
109 }
110 else if (result.right(Doxygen::htmlFileExtension.length())==
112 {
113 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
114 }
115 return result;
116}
117
118static void setParent(DocNodeVariant *n,DocNodeVariant *newParent)
119{
120 std::visit([&](auto &&x)->decltype(auto) { return x.setParent(newParent); }, *n);
121}
122
123//----------- DocStyleChange
124
126{
127 switch (m_style)
128 {
129 case DocStyleChange::Bold: return "b";
130 case DocStyleChange::Italic: return "em";
131 case DocStyleChange::Code: return "code";
132 case DocStyleChange::Center: return "center";
133 case DocStyleChange::Small: return "small";
134 case DocStyleChange::Cite: return "cite";
135 case DocStyleChange::Subscript: return "subscript";
136 case DocStyleChange::Superscript: return "superscript";
137 case DocStyleChange::Preformatted: return "pre";
138 case DocStyleChange::Div: return "div";
139 case DocStyleChange::Span: return "span";
140 case DocStyleChange::Strike: return "strike";
141 case DocStyleChange::S: return "s";
142 case DocStyleChange::Del: return "del";
143 case DocStyleChange::Underline: return "u";
144 case DocStyleChange::Ins: return "ins";
145 case DocStyleChange::Kbd: return "kbd";
146 case DocStyleChange::Typewriter: return "tt";
147 }
148 return "<invalid>";
149}
150
151//----------- DocSymbol
152
157
158//----------- DocEmoji
159
161 DocNode(parser,parent), m_symName(symName), m_index(-1)
162{
163 QCString locSymName = symName;
164 size_t len=locSymName.length();
165 if (len>0)
166 {
167 if (locSymName.at(len-1)!=':') locSymName.append(":");
168 if (locSymName.at(0)!=':') locSymName.prepend(":");
169 }
170 m_symName = locSymName;
172 if (m_index==-1)
173 {
174 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Found unsupported emoji symbol '{}'",m_symName);
175 }
176}
177
178//---------------------------------------------------------------------------
179
182{
183 //printf("new word %s url=%s\n",qPrint(word),qPrint(parser->context.searchUrl));
184 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
185 {
186 Doxygen::searchIndex.addWord(word,false);
187 }
188}
189
190//---------------------------------------------------------------------------
191
193 const QCString &ref,const QCString &file,
194 const QCString &anchor,const QCString &tooltip) :
198{
199 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
200 // qPrint(word),qPrint(parser->context.searchUrl),qPrint(tooltip));
201 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
202 {
203 Doxygen::searchIndex.addWord(word,false);
204 }
205}
206
207//---------------------------------------------------------------------------
208
210{
211 if (id.isEmpty())
212 {
213 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Empty anchor label");
214 return;
215 }
216
218 QCString anchorPrefix = ct.anchorPrefix();
219 if (id.left(anchorPrefix.length()) == anchorPrefix)
220 {
221 const CiteInfo *cite = ct.find(id.mid(anchorPrefix.length()));
222 if (cite)
223 {
225 m_anchor = id;
226 }
227 else
228 {
229 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid cite anchor id '{}'",id);
230 m_anchor = "invalid";
231 m_file = "invalid";
232 }
233 }
234 else if (newAnchor) // found <a name="label">
235 {
236 m_anchor = id;
237 }
238 else // found \anchor label
239 {
240 const SectionInfo *sec = SectionManager::instance().find(id);
241 if (sec)
242 {
243 //printf("Found anchor %s\n",qPrint(id));
244 m_file = sec->fileName();
245 m_anchor = sec->label();
246 }
247 else
248 {
249 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid anchor id '{}'",id);
250 m_anchor = "invalid";
251 m_file = "invalid";
252 }
253 }
254}
255
256//---------------------------------------------------------------------------
257
264
265
266//---------------------------------------------------------------------------
267
269{
270 AUTO_TRACE("file={} text={}",m_file,Trace::trunc(m_text));
271 switch(m_type)
272 {
273 case DontIncWithLines:
274 // fall through
275 case IncWithLines:
276 // fall through
277 case Include:
278 // fall through
279 case DontInclude:
288 //printf("parser->context.includeFile=<<%s>>\n",qPrint(parser->context.includeFileText));
289 break;
290 case VerbInclude:
291 // fall through
292 case HtmlInclude:
293 case LatexInclude:
299 break;
300 case Snippet:
301 case SnippetWithLines:
303 // check here for the existence of the blockId inside the file, so we
304 // only generate the warning once.
305 int count = 0;
306 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
307 {
308 warn_doc_error(parser()->context.fileName,
309 parser()->tokenizer.getLineNr(),
310 "block marked with {} for \\snippet should appear twice in file {}, found it {:d} times",
311 m_blockId,m_file,count);
312 }
313 break;
314 }
315}
316
317//---------------------------------------------------------------------------
318
320{
321 if (parser()->context.includeFileName.isEmpty())
322 {
323 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
324 "No previous '\\include' or '\\dontinclude' command for '\\{}' present",
325 typeAsString());
326 }
327 bool found = false;
328
330 const char *p = parser()->context.includeFileText.data();
331 size_t l = parser()->context.includeFileLength;
332 size_t o = parser()->context.includeFileOffset;
333 int il = parser()->context.includeFileLine;
334 AUTO_TRACE("text={} off={} len={}",Trace::trunc(p),o,l);
335 size_t so = o, bo = 0;
336 bool nonEmpty = FALSE;
337 switch(type())
338 {
339 case Line:
340 while (o<l)
341 {
342 char c = p[o];
343 if (c=='\n')
344 {
346 if (nonEmpty) break; // we have a pattern to match
347 so=o+1; // no pattern, skip empty line
348 }
349 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
350 {
351 nonEmpty=TRUE;
352 }
353 o++;
354 }
355 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
356 {
357 m_line = il;
359 found = true;
360 AUTO_TRACE_ADD("\\line {}",Trace::trunc(m_text));
361 }
362 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
365 break;
366 case SkipLine:
367 while (o<l)
368 {
369 so=o;
370 while (o<l)
371 {
372 char c = p[o];
373 if (c=='\n')
374 {
376 if (nonEmpty) break; // we have a pattern to match
377 so=o+1; // no pattern, skip empty line
378 }
379 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
380 {
381 nonEmpty=TRUE;
382 }
383 o++;
384 }
385 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
386 {
387 m_line = il;
389 found = true;
390 AUTO_TRACE_ADD("\\skipline {}",Trace::trunc(m_text));
391 break;
392 }
393 o++; // skip new line
394 }
395 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
398 break;
399 case Skip:
400 while (o<l)
401 {
402 so=o;
403 while (o<l)
404 {
405 char c = p[o];
406 if (c=='\n')
407 {
409 if (nonEmpty) break; // we have a pattern to match
410 so=o+1; // no pattern, skip empty line
411 }
412 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
413 {
414 nonEmpty=TRUE;
415 }
416 o++;
417 }
418 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
419 {
420 found = true;
421 break;
422 }
423 o++; // skip new line
424 }
425 parser()->context.includeFileOffset = so; // set pointer to start of new line
428 break;
429 case Until:
430 bo=o;
431 while (o<l)
432 {
433 so=o;
434 while (o<l)
435 {
436 char c = p[o];
437 if (c=='\n')
438 {
440 if (nonEmpty) break; // we have a pattern to match
441 so=o+1; // no pattern, skip empty line
442 }
443 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
444 {
445 nonEmpty=TRUE;
446 }
447 o++;
448 }
449 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
450 {
451 m_line = il;
453 found = true;
454 AUTO_TRACE_ADD("\\until {}",Trace::trunc(m_text));
455 break;
456 }
457 o++; // skip new line
458 }
459 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
462 break;
463 }
464 if (!found)
465 {
466 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
467 "referenced pattern '{}' for command '\\{}' not found",m_pattern,typeAsString());
468 }
469}
470
471//---------------------------------------------------------------------------
472
477
479{
481 if (refList && refList->isEnabled())
482 {
483 RefItem *item = refList->find(m_id);
484 ASSERT(item!=nullptr);
485 if (item)
486 {
487 if (parser()->context.memberDef && parser()->context.memberDef->name().at(0)=='@')
488 {
489 m_file = "@"; // can't cross reference anonymous enum
490 m_anchor = "@";
491 }
492 else
493 {
494 m_file = refList->fileName();
495 m_anchor = item->anchor();
496 }
497 m_title = refList->sectionTitle();
498 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
499 // qPrint(m_file),qPrint(m_anchor),qPrint(m_title));
500
501 if (!item->text().isEmpty())
502 {
503 parser()->pushContext();
505 parser()->popContext();
506 }
507 }
508 return TRUE;
509 }
510 return FALSE;
511}
512
513//---------------------------------------------------------------------------
514
516 m_relPath(parser->context.relPath)
517{
518 const Formula *formula = FormulaManager::instance().findFormula(id);
519 if (formula && !formula->text().isEmpty())
520 {
521 m_id = id;
522 m_name.sprintf("form_%d",m_id);
523 m_text = formula->text();
524 }
525 else // wrong \_form#<n> command
526 {
527 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Wrong formula id {:d}",id);
528 m_id = -1;
529 }
530}
531
532//---------------------------------------------------------------------------
533
538
540{
541 AUTO_TRACE();
542 auto ns = AutoNodeStack(parser(),thisVariant());
543
545 Token tok = parser()->tokenizer.lex();
546 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
547 {
548 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
549 {
550 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\refitem");
551 }
552 tok = parser()->tokenizer.lex();
553 }
556
557 if (!m_target.isEmpty())
558 {
560 if (sec==nullptr && parser()->context.lang==SrcLangExt::Markdown) // lookup as markdown file
561 {
563 }
564 if (sec) // ref to section or anchor
565 {
566 // set defaults
567 m_ref = sec->ref();
570 m_anchor = sec->label();
571 m_isSubPage = false;
572 // adjust if needed
573 switch (sec->type().level())
574 {
576 {
578 m_isSubPage = pd && pd->hasParentPage();
579 if (!m_isSubPage)
580 {
581 m_anchor="";
582 }
583 }
584 break;
587 break;
590 break;
591 default:
592 break;
593 }
594 //printf("m_ref=%s,m_file=%s,type=%d\n",
595 // qPrint(m_ref),qPrint(m_file),m_refType);
596 }
597 else
598 {
599 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to unknown section {}",m_target);
600 }
601 }
602 else
603 {
604 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to empty target");
605 }
606}
607
608//---------------------------------------------------------------------------
609
611{
612 AUTO_TRACE();
613 auto ns = AutoNodeStack(parser(),thisVariant());
614
615 Token tok=parser()->tokenizer.lex();
616 // skip white space
617 while (tok.is_any_of(TokenRetval::TK_WHITESPACE, TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
618 // handle items
619 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
620 {
621 if (tok.is_any_of(TokenRetval::TK_COMMAND_AT, TokenRetval::TK_COMMAND_BS))
622 {
623 switch (Mappers::cmdMapper->map(parser()->context.token->name))
624 {
626 {
627 tok=parser()->tokenizer.lex();
628 if (!tok.is(TokenRetval::TK_WHITESPACE))
629 {
630 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\refitem command");
631 break;
632 }
633 tok=parser()->tokenizer.lex();
634 if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
635 {
636 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\refitem",
637 tok.to_string());
638 break;
639 }
640
643 }
644 break;
646 return;
647 default:
648 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\secreflist",
649 tok.command_to_char(),qPrint(parser()->context.token->name));
650 return;
651 }
652 }
653 else if (tok.is(TokenRetval::TK_WHITESPACE))
654 {
655 // ignore whitespace
656 }
657 else
658 {
659 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} inside section reference list",
660 tok.to_string());
661 return;
662 }
663 tok=parser()->tokenizer.lex();
664 }
665
666}
667
668//---------------------------------------------------------------------------
669
672{
673 int i=ref.find('#');
674 if (i!=-1)
675 {
676 m_anchor = ref.right(static_cast<int>(ref.length())-i-1);
677 m_file = ref.left(i);
678 }
679 else
680 {
681 m_file = ref;
682 }
683}
684
686{
687 AUTO_TRACE();
688 auto ns = AutoNodeStack(parser(),thisVariant());
689
690 Token tok = parser()->tokenizer.lex();
691 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
692 {
693 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
694 {
696 }
697 tok=parser()->tokenizer.lex();
698 }
699
701}
702
703//---------------------------------------------------------------------------
704
707{
708 const Definition *compound = nullptr;
710 AUTO_TRACE("target='{}',context='{}'",target,context);
711 ASSERT(!target.isEmpty());
712 m_relPath = parser->context.relPath;
713 auto lang = parser->context.lang;
714 const SectionInfo *sec = SectionManager::instance().find(parser->context.prefix+target);
715 if (sec==nullptr && !parser->context.prefix.isEmpty())
716 {
717 sec = SectionManager::instance().find(target);
718 }
719
720 if (sec==nullptr && getLanguageFromFileName(target)==SrcLangExt::Markdown) // lookup as markdown file
721 {
723 }
724 if (sec) // ref to section or anchor
725 {
726 PageDef *pd = nullptr;
727 int secLevel = sec->type().level();
728 if (secLevel==SectionType::Page)
729 {
730 pd = Doxygen::pageLinkedMap->find(target);
731 }
732 m_text = sec->title();
733 if (m_text.isEmpty()) m_text = sec->label();
734
735 m_ref = sec->ref();
737 if (secLevel==SectionType::Anchor)
738 {
740 }
741 else if (secLevel==SectionType::Table)
742 {
744 }
745 else
746 {
748 }
749 m_isSubPage = pd && pd->hasParentPage();
750 if (secLevel!=SectionType::Page || m_isSubPage)
751 {
752 m_anchor = pd ? pd->getOutputFileBase() : sec->label();
753 }
754 m_sectionType = sec->type();
755 //printf("m_text=%s,m_ref=%s,m_file=%s,type=%d\n",
756 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),m_refType);
757 AUTO_TRACE_EXIT("section");
758 return;
759 }
760 else if (Config_getBool(IMPLICIT_DIR_DOCS) && target.lower().endsWith("/readme.md"))
761 {
762 QCString dirTarget = target.left(target.length() - 9); // strip readme.md part
763 const auto &dd = Doxygen::dirLinkedMap->find(dirTarget);
764 if (dd)
765 {
766 m_text = target;
767 m_file = dd->getOutputFileBase();
768 AUTO_TRACE_EXIT("directory");
769 return;
770 }
771 }
772 else if (resolveLink(context,target,true,&compound,anchor,lang,parser->context.prefix))
773 {
774 bool isFile = compound ?
775 (compound->definitionType()==Definition::TypeFile ||
777 FALSE;
778 if (compound && lang==SrcLangExt::Markdown) lang = compound->getLanguage();
779 m_text = linkToText(lang,target,isFile);
781 if (compound && compound->isLinkable()) // ref to compound
782 {
783 if (anchor.isEmpty() && /* compound link */
784 compound->definitionType()==Definition::TypeGroup && /* is group */
785 !toGroupDef(compound)->groupTitle().isEmpty() /* with title */
786 )
787 {
788 m_text=(toGroupDef(compound))->groupTitle(); // use group's title as link
789 }
790 else if (compound->definitionType()==Definition::TypeMember &&
791 toMemberDef(compound)->isObjCMethod())
792 {
793 // Objective C Method
794 const MemberDef *member = toMemberDef(compound);
795 bool localLink = parser->context.memberDef ? member->getClassDef()==parser->context.memberDef->getClassDef() : FALSE;
796 m_text = member->objCMethodName(localLink,parser->context.inSeeBlock);
797 }
798 else if (Config_getBool(HIDE_SCOPE_NAMES))
799 {
801 }
802
803 m_file = compound->getOutputFileBase();
804 m_ref = compound->getReference();
805 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
806 // compound->definitionType());
807 AUTO_TRACE_EXIT("compound");
808 return;
809 }
810 else if (compound && compound->definitionType()==Definition::TypeFile &&
811 toFileDef(compound)->generateSourceFile()
812 ) // undocumented file that has source code we can link to
813 {
814 m_file = compound->getSourceFileBase();
815 m_ref = compound->getReference();
816 AUTO_TRACE_EXIT("source");
817 return;
818 }
819 else
820 {
821 AUTO_TRACE_EXIT("compound '{}' not linkable",compound?compound->name():"none");
822 }
823 }
824 m_text = target;
825 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\ref command",
826 target);
827}
828
830{
831 for (auto &&elem : elements)
832 {
833 emplace_back(std::move(elem));
834 }
835 elements.clear();
836}
837
838static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
839{
840 DocNodeList newChildren;
841 for (auto &dn : children)
842 {
843 DocPara *para = std::get_if<DocPara>(&dn);
844 if (para)
845 {
846 //// move the children of the paragraph to the end of the newChildren list
847 newChildren.move_append(para->children());
848 }
849 }
850
851 // replace the children list by the newChildren list
852 children.clear();
853 children.move_append(newChildren);
854 // reparent the children
855 for (auto &cn : children)
856 {
857 setParent(&cn,root);
858 // we also need to set the parent for each child of cn, as cn's address may have changed.
859 auto opt_children = call_method_children(&cn);
860 if (opt_children)
861 {
862 for (auto &ccn : *opt_children)
863 {
864 setParent(&ccn,&cn);
865 }
866 }
867 }
868}
869
871{
872 AUTO_TRACE();
873 auto ns = AutoNodeStack(parser(),thisVariant());
874
875 Token tok = parser()->tokenizer.lex();
876 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
877 {
878 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
879 {
880 switch (tok.value())
881 {
882 case TokenRetval::TK_HTMLTAG:
883 break;
884 default:
886 break;
887 }
888 }
889 tok=parser()->tokenizer.lex();
890 }
891
892 if (children().empty() && !m_text.isEmpty())
893 {
894 QCString text = m_text;
895 if (parser()->context.insideHtmlLink)
896 {
897 // we already in a link/title only output anchor
898 text = m_anchor;
899 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
900 "Potential recursion while resolving \\ref command!");
901 }
903 parser()->pushContext();
905 parser()->popContext();
909 }
910
912}
913
914//---------------------------------------------------------------------------
915
917{
918 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
919 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
920 ASSERT(!target.isEmpty());
921 m_relPath = parser->context.relPath;
923 const CiteInfo *cite = ct.find(target);
924 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
925 m_option = opt;
927 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
928 {
929 m_ref = "";
930 m_anchor = ct.anchorPrefix()+cite->label();
932 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
933 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
934 return;
935 }
936 if (numBibFiles==0)
937 {
938 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
939 }
940 else if (cite==nullptr)
941 {
942 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\cite command",
943 target);
944 }
945 else
946 {
947 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '{}' does not have an associated number",
948 target);
949 }
950}
951
953{
954 QCString txt;
955 auto opt = m_option;
957 const CiteInfo *citeInfo = ct.find(m_target);
958
959 if (!opt.noPar()) txt += "[";
960
961 if (citeInfo)
962 {
963 if (opt.isNumber()) txt += citeInfo->text();
964 else if (opt.isShortAuthor()) txt += citeInfo->shortAuthor();
965 else if (opt.isYear()) txt += citeInfo->year();
966 }
967
968 if (!opt.noPar()) txt += "]";
969 return txt;
970}
971
972
973//---------------------------------------------------------------------------
974
976{
977 const Definition *compound = nullptr;
979 m_refText = target;
980 m_relPath = parser->context.relPath;
981 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
982 {
983 m_refText = m_refText.right(m_refText.length()-1);
984 }
985 if (resolveLink(parser->context.context,stripKnownExtensions(target),
986 parser->context.inSeeBlock,&compound,anchor,
987 parser->context.lang,parser->context.prefix))
988 {
989 m_anchor = anchor;
990 if (compound && compound->isLinkable())
991 {
992 m_file = compound->getOutputFileBase();
993 m_ref = compound->getReference();
994 }
995 else if (compound && compound->definitionType()==Definition::TypeFile &&
996 (toFileDef(compound))->generateSourceFile()
997 ) // undocumented file that has source code we can link to
998 {
999 m_file = compound->getSourceFileBase();
1000 m_ref = compound->getReference();
1001 }
1002 return;
1003 }
1004
1005 // bogus link target
1006 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '{}' for \\link command",
1007 target);
1008}
1009
1010
1011QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
1012{
1013 AUTO_TRACE();
1014 QCString result;
1015 auto ns = AutoNodeStack(parser(),thisVariant());
1016
1017 Token tok = parser()->tokenizer.lex();
1018 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1019 {
1020 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
1021 {
1022 switch (tok.value())
1023 {
1024 case TokenRetval::TK_COMMAND_AT:
1025 // fall through
1026 case TokenRetval::TK_COMMAND_BS:
1027 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1028 {
1030 if (isJavaLink)
1031 {
1032 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{{@link...' ended with '{:c}{}' command",
1033 tok.command_to_char(),parser()->context.token->name);
1034 }
1035 goto endlink;
1036 default:
1037 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\link",
1038 tok.command_to_char(),parser()->context.token->name);
1039 break;
1040 }
1041 break;
1042 case TokenRetval::TK_SYMBOL:
1043 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a \\link",
1044 parser()->context.token->name);
1045 break;
1046 case TokenRetval::TK_HTMLTAG:
1047 if (parser()->context.token->name!="see" || !isXmlLink)
1048 {
1049 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command {} found as part of a \\link",
1050 parser()->context.token->name);
1051 }
1052 goto endlink;
1053 case TokenRetval::TK_LNKWORD:
1054 case TokenRetval::TK_WORD:
1055 if (isJavaLink) // special case to detect closing }
1056 {
1058 int p = 0;
1059 if (w=="}")
1060 {
1061 goto endlink;
1062 }
1063 else if ((p=w.find('}'))!=-1)
1064 {
1065 int l = static_cast<int>(w.length());
1067 if (p<l-1) // something left after the } (for instance a .)
1068 {
1069 result=w.right(l-p-1);
1070 }
1071 goto endlink;
1072 }
1073 }
1075 break;
1076 default:
1077 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",tok.to_string());
1078 break;
1079 }
1080 }
1081 tok = parser()->tokenizer.lex();
1082 }
1083 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1084 {
1085 warn_doc_error(parser()->context.fileName,
1086 parser()->tokenizer.getLineNr(),
1087 "Unexpected end of comment while inside link command");
1088 }
1089endlink:
1090
1091 if (children().empty()) // no link text
1092 {
1094 }
1095
1097 return result;
1098}
1099
1100
1101//---------------------------------------------------------------------------
1102
1109
1111{
1112 bool ok = false;
1114
1115 bool ambig = false;
1117 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1118 {
1119 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1120 }
1121 if (fd)
1122 {
1123 p->file = fd->absFilePath();
1124 ok = true;
1125 if (ambig)
1126 {
1127 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '{}' is ambiguous.\n"
1128 "Possible candidates:\n{}",p->name,
1130 );
1131 }
1132 }
1133 else
1134 {
1135 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '{}' is not found "
1136 "in any of the paths specified via DOTFILE_DIRS!",p->name);
1137 }
1138 return ok;
1139}
1140
1147
1149{
1150 bool ok = false;
1152
1153 bool ambig = false;
1155 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1156 {
1157 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1158 }
1159 if (fd)
1160 {
1161 p->file = fd->absFilePath();
1162 ok = true;
1163 if (ambig)
1164 {
1165 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '{}' is ambiguous.\n"
1166 "Possible candidates:\n{}",qPrint(p->name),
1168 );
1169 }
1170 }
1171 else
1172 {
1173 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '{}' is not found "
1174 "in any of the paths specified via MSCFILE_DIRS!",p->name);
1175 }
1176 return ok;
1177}
1178
1179//---------------------------------------------------------------------------
1180
1187
1189{
1190 bool ok = false;
1192
1193 bool ambig = false;
1195 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1196 {
1197 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
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 dia 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 dia file '{}' is not found "
1214 "in any of the paths specified via DIAFILE_DIRS!",p->name);
1215 }
1216 return ok;
1217}
1218//---------------------------------------------------------------------------
1219
1226
1228{
1229 bool ok = false;
1231
1232 bool ambig = false;
1234 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1235 {
1236 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1237 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1238 {
1239 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1240 }
1241 }
1242 if (fd)
1243 {
1244 p->file = fd->absFilePath();
1245 ok = true;
1246 if (ambig)
1247 {
1248 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '{}' is ambiguous.\n"
1249 "Possible candidates:\n{}",p->name,
1251 );
1252 }
1253 }
1254 else
1255 {
1256 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '{}' is not found "
1257 "in any of the paths specified via PLANTUMLFILE_DIRS!",p->name);
1258 }
1259 return ok;
1260}
1261
1262//---------------------------------------------------------------------------
1263
1267
1269{
1270 AUTO_TRACE();
1271 auto ns = AutoNodeStack(parser(),thisVariant());
1272
1274 Token tok = parser()->tokenizer.lex();
1275 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1276 {
1277 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1278 {
1279 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1280 }
1281 tok = parser()->tokenizer.lex();
1282 }
1283 parser()->tokenizer.lex();
1284
1287
1288 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1289}
1290
1291
1292//---------------------------------------------------------------------------
1293
1295 Type t,const QCString &url, bool inlineImage) :
1296 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1297{
1298}
1299
1301{
1302 QCString locName = p->url.isEmpty() ? p->name : p->url;
1303 int len = static_cast<int>(locName.length());
1304 int fnd = locName.find('?'); // ignore part from ? until end
1305 if (fnd==-1) fnd=len;
1306 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1307}
1308
1313
1314
1315//---------------------------------------------------------------------------
1316
1318{
1319 AUTO_TRACE();
1320 Token retval(TokenRetval::RetVal_OK);
1321 auto ns = AutoNodeStack(parser(),thisVariant());
1322
1323 Token tok = parser()->tokenizer.lex();
1324 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1325 {
1326 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1327 {
1328 switch (tok.value())
1329 {
1330 case TokenRetval::TK_HTMLTAG:
1331 {
1332 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1333 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1334 {
1335 if (m_level!=1)
1336 {
1337 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h1>",
1338 m_level);
1339 }
1340 goto endheader;
1341 }
1342 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1343 {
1344 if (m_level!=2)
1345 {
1346 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h2>",
1347 m_level);
1348 }
1349 goto endheader;
1350 }
1351 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1352 {
1353 if (m_level!=3)
1354 {
1355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h3>",
1356 m_level);
1357 }
1358 goto endheader;
1359 }
1360 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1361 {
1362 if (m_level!=4)
1363 {
1364 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h4>",
1365 m_level);
1366 }
1367 goto endheader;
1368 }
1369 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1370 {
1371 if (m_level!=5)
1372 {
1373 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h5>",
1374 m_level);
1375 }
1376 goto endheader;
1377 }
1378 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1379 {
1380 if (m_level!=6)
1381 {
1382 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h6>",
1383 m_level);
1384 }
1385 goto endheader;
1386 }
1387 else if (tagId==HtmlTagType::HTML_A)
1388 {
1389 if (!parser()->context.token->endTag)
1390 {
1391 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1392 }
1393 }
1394 else if (tagId==HtmlTagType::HTML_BR)
1395 {
1397 }
1398 else
1399 {
1400 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <h{:d}> context",
1401 parser()->context.token->endTag?"/":"",parser()->context.token->name,m_level);
1402 }
1403 }
1404 break;
1405 default:
1406 char tmp[20];
1407 qsnprintf(tmp,20,"<h%d> tag",m_level);
1409 }
1410 }
1411 tok = parser()->tokenizer.lex();
1412 }
1413 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1414 {
1415 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1416 " <h{:d}> tag",m_level);
1417 }
1418endheader:
1420 return retval;
1421}
1422//---------------------------------------------------------------------------
1423
1425{
1426 AUTO_TRACE();
1427 auto ns = AutoNodeStack(parser(),thisVariant());
1429 Token tok = parser()->tokenizer.lex();
1430 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1431 {
1433 // check of </summary>
1434 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1435 (tagId=Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1436 parser()->context.token->endTag
1437 )
1438 {
1439 break;
1440 }
1441 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1442 {
1443 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1444 }
1445 tok = parser()->tokenizer.lex();
1446 }
1448 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1449 {
1450 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1451 " <summary> tag");
1452 }
1453}
1454
1455//---------------------------------------------------------------------------
1456
1458{
1459 AUTO_TRACE();
1460 Token retval(TokenRetval::TK_NONE);
1461 auto ns = AutoNodeStack(parser(),thisVariant());
1462
1463 // parse one or more paragraphs
1464 bool isFirst=TRUE;
1465 DocPara *par=nullptr;
1466 do
1467 {
1469 par = children().get_last<DocPara>();
1470 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1471 retval=par->parse();
1472 }
1473 while (retval.is(TokenRetval::TK_NEWPARA));
1474 if (par) par->markLast();
1475
1476 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1477 {
1478 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1479 }
1480
1481 if (!summary())
1482 {
1483 HtmlAttribList summaryAttribs;
1485 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1486 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1487 }
1488 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1489 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1490}
1491
1499
1500//---------------------------------------------------------------------------
1501
1503{
1504 AUTO_TRACE();
1505 Token retval(TokenRetval::RetVal_OK);
1506 auto ns = AutoNodeStack(parser(),thisVariant());
1507
1508 Token tok = parser()->tokenizer.lex();
1509 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1510 {
1511 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1512 {
1513 switch (tok.value())
1514 {
1515 case TokenRetval::TK_HTMLTAG:
1516 {
1517 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1518 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1519 {
1520 goto endhref;
1521 }
1522 else if (tagId==HtmlTagType::HTML_BR)
1523 {
1525 }
1526 else
1527 {
1528 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <a href=...> context",
1529 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1530 }
1531 }
1532 break;
1533 default:
1534 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1535 break;
1536 }
1537 }
1538 tok = parser()->tokenizer.lex();
1539 }
1540 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1541 {
1542 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1543 " <a href=...> tag");
1544 }
1545endhref:
1547 return retval;
1548}
1549
1550//---------------------------------------------------------------------------
1551
1553{
1554 AUTO_TRACE();
1555 Token retval(TokenRetval::RetVal_OK);
1556 auto ns = AutoNodeStack(parser(),thisVariant());
1557
1558 // first parse any number of paragraphs
1559 bool isFirst=TRUE;
1560 DocPara *lastPar=nullptr;
1561 do
1562 {
1564 DocPara *par = children().get_last<DocPara>();
1565 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1566 retval=par->parse();
1567 if (!par->isEmpty())
1568 {
1569 if (lastPar) lastPar->markLast(FALSE);
1570 lastPar=par;
1571 }
1572 else
1573 {
1574 children().pop_back();
1575 }
1576 if (retval.is(TokenRetval::TK_LISTITEM))
1577 {
1578 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1579 }
1580 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1581 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1582 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1583 TokenRetval::RetVal_EndInternal));
1584 if (lastPar) lastPar->markLast();
1585
1586 // then parse any number of level-n sections
1587 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1588 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1589 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1590 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1591 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1592 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1593 )
1594 {
1596 level,
1598 retval = children().get_last<DocSection>()->parse();
1599 }
1600
1601 if (retval.is(TokenRetval::RetVal_Internal))
1602 {
1603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1604 }
1605
1606 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1607 return retval;
1608}
1609
1610//---------------------------------------------------------------------------
1611
1613{
1614 AUTO_TRACE();
1615 Token retval(TokenRetval::RetVal_OK);
1616 auto ns = AutoNodeStack(parser(),thisVariant());
1617 Token tok=parser()->tokenizer.lex();
1618 if (!tok.is(TokenRetval::TK_WHITESPACE))
1619 {
1620 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1621 goto endindexentry;
1622 }
1624 m_entry="";
1625 tok = parser()->tokenizer.lex();
1626 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1627 {
1628 switch (tok.value())
1629 {
1630 case TokenRetval::TK_WHITESPACE:
1631 m_entry+=" ";
1632 break;
1633 case TokenRetval::TK_WORD:
1634 case TokenRetval::TK_LNKWORD:
1636 break;
1637 case TokenRetval::TK_SYMBOL:
1638 {
1639 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1640 switch (s)
1641 {
1642 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1643 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1644 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1645 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1646 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1647 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1648 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1649 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1650 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1651 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1652 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1653 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1654 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1655 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1656 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1657 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1658 default:
1659 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '{}' found as argument of \\addindex",parser()->context.token->name);
1660 break;
1661 }
1662 }
1663 break;
1664 case TokenRetval::TK_COMMAND_AT:
1665 // fall through
1666 case TokenRetval::TK_COMMAND_BS:
1667 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1668 {
1669 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1670 case CommandType::CMD_AT: m_entry+='@'; break;
1671 case CommandType::CMD_LESS: m_entry+='<'; break;
1672 case CommandType::CMD_GREATER: m_entry+='>'; break;
1673 case CommandType::CMD_AMP: m_entry+='&'; break;
1674 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1675 case CommandType::CMD_HASH: m_entry+='#'; break;
1676 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1677 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1678 case CommandType::CMD_NDASH: m_entry+="--"; break;
1679 case CommandType::CMD_MDASH: m_entry+="---"; break;
1680 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1681 case CommandType::CMD_PUNT: m_entry+='.'; break;
1682 case CommandType::CMD_PLUS: m_entry+='+'; break;
1683 case CommandType::CMD_MINUS: m_entry+='-'; break;
1684 case CommandType::CMD_EQUAL: m_entry+='='; break;
1685 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1686 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1687 default:
1688 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command {} found as argument of \\addindex",
1689 parser()->context.token->name);
1690 break;
1691 }
1692 break;
1693 default:
1694 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
1695 tok.to_string());
1696 break;
1697 }
1698 tok = parser()->tokenizer.lex();
1699 }
1701 m_entry = m_entry.stripWhiteSpace();
1702endindexentry:
1703 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1704 return retval;
1705}
1706
1707//---------------------------------------------------------------------------
1708
1711{
1713 for (const auto &opt : attribs)
1714 {
1715 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1716 {
1717 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1718 if (sec)
1719 {
1720 //printf("Found anchor %s\n",qPrint(id));
1721 m_file = sec->fileName();
1722 m_anchor = sec->label();
1724 }
1725 else
1726 {
1727 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '{}'",opt.value);
1728 }
1729 }
1730 else // copy attribute
1731 {
1732 m_attribs.push_back(opt);
1733 }
1734 }
1735}
1736
1738{
1739 AUTO_TRACE();
1740 Token retval = Token::make_TK_NONE();
1741 auto ns = AutoNodeStack(parser(),thisVariant());
1742 Token tok = parser()->tokenizer.lex();
1743 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1744 {
1745 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1746 {
1747 switch (tok.value())
1748 {
1749 case TokenRetval::TK_HTMLTAG:
1750 {
1751 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1752 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1753 {
1754 retval = Token::make_RetVal_OK();
1755 goto endcaption;
1756 }
1757 else
1758 {
1759 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <caption> context",
1760 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1761 }
1762 }
1763 break;
1764 default:
1765 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1766 break;
1767 }
1768 }
1769 tok = parser()->tokenizer.lex();
1770 }
1771 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1772 {
1773 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1774 " <caption> tag");
1775 }
1776endcaption:
1778 return retval;
1779}
1780
1781//---------------------------------------------------------------------------
1782
1784{
1785 AUTO_TRACE();
1786 Token retval = Token::make_RetVal_OK();
1787 auto ns = AutoNodeStack(parser(),thisVariant());
1788
1789 // parse one or more paragraphs
1790 bool isFirst=TRUE;
1791 DocPara *par=nullptr;
1792 do
1793 {
1795 par = children().get_last<DocPara>();
1796 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1797 retval=par->parse();
1798 if (retval.is(TokenRetval::TK_HTMLTAG))
1799 {
1800 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1801 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1802 {
1803 retval = Token::make_TK_NEWPARA(); // ignore the tag
1804 }
1805 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1806 {
1807 retval = Token::make_TK_NEWPARA(); // ignore the tag
1808 }
1809 }
1810 }
1811 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1812 if (par) par->markLast();
1813
1814 return retval;
1815}
1816
1818{
1819 AUTO_TRACE();
1820 Token retval = Token::make_RetVal_OK();
1821 auto ns = AutoNodeStack(parser(),thisVariant());
1822
1823 // parse one or more paragraphs
1824 bool isFirst=TRUE;
1825 DocPara *par=nullptr;
1826 do
1827 {
1829 par = children().get_last<DocPara>();
1830 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1831 retval=par->parse();
1832 if (retval.is(TokenRetval::TK_HTMLTAG))
1833 {
1834 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1835 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1836 {
1837 retval = Token::make_TK_NEWPARA(); // ignore the tag
1838 }
1839 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1840 {
1841 retval = Token::make_TK_NEWPARA(); // ignore the tag
1842 }
1843 }
1844 }
1845 while (retval.is(TokenRetval::TK_NEWPARA));
1846 if (par) par->markLast();
1847
1848 return retval;
1849}
1850
1851uint32_t DocHtmlCell::rowSpan() const
1852{
1853 for (const auto &attr : attribs())
1854 {
1855 if (attr.name.lower()=="rowspan")
1856 {
1857 return attr.value.toUInt();
1858 }
1859 }
1860 return 0;
1861}
1862
1863uint32_t DocHtmlCell::colSpan() const
1864{
1865 for (const auto &attr : attribs())
1866 {
1867 if (attr.name.lower()=="colspan")
1868 {
1869 return std::max(1u,attr.value.toUInt());
1870 }
1871 }
1872 return 1;
1873}
1874
1876{
1877 for (const auto &attr : attribs())
1878 {
1879 QCString attrName = attr.name.lower();
1880 QCString attrValue = attr.value.lower();
1881 if (attrName=="align")
1882 {
1883 if (attrValue=="center")
1884 return Center;
1885 else if (attrValue=="right")
1886 return Right;
1887 else return Left;
1888 }
1889 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1890 {
1891 if (attrValue=="markdowntableheadcenter")
1892 return Center;
1893 else if (attrValue=="markdowntableheadright")
1894 return Right;
1895 else if (attrValue=="markdowntableheadleft")
1896 return Left;
1897 else if (attrValue=="markdowntableheadnone")
1898 return Center;
1899 else if (attrValue=="markdowntablebodycenter")
1900 return Center;
1901 else if (attrValue=="markdowntablebodyright")
1902 return Right;
1903 else if (attrValue=="markdowntablebodyleft")
1904 return Left;
1905 else if (attrValue=="markdowntablebodynone")
1906 return Left;
1907 else return Left;
1908 }
1909 }
1910 return Left;
1911}
1912
1914{
1915 for (const auto &attr : attribs())
1916 {
1917 QCString attrName = attr.name.lower();
1918 QCString attrValue = attr.value.lower();
1919 if (attrName=="valign")
1920 {
1921 if (attrValue=="top")
1922 return Top;
1923 else if (attrValue=="bottom")
1924 return Bottom;
1925 else if (attrValue=="middle")
1926 return Middle;
1927 else return Middle;
1928 }
1929 }
1930 return Middle;
1931}
1932
1933//---------------------------------------------------------------------------
1934
1936{ // a row is a table heading if all cells are marked as such
1937 bool heading=TRUE;
1938 for (const auto &n : children())
1939 {
1940 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1941 if (cell && !cell->isHeading())
1942 {
1943 heading = FALSE;
1944 break;
1945 }
1946 }
1947 return !children().empty() && heading;
1948}
1949
1951{
1952 AUTO_TRACE();
1953 // get next token
1954 Token tok=parser->tokenizer.lex();
1955 // skip whitespace and tbody, thead and tfoot tags
1956 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA,TokenRetval::TK_HTMLTAG,
1957 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS))
1958 {
1959 if (tok.is(TokenRetval::TK_HTMLTAG))
1960 {
1961 AUTO_TRACE_ADD("html_tag={}",parser->context.token->name);
1963 // skip over tbody, thead, tfoot tags
1964 if (tagId==HtmlTagType::HTML_TBODY ||
1965 tagId==HtmlTagType::HTML_THEAD ||
1967 {
1968 tok=parser->tokenizer.lex();
1969 }
1970 else
1971 {
1972 break;
1973 }
1974 }
1975 else if (tok.is(TokenRetval::TK_COMMAND_AT) || tok.is(TokenRetval::TK_COMMAND_BS))
1976 {
1977 QCString cmdName=parser->context.token->name;
1978 AUTO_TRACE_ADD("command={}",cmdName);
1979 auto cmdType = Mappers::cmdMapper->map(cmdName);
1980 if (cmdType==CommandType::CMD_ILINE)
1981 {
1982 parser->tokenizer.pushState();
1983 parser->tokenizer.setStateILine();
1984 tok = parser->tokenizer.lex();
1985 if (!tok.is(TokenRetval::TK_WORD))
1986 {
1987 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
1988 tok.command_to_char(),cmdName);
1989 }
1990 parser->tokenizer.popState();
1991 tok = parser->tokenizer.lex();
1992 }
1993 else
1994 {
1995 break;
1996 }
1997 }
1998 else
1999 {
2000 AUTO_TRACE_ADD("skip whitespace");
2001 tok=parser->tokenizer.lex();
2002 }
2003 }
2004 return tok;
2005}
2006
2007
2008
2009
2011{
2012 AUTO_TRACE();
2013 Token retval = Token::make_RetVal_OK();
2014 auto ns = AutoNodeStack(parser(),thisVariant());
2015
2016 bool isHeading=FALSE;
2017 bool isFirst=TRUE;
2018 DocHtmlCell *cell=nullptr;
2019
2021 // should find a html tag now
2022 if (tok.is(TokenRetval::TK_HTMLTAG))
2023 {
2024 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2025 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
2026 {
2027 }
2028 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
2029 {
2031 }
2032 else // found some other tag
2033 {
2034 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
2035 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2036 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2037 goto endrow;
2038 }
2039 }
2040 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2041 {
2042 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2043 " for a html description title");
2044 goto endrow;
2045 }
2046 else // token other than html token
2047 {
2048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2049 tok.to_string());
2050 goto endrow;
2051 }
2052
2053 // parse one or more cells
2054 do
2055 {
2058 isHeading);
2059 cell = children().get_last<DocHtmlCell>();
2060 cell->markFirst(isFirst);
2061 isFirst=FALSE;
2062 retval=cell->parse();
2063 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
2064 //printf("DocHtmlRow:retval=%s\n",retval.to_string());
2065 if (retval.is(TokenRetval::RetVal_EndTableCell))
2066 {
2067 // get next token
2068 retval = skipSpacesForTable(parser());
2069 //printf("DocHtmlRow:retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2070 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2071 if (tok.is(TokenRetval::TK_HTMLTAG))
2072 {
2073 if ((tagId==HtmlTagType::HTML_TD || tagId==HtmlTagType::HTML_TH) &&
2074 !parser()->context.token->endTag) // found new <td> or <td> tag
2075 {
2076 retval = Token::make_RetVal_TableCell();
2078 }
2079 else if (tagId==HtmlTagType::HTML_TR)
2080 {
2081 if (parser()->context.token->endTag) // found </tr> tag
2082 {
2083 retval = Token::make_RetVal_EndTableRow();
2084 }
2085 else // found <tr> tag
2086 {
2087 retval = Token::make_RetVal_TableRow();
2088 }
2089 }
2090 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag) // found </table>
2091 {
2092 retval = Token::make_RetVal_EndTable();
2093 }
2094 else // found some other tag
2095 {
2096 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but "
2097 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2098 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2099 goto endrow;
2100 }
2101 }
2102 else // token other than html token
2103 {
2104 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but found {} token instead!",
2105 tok.to_string());
2106 goto endrow;
2107 }
2108 }
2109 }
2110 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2111 cell->markLast(TRUE);
2112
2113endrow:
2114 return retval;
2115}
2116
2118{
2119 AUTO_TRACE();
2120 Token retval = Token::make_RetVal_OK();
2121 auto ns = AutoNodeStack(parser(),thisVariant());
2122
2123 bool isFirst=TRUE;
2124 DocHtmlCell *cell=nullptr;
2125
2126 // get next token
2127 Token tok=parser()->tokenizer.lex();
2128 // skip whitespace
2129 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2130 // should find a html tag now
2131 if (tok.is(TokenRetval::TK_HTMLTAG))
2132 {
2133 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2134 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
2135 {
2136 }
2137 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
2138 {
2139 }
2140 else // found some other tag
2141 {
2142 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
2143 "found <{}> instead!",parser()->context.token->name);
2144 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2145 goto endrow;
2146 }
2147 }
2148 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2149 {
2150 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2151 " for a html description title");
2152 goto endrow;
2153 }
2154 else // token other than html token
2155 {
2156 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2157 tok.to_string());
2158 goto endrow;
2159 }
2160
2161 do
2162 {
2164 cell = children().get_last<DocHtmlCell>();
2165 cell->markFirst(isFirst);
2166 isFirst=FALSE;
2167 retval=cell->parseXml();
2168 }
2169 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2170 cell->markLast(TRUE);
2171
2172endrow:
2173 return retval;
2174}
2175
2176//---------------------------------------------------------------------------
2177
2179{
2180 return m_caption!=nullptr;
2181}
2182
2184{
2185 return m_caption.get();
2186}
2187
2189{
2190 if (!children().empty() && std::holds_alternative<DocHtmlRow>(children().front()))
2191 {
2192 return &children().front();
2193 }
2194 return nullptr;
2195}
2196
2198{
2199 AUTO_TRACE();
2200 Token retval = Token::make_RetVal_OK();
2201 auto ns = AutoNodeStack(parser(),thisVariant());
2202
2203getrow:
2204 // skip whitespace and tbody, thead and tfoot tags
2206 // should find a html tag now
2207 if (tok.is(TokenRetval::TK_HTMLTAG))
2208 {
2209 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2210 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2211 {
2212 // no caption, just rows
2213 retval = Token::make_RetVal_TableRow();
2214 }
2215 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2216 {
2217 if (m_caption)
2218 {
2219 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2220 }
2221 else
2222 {
2223 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2224 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2225
2226 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2227 {
2228 goto getrow;
2229 }
2230 }
2231 }
2232 else // found wrong token
2233 {
2234 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2235 "found <{}{}> instead!", parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2236 }
2237 }
2238 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2239 {
2240 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2241 " for a <tr> or <caption> tag");
2242 }
2243 else // token other than html token
2244 {
2245 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found {} token instead!",
2246 tok.to_string());
2247 }
2248
2249 // parse one or more rows
2250 while (retval.is(TokenRetval::RetVal_TableRow))
2251 {
2253 retval = children().get_last<DocHtmlRow>()->parse();
2254 //printf("DocHtmlTable::retval=%s\n",retval.to_string());
2255 if (retval.is(TokenRetval::RetVal_EndTableRow))
2256 {
2257 // get next token
2258 retval = skipSpacesForTable(parser());
2259 //printf("DocHtmlTable::retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2260 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2261 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag)
2262 {
2263 retval = Token::make_RetVal_TableRow();
2264 }
2265 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag)
2266 {
2267 retval = Token::make_RetVal_EndTable();
2268 }
2269 else // found some other tag
2270 {
2271 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or </table> tag but "
2272 "found token {} instead!",retval.to_string());
2273 retval=Token::make_RetVal_OK();
2274 break;
2275 }
2276 }
2277 }
2278
2280
2281 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2282}
2283
2285{
2286 AUTO_TRACE();
2287 Token retval = Token::make_RetVal_OK();
2288 auto ns = AutoNodeStack(parser(),thisVariant());
2289
2290 // get next token
2291 Token tok=parser()->tokenizer.lex();
2292 // skip whitespace
2293 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2294 // should find a html tag now
2296 bool isHeader=FALSE;
2297 if (tok.is(TokenRetval::TK_HTMLTAG))
2298 {
2299 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2300 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2301 {
2302 retval = Token::make_RetVal_TableRow();
2303 }
2304 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2305 {
2306 retval = Token::make_RetVal_TableRow();
2307 isHeader=TRUE;
2308 }
2309 }
2310
2311 // parse one or more rows
2312 while (retval.is(TokenRetval::RetVal_TableRow))
2313 {
2316 retval=tr->parseXml(isHeader);
2317 isHeader=FALSE;
2318 }
2319
2321
2322 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2323 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2324}
2325
2326/** Helper class to compute the grid for an HTML style table */
2328{
2329 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2330 uint32_t rowsLeft;
2331 uint32_t column;
2332};
2333
2334/** List of ActiveRowSpan classes. */
2335typedef std::vector<ActiveRowSpan> RowSpanList;
2336
2337/** determines the location of all cells in a grid, resolving row and
2338 column spans. For each the total number of visible cells is computed,
2339 and the total number of visible columns over all rows is stored.
2340 */
2342{
2343 //printf("computeTableGrid()\n");
2344 RowSpanList rowSpans;
2345 uint32_t maxCols=0;
2346 uint32_t rowIdx=1;
2347 for (auto &rowNode : children())
2348 {
2349 uint32_t colIdx=1;
2350 uint32_t cells=0;
2351 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2352 if (row)
2353 {
2354 for (auto &cellNode : row->children())
2355 {
2356 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2357 if (cell)
2358 {
2359 uint32_t rs = cell->rowSpan();
2360 uint32_t cs = cell->colSpan();
2361
2362 for (size_t i=0;i<rowSpans.size();i++)
2363 {
2364 if (rowSpans[i].rowsLeft>0 &&
2365 rowSpans[i].column==colIdx)
2366 {
2367 colIdx=rowSpans[i].column+1;
2368 cells++;
2369 }
2370 }
2371 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2372 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2373 cell->setRowIndex(rowIdx);
2374 cell->setColumnIndex(colIdx);
2375 colIdx+=cs;
2376 cells++;
2377 }
2378 }
2379 for (size_t i=0;i<rowSpans.size();i++)
2380 {
2381 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2382 }
2383 row->setVisibleCells(cells);
2384 row->setRowIndex(rowIdx);
2385 rowIdx++;
2386 }
2387 if (colIdx-1>maxCols) maxCols=colIdx-1;
2388 }
2389 m_numCols = maxCols;
2390}
2391
2392//---------------------------------------------------------------------------
2393
2395{
2396 AUTO_TRACE();
2397 Token retval = Token::make_TK_NONE();
2398 auto ns = AutoNodeStack(parser(),thisVariant());
2399
2400 Token tok = parser()->tokenizer.lex();
2401 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2402 {
2403 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2404 {
2405 switch (tok.value())
2406 {
2407 case TokenRetval::TK_COMMAND_AT:
2408 // fall through
2409 case TokenRetval::TK_COMMAND_BS:
2410 {
2411 QCString cmdName=parser()->context.token->name;
2412 bool isJavaLink=FALSE;
2413 switch (Mappers::cmdMapper->map(cmdName))
2414 {
2416 {
2417 tok=parser()->tokenizer.lex();
2418 if (!tok.is(TokenRetval::TK_WHITESPACE))
2419 {
2420 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
2421 tok.command_to_char(),cmdName);
2422 }
2423 else
2424 {
2426 tok=parser()->tokenizer.lex(); // get the reference id
2427 if (!tok.is(TokenRetval::TK_WORD))
2428 {
2429 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}' command",
2430 tok.to_string(),tok.command_to_char(),cmdName);
2431 }
2432 else
2433 {
2435 children().get_last<DocRef>()->parse();
2436 }
2438 }
2439 }
2440 break;
2442 isJavaLink=TRUE;
2443 // fall through
2445 {
2446 tok=parser()->tokenizer.lex();
2447 if (!tok.is(TokenRetval::TK_WHITESPACE))
2448 {
2449 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
2450 cmdName);
2451 }
2452 else
2453 {
2455 tok=parser()->tokenizer.lex();
2456 if (!tok.is(TokenRetval::TK_WORD))
2457 {
2458 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\{} command",
2459 tok.to_string(),cmdName);
2460 }
2461 else
2462 {
2465 DocLink *lnk = children().get_last<DocLink>();
2466 QCString leftOver = lnk->parse(isJavaLink);
2467 if (!leftOver.isEmpty())
2468 {
2469 children().append<DocWord>(parser(),thisVariant(),leftOver);
2470 }
2471 }
2472 }
2473 }
2474
2475 break;
2476 default:
2477 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' found as part of a <dt> tag",
2478 tok.command_to_char(),cmdName);
2479 }
2480 }
2481 break;
2482 case TokenRetval::TK_SYMBOL:
2483 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a <dt> tag",
2484 parser()->context.token->name);
2485 break;
2486 case TokenRetval::TK_HTMLTAG:
2487 {
2488 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2489 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2490 {
2491 retval = Token::make_RetVal_DescData();
2492 goto endtitle;
2493 }
2494 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2495 {
2496 // ignore </dt> tag.
2497 }
2498 else if (tagId==HtmlTagType::HTML_DT)
2499 {
2500 // missing <dt> tag.
2501 retval = Token::make_RetVal_DescTitle();
2502 goto endtitle;
2503 }
2504 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2505 {
2506 retval = Token::make_RetVal_EndDesc();
2507 goto endtitle;
2508 }
2509 else if (tagId==HtmlTagType::HTML_A)
2510 {
2511 if (!parser()->context.token->endTag)
2512 {
2513 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2514 }
2515 }
2516 else
2517 {
2518 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <dt> context",
2519 parser()->context.token->endTag?"/":"",parser()->context.token->name);
2520 }
2521 }
2522 break;
2523 default:
2524 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} found as part of a <dt> tag",
2525 tok.to_string());
2526 break;
2527 }
2528 }
2529 tok = parser()->tokenizer.lex();
2530 }
2531 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2532 {
2533 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2534 " <dt> tag");
2535 }
2536endtitle:
2538 return retval;
2539}
2540
2541//---------------------------------------------------------------------------
2542
2544{
2545 AUTO_TRACE();
2547 Token retval = Token::make_TK_NONE();
2548 auto ns = AutoNodeStack(parser(),thisVariant());
2549
2550 bool isFirst=TRUE;
2551 DocPara *par=nullptr;
2552 do
2553 {
2555 par = children().get_last<DocPara>();
2556 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2557 retval=par->parse();
2558 }
2559 while (retval.is(TokenRetval::TK_NEWPARA));
2560 if (par) par->markLast();
2561
2562 return retval;
2563}
2564
2565//---------------------------------------------------------------------------
2566
2568{
2569 AUTO_TRACE();
2570 Token retval = Token::make_RetVal_OK();
2571 auto ns = AutoNodeStack(parser(),thisVariant());
2572
2573 // get next token
2574 Token tok=parser()->tokenizer.lex();
2575 // skip whitespace
2576 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2577 // should find a html tag now
2578 if (tok.is(TokenRetval::TK_HTMLTAG))
2579 {
2580 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2581 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2582 {
2583 // continue
2584 }
2585 else // found some other tag
2586 {
2587 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2588 "found <{}> instead!",parser()->context.token->name);
2589 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2590 goto enddesclist;
2591 }
2592 }
2593 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2594 {
2595 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2596 " for a html description title");
2597 goto enddesclist;
2598 }
2599 else // token other than html token
2600 {
2601 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found {} token instead!",
2602 tok.to_string());
2603 goto enddesclist;
2604 }
2605
2606 do
2607 {
2612 retval=dt->parse();
2613 if (retval.is(TokenRetval::RetVal_DescData))
2614 {
2615 retval=dd->parse();
2616 while (retval.is(TokenRetval::RetVal_DescData))
2617 {
2620 retval=dd->parse();
2621 }
2622 }
2623 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2624 {
2625 // error
2626 break;
2627 }
2628 } while (retval.is(TokenRetval::RetVal_DescTitle));
2629
2630 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2631 {
2632 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2633 }
2634
2635enddesclist:
2636
2637 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2638}
2639
2640//---------------------------------------------------------------------------
2641
2643{
2644 AUTO_TRACE();
2645 Token retval = Token::make_TK_NONE();
2646 auto ns = AutoNodeStack(parser(),thisVariant());
2647
2648 // parse one or more paragraphs
2649 bool isFirst=TRUE;
2650 DocPara *par=nullptr;
2651 do
2652 {
2654 par = children().get_last<DocPara>();
2655 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2656 retval=par->parse();
2657 }
2658 while (retval.is(TokenRetval::TK_NEWPARA));
2659 if (par) par->markLast();
2660
2661 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2662 return retval;
2663}
2664
2666{
2667 AUTO_TRACE();
2668 Token retval = Token::make_TK_NONE();
2669 auto ns = AutoNodeStack(parser(),thisVariant());
2670
2671 // parse one or more paragraphs
2672 bool isFirst=TRUE;
2673 DocPara *par=nullptr;
2674 do
2675 {
2677 par = children().get_last<DocPara>();
2678 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2679 retval=par->parse();
2680 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2681
2682 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2683 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2684 if (retval.is(TokenRetval::RetVal_ListItem))
2685 {
2686 break;
2687 }
2688 }
2689 while (!retval.is(TokenRetval::RetVal_CloseXml));
2690
2691 if (par) par->markLast();
2692
2693 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2694 return retval;
2695}
2696
2697//---------------------------------------------------------------------------
2698
2700{
2701 AUTO_TRACE();
2702 Token retval = Token::make_RetVal_OK();
2703 int num=1;
2704 auto ns = AutoNodeStack(parser(),thisVariant());
2705
2706 // get next token
2707 Token tok=parser()->tokenizer.lex();
2708 // skip whitespace and paragraph breaks
2709 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2710 // should find a html tag now
2711 if (tok.is(TokenRetval::TK_HTMLTAG))
2712 {
2713 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2714 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2715 {
2716 // ok, we can go on.
2717 }
2718 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2720 ) && parser()->context.token->endTag
2721 ) // found empty list
2722 {
2723 // add dummy item to obtain valid HTML
2725 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2726 retval = Token::make_RetVal_EndList();
2727 goto endlist;
2728 }
2729 else // found some other tag
2730 {
2731 // add dummy item to obtain valid HTML
2733 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2734 "found <{}{}> instead!",parser()->context.token->endTag?"/":"",parser()->context.token->name);
2735 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2736 goto endlist;
2737 }
2738 }
2739 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2740 {
2741 // add dummy item to obtain valid HTML
2743 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2744 " for a html list item");
2745 goto endlist;
2746 }
2747 else // token other than html token
2748 {
2749 // add dummy item to obtain valid HTML
2751 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found {} token instead!",
2752 tok.to_string());
2753 goto endlist;
2754 }
2755
2756 do
2757 {
2760 retval=li->parse();
2761 } while (retval.is(TokenRetval::RetVal_ListItem));
2762
2763 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2764 {
2765 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <{:c}l> block",
2766 m_type==Unordered ? 'u' : 'o');
2767 }
2768
2769endlist:
2770 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2771 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2772}
2773
2775{
2776 AUTO_TRACE();
2777 Token retval = Token::make_RetVal_OK();
2778 int num=1;
2779 auto ns = AutoNodeStack(parser(),thisVariant());
2780
2781 // get next token
2782 Token tok=parser()->tokenizer.lex();
2783 // skip whitespace and paragraph breaks
2784 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2785 // should find a html tag now
2786 if (tok.is(TokenRetval::TK_HTMLTAG))
2787 {
2788 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2789 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2790 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2791 {
2792 // ok, we can go on.
2793 }
2794 else // found some other tag
2795 {
2796 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2797 "found <{}> instead!",parser()->context.token->name);
2798 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2799 goto endlist;
2800 }
2801 }
2802 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2803 {
2804 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2805 " for a html list item");
2806 goto endlist;
2807 }
2808 else // token other than html token
2809 {
2810 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found {} token instead!",
2811 tok.to_string());
2812 goto endlist;
2813 }
2814
2815 do
2816 {
2819 retval=li->parseXml();
2820 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2821 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2822 } while (retval.is(TokenRetval::RetVal_ListItem));
2823
2824 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2825 {
2826 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"{}\"> block",
2827 m_type==Unordered ? "bullet" : "number");
2828 }
2829
2830endlist:
2831 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2832 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2833 Token::make_RetVal_OK() : retval;
2834}
2835
2836//--------------------------------------------------------------------------
2837
2839{
2840 AUTO_TRACE();
2841 Token retval = Token::make_TK_NONE();
2842 auto ns = AutoNodeStack(parser(),thisVariant());
2843
2844 // parse one or more paragraphs
2845 bool isFirst=TRUE;
2846 DocPara *par=nullptr;
2847 do
2848 {
2850 par = children().get_last<DocPara>();
2851 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2852 retval=par->parse();
2853 }
2854 while (retval.is(TokenRetval::TK_NEWPARA));
2855 if (par) par->markLast();
2856
2857 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2858 {
2859 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2860 }
2861
2862 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2863 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2864}
2865
2866//---------------------------------------------------------------------------
2867
2869{
2870 AUTO_TRACE();
2871 Token retval = Token::make_TK_NONE();
2872 auto ns = AutoNodeStack(parser(),thisVariant());
2873
2874 // parse one or more paragraphs
2875 bool isFirst=TRUE;
2876 DocPara *par=nullptr;
2877 do
2878 {
2880 par = children().get_last<DocPara>();
2881 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2882 retval=par->parse();
2883 }
2884 while (retval.is(TokenRetval::TK_NEWPARA));
2885 if (par) par->markLast();
2886
2887 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2888 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2889}
2890
2891//---------------------------------------------------------------------------
2892
2897
2898
2900{
2901 auto ns = AutoNodeStack(parser(),thisVariant());
2903 DocPara *par = &std::get<DocPara>(*m_paragraph);
2904 Token rv=par->parse();
2905 par->markFirst();
2906 par->markLast();
2907 return rv;
2908}
2909
2910//--------------------------------------------------------------------------
2911
2913{
2914 auto ns = AutoNodeStack(parser(),thisVariant());
2915 Token rv = Token::make_TK_NONE();
2916 do
2917 {
2920 rv=li->parse();
2921 } while (rv.is(TokenRetval::RetVal_ListItem));
2922 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2923}
2924
2925//--------------------------------------------------------------------------
2926
2931
2933{
2934 AUTO_TRACE();
2935 Token retval = Token::make_RetVal_OK();
2936 auto ns = AutoNodeStack(parser(),thisVariant());
2937
2938 // first parse any number of paragraphs
2939 bool isFirst=TRUE;
2940 DocPara *lastPar=nullptr;
2941 do
2942 {
2944 DocPara *par = children().get_last<DocPara>();
2945 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2946 retval=par->parse();
2947 if (!par->isEmpty())
2948 {
2949 if (lastPar) lastPar->markLast(FALSE);
2950 lastPar=par;
2951 }
2952 else
2953 {
2954 children().pop_back();
2955 }
2956 // next paragraph should be more indented than the - marker to belong
2957 // to this item
2958 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2959 if (lastPar) lastPar->markLast();
2960
2961 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2962 return retval;
2963}
2964
2965//--------------------------------------------------------------------------
2966
2973
2975{
2976 AUTO_TRACE();
2977 Token retval = Token::make_RetVal_OK();
2978 int num=1;
2979 auto ns = AutoNodeStack(parser(),thisVariant());
2981 // first item or sub list => create new list
2982 do
2983 {
2984 switch (parser()->context.token->id)
2985 {
2986 case -1:
2987 break;
2988 case DocAutoList::Unchecked: // unchecked
2989 case DocAutoList::Checked_x: // checked with x
2990 case DocAutoList::Checked_X: // checked with X
2991 num = parser()->context.token->id;
2992 break;
2993 default: // explicitly numbered list
2994 num=parser()->context.token->id; // override num with real number given
2995 break;
2996 }
2997
2999 retval = children().get_last<DocAutoListItem>()->parse();
3000 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
3001 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
3002 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
3003 // qPrint(parser()->context.token->name));
3004 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
3005 }
3006 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
3007 m_indent==parser()->context.token->indent && // at same indent level
3008 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
3009 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
3010 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
3011 );
3012
3014 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3015 return retval;
3016}
3017
3018//--------------------------------------------------------------------------
3019
3021{
3022 AUTO_TRACE();
3023 auto ns = AutoNodeStack(parser(),thisVariant());
3025 Token tok = parser()->tokenizer.lex();
3026 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
3027 {
3028 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
3029 {
3030 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
3031 }
3032 tok = parser()->tokenizer.lex();
3033 }
3036}
3037
3039{
3041 parser()->pushContext(); // this will create a new parser->context.token
3043 parser()->popContext(); // this will restore the old parser->context.token
3047}
3048
3049//--------------------------------------------------------------------------
3050
3055
3057{
3058 return m_title && std::get<DocTitle>(*m_title).hasTitle();
3059}
3060
3061Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
3062{
3063 AUTO_TRACE();
3064 auto ns = AutoNodeStack(parser(),thisVariant());
3065
3066 // handle case for user defined title
3067 if (userTitle)
3068 {
3070 std::get_if<DocTitle>(m_title.get())->parse();
3071 }
3072
3073 // add new paragraph as child
3074 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3075 {
3076 std::get<DocPara>(children().back()).markLast(FALSE);
3077 }
3078 bool markFirst = children().empty();
3079 if (needsSeparator)
3080 {
3082 }
3084 DocPara *par = children().get_last<DocPara>();
3085 if (markFirst)
3086 {
3087 par->markFirst();
3088 }
3089 par->markLast();
3090
3091 // parse the contents of the paragraph
3092 Token retval = par->parse();
3093
3094 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3095 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
3096}
3097
3099{
3100 AUTO_TRACE();
3101 auto ns = AutoNodeStack(parser(),thisVariant());
3102
3104 DocTitle *title = &std::get<DocTitle>(*m_title);
3105 title->parseFromString(thisVariant(),parser()->context.token->name);
3106
3107 QCString text = parser()->context.token->text;
3108 parser()->pushContext(); // this will create a new parser->context.token
3110 parser()->popContext(); // this will restore the old parser->context.token
3111
3112 return Token::make_RetVal_OK();
3113}
3114
3116{
3117 AUTO_TRACE();
3118 auto ns = AutoNodeStack(parser(),thisVariant());
3119
3120 Token retval = Token::make_RetVal_OK();
3121 for (;;)
3122 {
3123 // add new paragraph as child
3124 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3125 {
3126 std::get<DocPara>(children().back()).markLast(false);
3127 }
3128 bool markFirst = children().empty();
3130 DocPara *par = children().get_last<DocPara>();
3131 if (markFirst)
3132 {
3133 par->markFirst();
3134 }
3135 par->markLast();
3136
3137 // parse the contents of the paragraph
3138 retval = par->parse();
3139 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3140 if (retval.is(TokenRetval::RetVal_CloseXml))
3141 {
3142 retval = Token::make_RetVal_OK();
3143 break;
3144 }
3145 }
3146
3147 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3148 return retval;
3149}
3150
3152{
3153 DocPara *p=nullptr;
3154 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
3155 {
3157 p = children().get_last<DocPara>();
3158 }
3159 else
3160 {
3161 // Comma-separate <seealso> links.
3162 p->injectToken(Token::make_TK_WORD(),",");
3163 p->injectToken(Token::make_TK_WHITESPACE()," ");
3164 }
3165
3167 p->injectToken(Token::make_TK_LNKWORD(),word);
3169}
3170
3172{
3173 switch (m_type)
3174 {
3175 case Unknown: break;
3176 case See: return "see";
3177 case Return: return "return";
3178 case Author: // fall through
3179 case Authors: return "author";
3180 case Version: return "version";
3181 case Since: return "since";
3182 case Date: return "date";
3183 case Note: return "note";
3184 case Warning: return "warning";
3185 case Pre: return "pre";
3186 case Post: return "post";
3187 case Copyright: return "copyright";
3188 case Invar: return "invariant";
3189 case Remark: return "remark";
3190 case Attention: return "attention";
3191 case Important: return "important";
3192 case User: return "user";
3193 case Rcs: return "rcs";
3194 }
3195 return "unknown";
3196}
3197
3198//--------------------------------------------------------------------------
3199
3201{
3202 AUTO_TRACE();
3203 Token retval = Token::make_RetVal_OK();
3204 auto ns = AutoNodeStack(parser(),thisVariant());
3205 DocPara *par=nullptr;
3206 QCString saveCmdName = cmdName;
3207
3208 Token tok=parser()->tokenizer.lex();
3209 if (!tok.is(TokenRetval::TK_WHITESPACE))
3210 {
3211 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3212 saveCmdName);
3213 retval = Token::make_RetVal_EndParBlock();
3214 goto endparamlist;
3215 }
3217 tok=parser()->tokenizer.lex();
3218 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3219 {
3221 {
3222 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3223 if (typeSeparator!=-1)
3224 {
3225 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3226 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3229 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3230 {
3231 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3232 }
3233 }
3234 else
3235 {
3238 }
3239 }
3240 else if (m_type==DocParamSect::RetVal)
3241 {
3244 }
3245 //m_params.append(parser()->context.token->name);
3247 tok=parser()->tokenizer.lex();
3248 }
3250 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3251 {
3252 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3253 "argument of command {}",saveCmdName);
3254 retval = Token::make_RetVal_EndParBlock();
3255 goto endparamlist;
3256 }
3257 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3258 {
3259 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3260 {
3261 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3262 "argument of command {}",tok.to_string(),saveCmdName);
3263 }
3264 retval = Token::make_RetVal_EndParBlock();
3265 goto endparamlist;
3266 }
3267
3269 par = m_paragraphs.get_last<DocPara>();
3270 retval = par->parse();
3271 par->markFirst();
3272 par->markLast();
3273
3274endparamlist:
3275 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3276 return retval;
3277}
3278
3280{
3281 AUTO_TRACE();
3282 Token retval = Token::make_RetVal_OK();
3283 auto ns = AutoNodeStack(parser(),thisVariant());
3284
3285 parser()->context.token->name = paramName;
3287 {
3290 }
3291 else if (m_type==DocParamSect::RetVal)
3292 {
3295 }
3296
3298
3299 do
3300 {
3302 DocPara *par = m_paragraphs.get_last<DocPara>();
3303 retval = par->parse();
3304 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3305 // after </para> and before </param>
3306 {
3307 m_paragraphs.pop_back();
3308 break;
3309 }
3310 else // append the paragraph to the list
3311 {
3312 if (!m_paragraphs.empty())
3313 {
3314 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3315 }
3316 bool markFirst = m_paragraphs.empty();
3317 par = &std::get<DocPara>(m_paragraphs.back());
3318 if (markFirst)
3319 {
3320 par->markFirst();
3321 }
3322 par->markLast();
3323 }
3324
3325 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3326
3327 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3328 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3329 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3330 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3331
3332 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3333 {
3334 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3335 }
3336 else
3337 {
3338 retval = Token::make_RetVal_OK();
3339 }
3340
3341 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3342 return retval;
3343}
3344
3345//--------------------------------------------------------------------------
3346
3347Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3348{
3349 AUTO_TRACE();
3350 Token retval = Token::make_RetVal_OK();
3351 auto ns = AutoNodeStack(parser(),thisVariant());
3352
3353 if (d!=Unspecified)
3354 {
3356 }
3357
3358 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3359 {
3360 DocParamList &lastPl = std::get<DocParamList>(children().back());
3361 lastPl.markLast(false);
3362 }
3363 bool markFirst = children().empty();
3366 if (markFirst)
3367 {
3368 pl->markFirst();
3369 }
3370 pl->markLast();
3371 if (xmlContext)
3372 {
3373 retval = pl->parseXml(cmdName);
3374 }
3375 else
3376 {
3377 retval = pl->parse(cmdName);
3378 }
3379 if (retval.is(TokenRetval::RetVal_EndParBlock))
3380 {
3381 retval = Token::make_RetVal_OK();
3382 }
3383
3384 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3385 return retval;
3386}
3387
3388//--------------------------------------------------------------------------
3389
3395
3397{
3398 AUTO_TRACE();
3399 DocSimpleSect *ss=nullptr;
3400 bool needsSeparator = FALSE;
3401 if (!children().empty() && // has previous element
3402 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3403 ss->type()==t && // of same type
3404 t!=DocSimpleSect::User) // but not user defined
3405 {
3406 // append to previous section
3407 needsSeparator = TRUE;
3408 }
3409 else // start new section
3410 {
3413 }
3414 Token rv = Token::make_RetVal_OK();
3415 if (xmlContext)
3416 {
3417 return ss->parseXml();
3418 }
3419 else
3420 {
3421 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3422 }
3423 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3424}
3425
3428 bool xmlContext=FALSE,
3429 int direction=DocParamSect::Unspecified)
3430{
3431 AUTO_TRACE();
3432 DocParamSect *ps = nullptr;
3433 if (!children().empty() && // previous element
3434 (ps=children().get_last<DocParamSect>()) && // was a param sect
3435 ps->type()==t) // of same type
3436 { // append to previous section ps
3437 }
3438 else // start new section
3439 {
3441 ps = children().get_last<DocParamSect>();
3442 }
3443 Token rv=ps->parse(cmdName,xmlContext,
3444 static_cast<DocParamSect::Direction>(direction));
3445 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3446 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3447}
3448
3449void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3450{
3451 AUTO_TRACE();
3452 QCString saveCmdName = cmdName;
3453 // get the argument of the cite command.
3454 Token tok=parser()->tokenizer.lex();
3455
3456 CiteInfoOption option;
3457 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3458 {
3460 parser()->tokenizer.lex();
3461 StringVector optList=split(parser()->context.token->name.str(),",");
3462 for (auto const &opt : optList)
3463 {
3464 if (opt == "number")
3465 {
3466 if (!option.isUnknown())
3467 {
3468 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3469 }
3470 else
3471 {
3472 option = CiteInfoOption::makeNumber();
3473 }
3474 }
3475 else if (opt == "year")
3476 {
3477 if (!option.isUnknown())
3478 {
3479 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3480 }
3481 else
3482 {
3483 option = CiteInfoOption::makeYear();
3484 }
3485 }
3486 else if (opt == "shortauthor")
3487 {
3488 if (!option.isUnknown())
3489 {
3490 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3491 }
3492 else
3493 {
3495 }
3496 }
3497 else if (opt == "nopar")
3498 {
3499 option.setNoPar();
3500 }
3501 else if (opt == "nocite")
3502 {
3503 option.setNoCite();
3504 }
3505 else
3506 {
3507 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unknown option specified with \\{}, discarding '{}'", saveCmdName, opt);
3508 }
3509 }
3510
3511 if (option.isUnknown()) option.changeToNumber();
3512
3514 tok=parser()->tokenizer.lex();
3515 if (!tok.is(TokenRetval::TK_WHITESPACE))
3516 {
3517 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3518 saveCmdName);
3519 return;
3520 }
3521 }
3522 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3523 {
3524 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3525 cmdChar,saveCmdName);
3526 return;
3527 }
3528 else
3529 {
3530 option = CiteInfoOption::makeNumber();
3531 }
3532
3534 tok=parser()->tokenizer.lex();
3535 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3536 {
3537 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"THE ONE unexpected end of comment block while parsing the "
3538 "argument of command '{:c}{}'",cmdChar,saveCmdName);
3539 return;
3540 }
3541 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3542 {
3543 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3544 tok.to_string(),cmdChar,saveCmdName);
3545 return;
3546 }
3550
3552}
3553
3554void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3555{
3556 AUTO_TRACE();
3557 // get the argument of the emoji command.
3558 Token tok=parser()->tokenizer.lex();
3559 if (!tok.is(TokenRetval::TK_WHITESPACE))
3560 {
3561 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3562 cmdChar,cmdName);
3563 return;
3564 }
3566 tok=parser()->tokenizer.lex();
3567 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3568 {
3569 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3570 "argument of command '{:c}{}'",cmdChar,cmdName);
3572 return;
3573 }
3574 else 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);
3579 return;
3580 }
3583}
3584
3585void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3586{
3587 // get the argument of the cite command.
3588 Token tok=parser()->tokenizer.lex();
3589 if (!tok.is(TokenRetval::TK_WHITESPACE))
3590 {
3591 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3592 cmdChar,cmdName);
3593 return;
3594 }
3596 tok=parser()->tokenizer.lex();
3597 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3598 {
3599 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3600 "argument of command '{:c}{}'",cmdChar,cmdName);
3601 return;
3602 }
3603 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3604 {
3605 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3606 tok.to_string(),cmdChar,cmdName);
3607 return;
3608 }
3609 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3610 if (opt)
3611 {
3612 QCString optionValue;
3613 switch (opt->kind())
3614 {
3616 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3617 break;
3619 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3620 break;
3622 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3623 break;
3625 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3626 break;
3628 {
3629 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3630 optionValue="";
3631 if (!lst->empty())
3632 {
3633 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3634 static const reg::Ex marker(R"(@(\d+))");
3635 reg::Iterator it(lstFormat,marker);
3637 size_t index=0;
3638 // now replace all markers with the real text
3639 for ( ; it!=end ; ++it)
3640 {
3641 const auto &match = *it;
3642 size_t newIndex = match.position();
3643 size_t matchLen = match.length();
3644 optionValue += lstFormat.substr(index,newIndex-index);
3645 unsigned long entryIndex = std::stoul(match[1].str());
3646 if (entryIndex<(unsigned long)lst->size())
3647 {
3648 optionValue += lst->at(entryIndex);
3649 }
3650 index=newIndex+matchLen;
3651 }
3652 optionValue+=lstFormat.substr(index);
3653 }
3654 }
3655 break;
3657 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3658 cmdChar,cmdName,parser()->context.token->name);
3659 break;
3661 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3662 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3663 cmdChar,cmdName,parser()->context.token->name);
3664 break;
3666 // nothing to show here
3667 break;
3668 }
3669 if (!optionValue.isEmpty())
3670 {
3671 children().append<DocWord>(parser(),thisVariant(),optionValue);
3672 }
3673 }
3674 else
3675 {
3676 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3677 cmdChar,cmdName,parser()->context.token->name);
3679 }
3681}
3682
3684{
3685 AUTO_TRACE();
3686 Token retval=parser()->tokenizer.lex();
3687 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3689 retval=parser()->tokenizer.lex();
3690 if (retval.is(TokenRetval::RetVal_OK))
3691 {
3695 if (!ref->parse())
3696 {
3697 children().pop_back();
3698 }
3699 }
3701 return retval;
3702}
3703
3704void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3705{
3706 AUTO_TRACE();
3707 QCString fmt;
3708 QCString date;
3709 Token tok=parser()->tokenizer.lex();
3710 if (!tok.is(TokenRetval::TK_WHITESPACE))
3711 {
3712 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3713 cmdChar,cmdName);
3714 return;
3715 }
3717 tok = parser()->tokenizer.lex();
3718 if (!tok.is(TokenRetval::TK_WORD))
3719 {
3720 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3721 cmdChar,cmdName);
3723 return;
3724 }
3725 fmt = parser()->context.token->name;
3726
3728 tok = parser()->tokenizer.lex();
3729
3730 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3731 QCString specDate = specDateRaw.stripWhiteSpace();
3732 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3733 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3734 {
3735 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3736 cmdChar,cmdName);
3738 return;
3739 }
3740
3741 std::tm dat{};
3742 int specFormat=0;
3743 QCString err = dateTimeFromString(specDate,dat,specFormat);
3744 if (!err.isEmpty())
3745 {
3746 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3747 cmdChar,cmdName,err);
3749 return;
3750 }
3751
3752 int usedFormat=0;
3753 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3754
3755 // warn the user if the format contains markers that are not explicitly filled in
3756 for (int i=0;i<SF_NumBits;i++)
3757 {
3758 int bitMask = 1<<i;
3759 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3760 {
3761 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.",
3762 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3763 }
3764 }
3765
3766 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3767 if (specDateOnlyWS) // specDate is only whitespace
3768 {
3770 }
3772}
3773
3774void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3775{
3776 AUTO_TRACE();
3778 Token tok = parser()->tokenizer.lex();
3779 if (!tok.is(TokenRetval::TK_WORD))
3780 {
3781 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
3782 cmdChar,cmdName);
3783 return;
3784 }
3786}
3787
3788void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3789{
3790 AUTO_TRACE();
3791 Token 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 '{:c}{}' command",
3795 cmdChar,cmdName);
3796 return;
3797 }
3799 tok=parser()->tokenizer.lex();
3801 if (!tok.is(TokenRetval::TK_WORD))
3802 {
3803 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3804 tok.to_string(),cmdChar,cmdName);
3805 return;
3806 }
3809}
3810
3811
3813{
3814 AUTO_TRACE("cmdName={}",cmdName);
3815 QCString saveCmdName = cmdName;
3816 Token tok=parser()->tokenizer.lex();
3817 if (!tok.is(TokenRetval::TK_WHITESPACE))
3818 {
3819 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3820 saveCmdName);
3821 return;
3822 }
3824 tok=parser()->tokenizer.lex();
3826 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3827 {
3828 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3829 "argument of command {}", saveCmdName);
3830 return;
3831 }
3832 else if (!tok.is(TokenRetval::TK_WORD))
3833 {
3834 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3835 tok.to_string(),saveCmdName);
3836 return;
3837 }
3838 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3839 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3840 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3841 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3842 //TODO get from context the stripCodeComments()
3843 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3847 stripCodeComments,
3850 );
3852 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3853 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3854 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3855 bool isFirst = !n1 || // no last node
3856 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3857 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3858 op->markFirst(isFirst);
3859 op->markLast(true);
3860 if (n1_docIncOp)
3861 {
3862 n1_docIncOp->markLast(false);
3863 }
3864 else if (n1_docWs && n2_docIncOp)
3865 {
3866 n2_docIncOp->markLast(false);
3867 }
3868 op->parse();
3869}
3870
3871template<class T>
3872void DocPara::handleFile(const QCString &cmdName)
3873{
3874 AUTO_TRACE("cmdName={}",cmdName);
3875 QCString saveCmdName = cmdName;
3876 Token tok=parser()->tokenizer.lex();
3877 if (!tok.is(TokenRetval::TK_WHITESPACE))
3878 {
3879 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3880 saveCmdName);
3881 return;
3882 }
3884 tok=parser()->tokenizer.lex();
3886 if (!tok.is(TokenRetval::TK_WORD))
3887 {
3888 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3889 tok.to_string(),saveCmdName);
3890 return;
3891 }
3892 QCString name = parser()->context.token->name;
3893 children().append<T>(parser(),thisVariant(),name,
3897 auto df = children().get_last<T>();
3898 if (!df->parse())
3899 {
3900 children().pop_back();
3901 }
3902}
3903
3910
3911void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3912{
3913 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3914 QCString saveCmdName = cmdName;
3915 Token tok=parser()->tokenizer.lex();
3916 if (!tok.is(TokenRetval::TK_WHITESPACE))
3917 {
3918 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3919 saveCmdName);
3920 return;
3921 }
3923 tok=parser()->tokenizer.lex();
3924 if (!tok.is(TokenRetval::TK_WORD))
3925 {
3926 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3927 tok.to_string(),saveCmdName);
3928 return;
3929 }
3930 if (saveCmdName == "javalink")
3931 {
3933 parser()->context.nodeStack.size(),
3934 DocStyleChange::Code,cmdName,TRUE);
3935 }
3938 DocLink *lnk = children().get_last<DocLink>();
3939 if (saveCmdName == "javalink")
3940 {
3942 parser()->context.nodeStack.size(),
3943 DocStyleChange::Code,cmdName,FALSE);
3944 }
3945 QCString leftOver = lnk->parse(isJavaLink);
3946 if (!leftOver.isEmpty())
3947 {
3948 children().append<DocWord>(parser(),thisVariant(),leftOver);
3949 }
3950}
3951
3952void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3953{
3954 AUTO_TRACE("cmdName={}",cmdName);
3955 QCString saveCmdName = cmdName;
3956 Token tok=parser()->tokenizer.lex();
3957 if (!tok.is(TokenRetval::TK_WHITESPACE))
3958 {
3959 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3960 cmdChar,qPrint(saveCmdName));
3961 return;
3962 }
3964 tok=parser()->tokenizer.lex(); // get the reference id
3965 if (!tok.is(TokenRetval::TK_WORD))
3966 {
3967 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3968 tok.to_string(),cmdChar,saveCmdName);
3969 goto endref;
3970 }
3974 children().get_last<DocRef>()->parse();
3975endref:
3977}
3978
3980{
3981 AUTO_TRACE("cmdName={}",cmdName);
3982 QCString saveCmdName = cmdName;
3983 Token tok=parser()->tokenizer.lex();
3984 bool isBlock = false;
3985 bool trimLeft = false;
3986 bool localScope = false;
3987 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3988 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3989 {
3991 parser()->tokenizer.lex();
3993 StringVector optList=split(parser()->context.token->name.str(),",");
3994 auto contains = [&optList](const char *kw)
3995 {
3996 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
3997 };
3998 localScope = contains("local");
3999 if (contains("nostrip"))
4000 {
4001 stripCodeComments = false;
4002 }
4003 else if (contains("strip"))
4004 {
4005 stripCodeComments = true;
4006 }
4007 if (t==DocInclude::Snippet && contains("trimleft"))
4008 {
4009 trimLeft = true;
4010 }
4011
4012 if (contains("lineno"))
4013 {
4017 }
4018 tok=parser()->tokenizer.lex();
4019 if (!tok.is(TokenRetval::TK_WHITESPACE))
4020 {
4021 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4022 saveCmdName);
4023 return;
4024 }
4025 }
4026 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
4027 {
4029 parser()->tokenizer.lex();
4030 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
4032 parser()->tokenizer.lex();
4033 }
4034 else if (!tok.is(TokenRetval::TK_WHITESPACE))
4035 {
4036 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4037 saveCmdName);
4038 return;
4039 }
4041 tok=parser()->tokenizer.lex();
4043 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4044 {
4045 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4046 "argument of command {}",saveCmdName);
4047 return;
4048 }
4049 else if (!tok.is(TokenRetval::TK_WORD))
4050 {
4051 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
4052 tok.to_string(),saveCmdName);
4053 return;
4054 }
4055 QCString fileName = parser()->context.token->name;
4056 QCString blockId;
4058 {
4059 if (fileName == "this") fileName=parser()->context.fileName;
4061 tok=parser()->tokenizer.lex();
4063 if (!tok.is(TokenRetval::TK_WORD))
4064 {
4065 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
4066 tok.to_string(),saveCmdName);
4067 return;
4068 }
4069 blockId = "["+parser()->context.token->name+"]";
4070 }
4071
4073 thisVariant(),
4074 fileName,
4075 localScope ? parser()->context.context : "",
4076 t,
4077 stripCodeComments,
4080 blockId,isBlock,trimLeft);
4082}
4083
4084void DocPara::handleSection(char cmdChar,const QCString &cmdName)
4085{
4086 AUTO_TRACE("cmdName={}",cmdName);
4087 QCString saveCmdName = cmdName;
4088 // get the argument of the section command.
4089 Token tok=parser()->tokenizer.lex();
4090 if (!tok.is(TokenRetval::TK_WHITESPACE))
4091 {
4092 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
4093 cmdChar,saveCmdName);
4094 return;
4095 }
4096 tok=parser()->tokenizer.lex();
4097 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4098 {
4099 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4100 "argument of command '{:c}{}'", cmdChar,saveCmdName);
4101 return;
4102 }
4103 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
4104 {
4105 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
4106 tok.to_string(),cmdChar,saveCmdName);
4107 return;
4108 }
4111 parser()->tokenizer.lex();
4113}
4114
4115Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
4116{
4117 AUTO_TRACE();
4118 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
4119 Token retval = children().get_last<DocHtmlHeader>()->parse();
4120 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
4121}
4122
4123// For XML tags whose content is stored in attributes rather than
4124// contained within the element, we need a way to inject the attribute
4125// text into the current paragraph.
4126bool DocPara::injectToken(Token tok,const QCString &tokText)
4127{
4128 AUTO_TRACE();
4129 parser()->context.token->name = tokText;
4130 return parser()->defaultHandleToken(thisVariant(),tok,children());
4131}
4132
4134{
4135 AUTO_TRACE();
4136 Token retval = parser()->tokenizer.lex();
4137 QCString lang = parser()->context.token->name;
4138 if (!lang.isEmpty() && lang.at(0)!='.')
4139 {
4140 lang="."+lang;
4141 }
4142 if (parser()->context.xmlComment)
4143 {
4144 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
4145 }
4146 // search for the first non-whitespace line, index is stored in li
4147 size_t i=0,li=0,l=parser()->context.token->verb.length();
4148 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
4149 {
4150 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
4151 i++;
4152 }
4155 stripIndentation(parser()->context.token->verb.mid(li)),
4159 FALSE,lang);
4160 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4161 {
4162 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
4163 }
4165 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4166 return retval;
4167}
4168
4170{
4171 if (parser()->context.memberDef) // inheriting docs from a member
4172 {
4173 const MemberDef *reMd = parser()->context.memberDef->reimplements();
4174 if (reMd) // member from which was inherited.
4175 {
4176 const MemberDef *thisMd = parser()->context.memberDef;
4177 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
4178 parser()->pushContext();
4179 parser()->context.scope=reMd->getOuterScope();
4180 if (parser()->context.scope!=Doxygen::globalScope)
4181 {
4183 }
4184 parser()->context.memberDef=reMd;
4185 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
4186 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
4187 parser()->context.copyStack.push_back(reMd);
4190 parser()->context.copyStack.pop_back();
4191 auto hasParamCommand = parser()->context.hasParamCommand;
4192 auto hasReturnCommand = parser()->context.hasReturnCommand;
4193 auto retvalsFound = parser()->context.retvalsFound;
4194 auto paramsFound = parser()->context.paramsFound;
4195 parser()->popContext();
4196 parser()->context.hasParamCommand = hasParamCommand;
4197 parser()->context.hasReturnCommand = hasReturnCommand;
4198 parser()->context.retvalsFound = retvalsFound;
4199 parser()->context.paramsFound = paramsFound;
4200 parser()->context.memberDef = thisMd;
4201 }
4202 }
4203}
4204
4205
4206Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
4207{
4208 AUTO_TRACE("cmdName={}",cmdName);
4209 Token retval = Token::make_RetVal_OK();
4210 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
4211 switch (cmdId)
4212 {
4214 {
4215 std::string str{cmdChar};
4216 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
4217 if (isAliasCmd(cmdName.view()))
4218 {
4219 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
4220 }
4221 else
4222 {
4223 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
4224 }
4225 }
4226 break;
4229 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4231 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4232 break;
4235 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4237 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4238 break;
4241 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4243 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4244 break;
4247 break;
4250 break;
4253 break;
4256 break;
4259 break;
4262 break;
4265 break;
4268 break;
4271 break;
4274 break;
4278 break;
4283 break;
4286 break;
4289 break;
4292 break;
4295 break;
4298 break;
4301 break;
4304 break;
4309 break;
4313 break;
4316 break;
4319 break;
4322 break;
4325 break;
4328 break;
4331 break;
4334 break;
4337 break;
4340 break;
4343 break;
4346 break;
4349 break;
4352 break;
4355 break;
4358 break;
4360 {
4362 retval = children().get_last<DocSimpleList>()->parse();
4363 }
4364 break;
4366 {
4367 handleSection(cmdChar,cmdName);
4368 retval = Token::make_RetVal_Section();
4369 }
4370 break;
4372 {
4373 handleSection(cmdChar,cmdName);
4374 retval = Token::make_RetVal_Subsection();
4375 }
4376 break;
4378 {
4379 handleSection(cmdChar,cmdName);
4380 retval = Token::make_RetVal_Subsubsection();
4381 }
4382 break;
4384 {
4385 handleSection(cmdChar,cmdName);
4386 retval = Token::make_RetVal_Paragraph();
4387 }
4388 break;
4390 {
4391 handleSection(cmdChar,cmdName);
4392 retval = Token::make_RetVal_SubParagraph();
4393 }
4394 break;
4396 {
4397 handleSection(cmdChar,cmdName);
4398 retval = Token::make_RetVal_SubSubParagraph();
4399 }
4400 break;
4402 {
4404 retval = handleStartCode();
4405 }
4406 break;
4408 {
4410 retval = handleStartCode();
4411 }
4412 break;
4414 {
4416 retval = parser()->tokenizer.lex();
4418 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4419 {
4420 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4421 }
4423 }
4424 break;
4426 {
4428 retval = parser()->tokenizer.lex();
4430 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4431 {
4432 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4433 }
4435 }
4436 break;
4438 {
4440 retval = parser()->tokenizer.lex();
4442 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4443 {
4444 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4445 }
4447 }
4448 break;
4450 {
4452 retval = parser()->tokenizer.lex();
4454 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4455 {
4456 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4457 }
4459 }
4460 break;
4462 {
4464 retval = parser()->tokenizer.lex();
4466 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4467 {
4468 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4469 }
4471 }
4472 break;
4474 {
4476 retval = parser()->tokenizer.lex();
4478 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4479 {
4480 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4481 }
4483 }
4484 break;
4486 {
4489 parser()->tokenizer.lex();
4490
4491 QCString fullMatch = parser()->context.token->verb;
4492 int idx = fullMatch.find('{');
4493 int idxEnd = fullMatch.find("}",idx+1);
4494 StringVector optList;
4495 if (idx != -1) // options present
4496 {
4497 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4498 optList = split(optStr.str(),",");
4499 for (const auto &opt : optList)
4500 {
4501 if (opt.empty()) continue;
4502 QCString locOpt(opt);
4503 locOpt = locOpt.stripWhiteSpace().lower();
4504 if (locOpt == "code")
4505 {
4507 }
4508 else if (!locOpt.isEmpty())
4509 {
4510 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4511 }
4512 }
4513 }
4514
4516 retval = parser()->tokenizer.lex();
4518 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4519 {
4520 if (t == DocVerbatim::JavaDocCode)
4521 {
4522 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4523 }
4524 else
4525 {
4526 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4527 }
4528 }
4530 }
4531 break;
4534 {
4535 if (cmdId == CommandType::CMD_VERBATIM)
4536 {
4538 }
4539 else
4540 {
4542 }
4543 retval = parser()->tokenizer.lex();
4545 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4546 {
4547 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4548 }
4550 }
4551 break;
4553 {
4562 QCString width,height;
4563 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4565 retval = parser()->tokenizer.lex();
4566 dv->setText(parser()->context.token->verb);
4567 dv->setWidth(width);
4568 dv->setHeight(height);
4569 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4570 if (!Config_getBool(HAVE_DOT))
4571 {
4572 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4573 children().pop_back();
4574 }
4575 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4576 {
4577 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4578 }
4580 }
4581 break;
4583 {
4592 QCString width,height;
4593 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4595 retval = parser()->tokenizer.lex();
4596 dv->setText(parser()->context.token->verb);
4597 dv->setWidth(width);
4598 dv->setHeight(height);
4599 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4600 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4601 {
4602 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4603 }
4605 }
4606 break;
4608 {
4609 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4611 parser()->tokenizer.lex();
4612 QCString fullMatch = parser()->context.token->sectionId;
4613 QCString sectionId = "";
4614 int idx = fullMatch.find('{');
4615 int idxEnd = fullMatch.find("}",idx+1);
4616 StringVector optList;
4617 QCString engine;
4618 if (idx != -1) // options present
4619 {
4620 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4621 optList = split(optStr.str(),",");
4622 for (const auto &opt : optList)
4623 {
4624 if (opt.empty()) continue;
4625 bool found = false;
4626 QCString locOpt(opt);
4627 locOpt = locOpt.stripWhiteSpace().lower();
4628 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4629 {
4630 if (!engine.isEmpty())
4631 {
4632 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4633 }
4634 engine = locOpt;
4635 found = true;
4636 }
4637 if (!found)
4638 {
4639 if (sectionId.isEmpty())
4640 {
4641 sectionId = opt;
4642 }
4643 else
4644 {
4645 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4646 }
4647 }
4648 }
4649 }
4650 else
4651 {
4652 sectionId = parser()->context.token->sectionId;
4653 }
4654 if (engine.isEmpty()) engine = "uml";
4655
4656 if (sectionId.isEmpty())
4657 {
4659 retval = parser()->tokenizer.lex();
4660 assert(retval.is(TokenRetval::RetVal_OK));
4661
4662 sectionId = parser()->context.token->sectionId;
4663 sectionId = sectionId.stripWhiteSpace();
4664 }
4665
4666 QCString plantFile(sectionId);
4671 FALSE,plantFile);
4673 dv->setEngine(engine);
4675 QCString width,height;
4676 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4678 retval = parser()->tokenizer.lex();
4679 int line = 0;
4680 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4681 if (engine == "ditaa")
4682 {
4683 dv->setUseBitmap(true);
4684 }
4685 else if (engine == "uml")
4686 {
4687 int i = trimmedVerb.find('\n');
4688 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4689 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4690 }
4691 dv->setText(trimmedVerb);
4692 dv->setWidth(width);
4693 dv->setHeight(height);
4694 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4695 if (jarPath.isEmpty())
4696 {
4697 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4698 children().pop_back();
4699 }
4700 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4701 {
4702 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4703 }
4705 }
4706 break;
4708 retval = Token::make_RetVal_EndParBlock();
4709 break;
4725 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4726 break;
4728 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4729 break;
4731 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4732 break;
4734 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4735 break;
4738 break;
4740 retval = handleXRefItem();
4741 break;
4743 {
4745 }
4746 break;
4749 {
4751 }
4752 break;
4754 {
4756 }
4757 break;
4759 {
4763 retval = children().get_last<DocIndexEntry>()->parse();
4764 }
4765 break;
4767 retval = Token::make_RetVal_Internal();
4768 break;
4770 retval = Token::make_RetVal_EndInternal();
4771 break;
4773 {
4775 retval = children().get_last<DocParBlock>()->parse();
4776 }
4777 break;
4778 case CommandType::CMD_COPYDOC: // fall through
4779 case CommandType::CMD_COPYBRIEF: // fall through
4781 //retval = Token::make_RetVal_CopyDoc();
4782 // these commands should already be resolved by processCopyDoc()
4783 break;
4786 break;
4789 break;
4792 break;
4795 break;
4798 break;
4801 break;
4804 break;
4807 break;
4810 break;
4813 break;
4816 break;
4819 break;
4822 break;
4825 break;
4828 break;
4831 break;
4834 break;
4836 if (!Config_getBool(HAVE_DOT))
4837 {
4838 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4839 "ignoring \\dotfile command because HAVE_DOT is not set");
4840 }
4841 else
4842 {
4843 handleFile<DocDotFile>(cmdName);
4844 }
4845 break;
4848 break;
4850 handleFile<DocMscFile>(cmdName);
4851 break;
4853 handleFile<DocDiaFile>(cmdName);
4854 break;
4857 break;
4859 handleLink(cmdName,FALSE);
4860 break;
4862 handleLink(cmdName,TRUE);
4863 break;
4865 handleCite(cmdChar,cmdName);
4866 break;
4868 handleEmoji(cmdChar,cmdName);
4869 break;
4871 handleDoxyConfig(cmdChar,cmdName);
4872 break;
4873 case CommandType::CMD_REF: // fall through
4875 handleRef(cmdChar,cmdName);
4876 break;
4878 {
4881 }
4882 break;
4884 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4885 break;
4887 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4888 break;
4890 {
4892 }
4893 break;
4894 //case CommandType::CMD_LANGSWITCH:
4895 // retval = handleLanguageSwitch();
4896 // break;
4898 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4899 {
4902 }
4903 break;
4906 break;
4908 handleShowDate(cmdChar,cmdName);
4909 break;
4911 handleILine(cmdChar,cmdName);
4912 break;
4914 handleIFile(cmdChar,cmdName);
4915 break;
4917 {
4919 (void)parser()->tokenizer.lex();
4921 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4923 }
4924 break;
4925 default:
4926 // we should not get here!
4927 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4928 break;
4929 }
4930 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4931 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4932 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4933 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4934 TokenRetval::RetVal_EndInternal)
4935 );
4936 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4937 return retval;
4938}
4939
4940static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4941 const char *attrName,
4942 QCString *result)
4943{
4944
4945 for (const auto &opt : tagHtmlAttribs)
4946 {
4947 if (opt.name==attrName)
4948 {
4949 *result = opt.value;
4950 return TRUE;
4951 }
4952 }
4953 return FALSE;
4954}
4955
4956Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4957{
4958 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4959 Token retval = Token::make_RetVal_OK();
4960 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4961 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4964 {
4965 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4966 tagName);
4967 }
4968 switch (tagId)
4969 {
4971 if (!parser()->context.token->emptyTag)
4972 {
4974 tagHtmlAttribs,DocHtmlList::Unordered);
4975 retval=children().get_last<DocHtmlList>()->parse();
4976 }
4977 break;
4979 if (!parser()->context.token->emptyTag)
4980 {
4982 tagHtmlAttribs,DocHtmlList::Ordered);
4983 retval=children().get_last<DocHtmlList>()->parse();
4984 }
4985 break;
4987 if (parser()->context.token->emptyTag) break;
4989 {
4990 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4991 }
4992 else
4993 {
4994 retval = Token::make_RetVal_ListItem();
4995 }
4996 break;
4998 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
4999 break;
5001 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
5002 break;
5004 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
5005 break;
5007 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
5008 break;
5010 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
5011 break;
5013 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
5014 break;
5016 if (parser()->context.token->emptyTag) break;
5017 if (parser()->context.xmlComment)
5018 // for C# source or inside a <summary> or <remark> section we
5019 // treat <code> as an XML tag (so similar to @code)
5020 {
5022 retval = handleStartCode();
5023 }
5024 else // normal HTML markup
5025 {
5026 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5027 }
5028 break;
5030 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
5031 break;
5033 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Typewriter,tagName,&parser()->context.token->attribs);
5034 break;
5036 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
5037 break;
5039 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
5040 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
5041 break;
5043 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
5044 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
5045 break;
5047 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
5048 break;
5050 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
5051 break;
5053 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
5054 break;
5056 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
5057 break;
5059 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
5060 break;
5062 if (parser()->context.token->emptyTag) break;
5063 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
5066 break;
5068 retval = Token::make_TK_NEWPARA();
5069 break;
5071 if (!parser()->context.token->emptyTag)
5072 {
5073 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
5074 retval=children().get_last<DocHtmlDescList>()->parse();
5075 }
5076 break;
5078 if (insideDL(thisVariant()))
5079 {
5080 retval = Token::make_RetVal_DescTitle();
5081 }
5082 else
5083 {
5084 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
5085 }
5086 break;
5088 if (insideDL(thisVariant()))
5089 {
5090 retval = Token::make_RetVal_DescData();
5091 }
5092 else
5093 {
5094 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
5095 }
5096 break;
5098 if (!parser()->context.token->emptyTag)
5099 {
5100 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
5101 retval=children().get_last<DocHtmlTable>()->parse();
5102 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5103 }
5104 break;
5106 retval = Token::make_RetVal_TableRow();
5107 break;
5109 retval = Token::make_RetVal_TableCell();
5110 break;
5112 retval = Token::make_RetVal_TableHCell();
5113 break;
5117 // for time being ignore </t....> tag
5118 break;
5120 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
5121 break;
5123 {
5124 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
5125 }
5126 break;
5128 {
5129 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
5130 }
5131 break;
5133 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
5134 break;
5136 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
5137 break;
5139 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
5140 break;
5142 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
5143 break;
5145 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
5146 break;
5148 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
5149 break;
5151 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
5152 break;
5154 {
5155 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
5156 }
5157 break;
5159 if (!parser()->context.token->emptyTag)
5160 {
5161 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
5162 retval=children().get_last<DocHtmlDetails>()->parse();
5163 }
5164 break;
5166 if (!parser()->context.token->emptyTag)
5167 {
5168 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
5169 retval = children().get_last<DocHtmlBlockQuote>()->parse();
5170 }
5171 break;
5172
5175 {
5176 if (!parser()->context.token->emptyTag)
5177 {
5179 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
5180 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
5181 if (d)
5182 {
5183 if (!d->summary()) // details section does not have a summary yet
5184 {
5185 d->parseSummary(n,parser()->context.token->attribs);
5186 }
5187 else
5188 {
5189 retval = Token::make_TK_NEWPARA();
5190 }
5191 }
5192 }
5193 }
5194 break;
5198 // fall through
5201 if (!children().empty())
5202 {
5203 retval = Token::make_TK_NEWPARA();
5204 }
5205 break;
5207 if (insideTable(thisVariant()))
5208 {
5209 retval = Token::make_RetVal_TableCell();
5210 }
5211 break;
5212 case HtmlTagType::XML_C:
5213 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5214 break;
5217 {
5219 QCString paramName;
5220 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5221 {
5222 if (paramName.isEmpty())
5223 {
5224 if (Config_getBool(WARN_NO_PARAMDOC))
5225 {
5226 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5227 }
5228 }
5229 else
5230 {
5231 retval = handleParamSection(paramName,
5233 TRUE);
5234 }
5235 }
5236 else
5237 {
5238 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5239 }
5240 }
5241 break;
5244 {
5245 QCString paramName;
5246 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5247 {
5248 //printf("paramName=%s\n",qPrint(paramName));
5250 children().append<DocWord>(parser(),thisVariant(),paramName);
5252 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5253 }
5254 else
5255 {
5256 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5257 }
5258 }
5259 break;
5261 {
5263 QCString exceptName;
5264 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5265 {
5266 unescapeCRef(exceptName);
5267 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5268 }
5269 else
5270 {
5271 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5272 }
5273 }
5274 break;
5277 if (insideTable(thisVariant()))
5278 {
5279 retval = Token::make_RetVal_TableRow();
5280 }
5281 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5282 {
5283 retval = Token::make_RetVal_ListItem();
5284 }
5285 else
5286 {
5287 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5288 }
5289 break;
5294 break;
5296 if (insideTable(thisVariant()))
5297 {
5298 retval = Token::make_RetVal_TableCell();
5299 }
5300 break;
5302 // I'm not sure if <see> is the same as <seealso> or if it
5303 // should you link a member without producing a section. The
5304 // C# specification is extremely vague about this (but what else
5305 // can we expect from Microsoft...)
5306 {
5307 QCString cref;
5308 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5309 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5310 {
5311 unescapeCRef(cref);
5312 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5313 {
5314 bool inSeeBlock = parser()->context.inSeeBlock;
5315 parser()->context.token->name = cref;
5318 parser()->context.inSeeBlock = inSeeBlock;
5319 }
5320 else // <see cref="...">...</see> style
5321 {
5322 //DocRef *ref = new DocRef(this,cref);
5323 //children().append(ref);
5324 //ref->parse();
5327 DocLink *lnk = children().get_last<DocLink>();
5328 QCString leftOver = lnk->parse(FALSE,TRUE);
5329 if (!leftOver.isEmpty())
5330 {
5331 children().append<DocWord>(parser(),thisVariant(),leftOver);
5332 }
5333 }
5334 }
5335 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5336 {
5337 bool inSeeBlock = parser()->context.inSeeBlock;
5338 parser()->context.token->name = cref;
5343 parser()->context.inSeeBlock = inSeeBlock;
5344 }
5345 else
5346 {
5347 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5348 }
5349 }
5350 break;
5352 {
5354 QCString cref;
5355 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5356 {
5357 unescapeCRef(cref);
5358 // Look for an existing "see" section
5359 DocNodeVariant *vss=nullptr;
5360 for (auto &n : children())
5361 {
5362 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5363 if (candidate && candidate->type()==DocSimpleSect::See)
5364 {
5365 vss = &n;
5366 }
5367 }
5368
5369 if (!vss) // start new section
5370 {
5372 vss = &children().back();
5373 }
5374
5375 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5376 retval = Token::make_RetVal_OK();
5377 }
5378 else
5379 {
5380 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5381 }
5382 }
5383 break;
5385 {
5386 QCString type;
5387 findAttribute(tagHtmlAttribs,"type",&type);
5389 HtmlAttribList emptyList;
5390 if (type=="number")
5391 {
5392 listType=DocHtmlList::Ordered;
5393 }
5394 if (type=="table")
5395 {
5396 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5397 retval=children().get_last<DocHtmlTable>()->parseXml();
5398 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5399 }
5400 else
5401 {
5402 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5403 retval=children().get_last<DocHtmlList>()->parseXml();
5404 }
5405 }
5406 break;
5409 // These tags are defined in .Net but are currently unsupported
5411 break;
5413 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5414 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5415 break;
5418 break;
5419 default:
5420 // we should not get here!
5421 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5422 ASSERT(0);
5423 break;
5424 }
5425 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5426 return retval;
5427}
5428
5430{
5431 AUTO_TRACE("tagName={}",tagName);
5432 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5433 Token retval = Token::make_RetVal_OK();
5434 switch (tagId)
5435 {
5437 if (!insideUL(thisVariant()))
5438 {
5439 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5440 }
5441 else
5442 {
5443 retval = Token::make_RetVal_EndList();
5444 }
5445 break;
5447 if (!insideOL(thisVariant()))
5448 {
5449 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5450 }
5451 else
5452 {
5453 retval = Token::make_RetVal_EndList();
5454 }
5455 break;
5457 if (!insideLI(thisVariant()))
5458 {
5459 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5460 }
5461 else
5462 {
5463 // ignore </li> tags
5464 }
5465 break;
5467 if (!insideDetails(thisVariant()))
5468 {
5469 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5470 }
5471 else
5472 {
5473 retval = Token::make_RetVal_EndHtmlDetails();
5474 }
5475 break;
5478 {
5479 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5480 }
5481 else
5482 {
5483 retval = Token::make_RetVal_EndBlockQuote();
5484 }
5485 break;
5488 break;
5491 break;
5494 break;
5497 break;
5500 break;
5503 break;
5506 break;
5509 break;
5512 break;
5515 break;
5518 break;
5521 break;
5524 break;
5527 break;
5530 break;
5533 break;
5536 break;
5541 break;
5543 retval = Token::make_TK_NEWPARA();
5544 break;
5546 retval = Token::make_RetVal_EndDesc();
5547 break;
5549 // ignore </dt> tag
5550 break;
5552 // ignore </dd> tag
5553 break;
5555 retval = Token::make_RetVal_EndTable();
5556 break;
5558 retval = Token::make_RetVal_EndTableRow();
5559 break;
5561 retval = Token::make_RetVal_EndTableCell();
5562 break;
5564 retval = Token::make_RetVal_EndTableCell();
5565 break;
5569 // for time being ignore </t....> tag
5570 break;
5572 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5573 break;
5575 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5576 break;
5578 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5579 break;
5581 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5582 break;
5584 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5585 break;
5587 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5588 break;
5590 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5591 break;
5593 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5594 break;
5596 break;
5598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5599 break;
5601 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5602 // ignore </a> tag (can be part of <a name=...></a>
5603 break;
5604
5606 break;
5608 retval = Token::make_TK_NEWPARA();
5609 break;
5622 retval = Token::make_RetVal_CloseXml();
5623 break;
5624 case HtmlTagType::XML_C:
5626 break;
5634 // These tags are defined in .Net but are currently unsupported
5635 break;
5637 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5638 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5639 break;
5640 default:
5641 // we should not get here!
5642 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5643 ASSERT(0);
5644 break;
5645 }
5646 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5647 return retval;
5648}
5649
5651{
5652 // expected hierarchy:
5653 // 1. DocAutoListItem <- n
5654 // 2. DocAutoList <- parent(n)
5655 // 3. DocPara <- parent(parent(n))
5656
5657 // step 1
5658 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5659 {
5660 return false;
5661 }
5662
5663 // step 2
5664 n = parent(n);
5665 int indent = 0;
5666 const auto docAutoList = std::get_if<DocAutoList>(n);
5667 if (docAutoList) // capture indent
5668 {
5669 indent = docAutoList->indent();
5670 }
5671 else
5672 {
5673 return false;
5674 }
5675
5676 // step 3
5677 n = parent(n);
5678 const auto docPara = std::get_if<DocPara>(n);
5679 if (docPara)
5680 {
5681 QCString tagNameLower = QCString(parser->context.token->name).lower();
5682 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5683 {
5684 return std::get<DocStyleChange>(*stack.top());
5685 };
5686
5687 if (parser->context.styleStack.empty() || // no style change
5688 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5689 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5690 )
5691 {
5692 // insert an artificial 'end of autolist' marker and parse again
5693 QCString indentStr;
5694 indentStr.fill(' ',indent);
5695 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5696 return true;
5697 }
5698 }
5699 return false;
5700}
5701
5703{
5704 AUTO_TRACE();
5705 auto ns = AutoNodeStack(parser(),thisVariant());
5706 // handle style commands "inherited" from the previous paragraph
5708 Token tok=parser()->tokenizer.lex();
5709 Token retval = Token::make_TK_NONE();
5710 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5711 {
5712reparsetoken:
5713 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5714 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5715 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5716 )
5717 {
5718 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5719 }
5720 switch(tok.value())
5721 {
5722 case TokenRetval::TK_WORD:
5724 break;
5725 case TokenRetval::TK_LNKWORD:
5727 break;
5728 case TokenRetval::TK_URL:
5730 break;
5731 case TokenRetval::TK_WHITESPACE:
5732 {
5733 // prevent leading whitespace and collapse multiple whitespace areas
5734 if (insidePRE(thisVariant()) || // all whitespace is relevant
5735 (
5736 // remove leading whitespace
5737 !children().empty() &&
5738 // and whitespace after certain constructs
5742 )
5743 )
5744 {
5746 }
5747 }
5748 break;
5749 case TokenRetval::TK_LISTITEM:
5750 {
5751 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5752 const DocNodeVariant *n=parent();
5753 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5754 const DocAutoList *al = std::get_if<DocAutoList>(n);
5755 if (al) // we found an auto list up in the hierarchy
5756 {
5757 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5758 if (al->indent()>=parser()->context.token->indent)
5759 // new item at the same or lower indent level
5760 {
5761 retval = Token::make_TK_LISTITEM();
5762 goto endparagraph;
5763 }
5764 }
5765
5766 // determine list depth
5767 int depth = 0;
5768 n=parent();
5769 while (n)
5770 {
5771 al = std::get_if<DocAutoList>(n);
5772 if (al && al->isEnumList()) depth++;
5773 n=::parent(n);
5774 }
5775
5776 // first item or sub list => create new list
5777 do
5778 {
5781 parser()->context.token->isEnumList,depth,
5783 al = children().get_last<DocAutoList>();
5784 retval = children().get_last<DocAutoList>()->parse();
5785 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5786 al->indent()==parser()->context.token->indent // at same indent level
5787 );
5788
5789 // check the return value
5790 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5791 {
5792 // Reparse the token that ended the section at this level,
5793 // so a new simple section will be started at this level.
5794 // This is the same as unputting the last read token and continuing.
5796 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5797 {
5800 tok = Token::make_TK_RCSTAG();
5801 }
5802 else // other section
5803 {
5804 tok = Token::make_TK_COMMAND_BS();
5805 }
5806 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5807 goto reparsetoken;
5808 }
5809 else if (retval.is(TokenRetval::TK_ENDLIST))
5810 {
5811 if (al->indent()>parser()->context.token->indent) // end list
5812 {
5813 goto endparagraph;
5814 }
5815 else // continue with current paragraph
5816 {
5817 }
5818 }
5819 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5820 {
5821 goto endparagraph;
5822 }
5823 }
5824 break;
5825 case TokenRetval::TK_ENDLIST:
5826 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5827 if (std::get_if<DocAutoListItem>(parent()))
5828 {
5829 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5830 if (al && al->indent()>=parser()->context.token->indent)
5831 {
5832 // end of list marker ends this paragraph
5833 retval = Token::make_TK_ENDLIST();
5834 goto endparagraph;
5835 }
5836 else
5837 {
5838 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5839 "has invalid indent level");
5840 }
5841 }
5842 else
5843 {
5844 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5845 "list items");
5846 }
5847 break;
5848 case TokenRetval::TK_COMMAND_AT:
5849 // fall through
5850 case TokenRetval::TK_COMMAND_BS:
5851 {
5852 // see if we have to start a simple section
5853 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5854 const DocNodeVariant *n=parent();
5855 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5856 !std::holds_alternative<DocParamSect>(*n))
5857 {
5858 n=::parent(n);
5859 }
5861 {
5862 if (n) // already in a simple section
5863 {
5864 // simple section cannot start in this paragraph, need
5865 // to unwind the stack and remember the command.
5867 retval = Token::make_RetVal_SimpleSec();
5868 goto endparagraph;
5869 }
5870 }
5871 // see if we are in a simple list
5872 n=parent();
5873 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5874 if (n)
5875 {
5876 if (cmd==CommandType::CMD_LI)
5877 {
5878 retval = Token::make_RetVal_ListItem();
5879 goto endparagraph;
5880 }
5881 }
5882
5883 // handle the command
5884 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5885 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5886
5887 // check the return value
5888 if (retval.is(TokenRetval::RetVal_SimpleSec))
5889 {
5890 // Reparse the token that ended the section at this level,
5891 // so a new simple section will be started at this level.
5892 // This is the same as unputting the last read token and continuing.
5894 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5895 {
5898 tok = Token::make_TK_RCSTAG();
5899 }
5900 else // other section
5901 {
5902 tok = Token::make_TK_COMMAND_BS();
5903 }
5904 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5905 goto reparsetoken;
5906 }
5907 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5908 {
5909 // the command ended with a new command, reparse this token
5910 tok = retval;
5911 goto reparsetoken;
5912 }
5913 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5914 // or some auto list marker
5915 {
5916 goto endparagraph;
5917 }
5918 }
5919 break;
5920 case TokenRetval::TK_HTMLTAG:
5921 {
5922 if (!parser()->context.token->endTag) // found a start tag
5923 {
5924 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5925 }
5926 else // found an end tag
5927 {
5929 {
5930 break; // new code has been pushed back to the scanner, need to reparse
5931 }
5932 retval = handleHtmlEndTag(parser()->context.token->name);
5933 }
5934 if (!retval.is(TokenRetval::RetVal_OK))
5935 {
5936 goto endparagraph;
5937 }
5938 }
5939 break;
5940 case TokenRetval::TK_SYMBOL:
5941 {
5942 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5944 {
5946 }
5947 else
5948 {
5950 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5951 parser()->context.token->name);
5952 }
5953 break;
5954 }
5955 case TokenRetval::TK_NEWPARA:
5956 retval = Token::make_TK_NEWPARA();
5957 goto endparagraph;
5958 case TokenRetval::TK_RCSTAG:
5959 {
5960 const DocNodeVariant *n=parent();
5961 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5962 !std::holds_alternative<DocParamSect>(*n))
5963 {
5964 n=::parent(n);
5965 }
5966 if (n) // already in a simple section
5967 {
5968 // simple section cannot start in this paragraph, need
5969 // to unwind the stack and remember the command.
5972 retval = Token::make_RetVal_SimpleSec();
5973 goto endparagraph;
5974 }
5975
5976 // see if we are in a simple list
5978 children().get_last<DocSimpleSect>()->parseRcs();
5979 }
5980 break;
5981 default:
5982 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5983 "Found unexpected token (id={})",tok.to_string());
5984 break;
5985 }
5986 tok=parser()->tokenizer.lex();
5987 }
5988 retval=Token::make_TK_NONE();
5989endparagraph:
5991 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5992 if (!parser()->context.token->endTag && par &&
5993 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5994 {
5995 par->setAttribs(parser()->context.token->attribs);
5996 }
5997 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
5998 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
5999 );
6000
6001 AUTO_TRACE_EXIT("retval={}",retval.to_string());
6002 return retval;
6003}
6004
6005//--------------------------------------------------------------------------
6006
6008{
6009 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
6010 Token retval = Token::make_RetVal_OK();
6011 auto ns = AutoNodeStack(parser(),thisVariant());
6012
6013 if (!m_id.isEmpty())
6014 {
6016 if (sec)
6017 {
6018 m_file = sec->fileName();
6019 m_anchor = sec->label();
6020 QCString titleStr = sec->title();
6021 if (titleStr.isEmpty()) titleStr = sec->label();
6023 DocTitle *title = &std::get<DocTitle>(*m_title);
6024 title->parseFromString(thisVariant(),titleStr);
6025 }
6026 }
6027
6028 // first parse any number of paragraphs
6029 bool isFirst=TRUE;
6030 DocPara *lastPar=nullptr;
6031 do
6032 {
6034 DocPara *par = children().get_last<DocPara>();
6035 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6036 retval=par->parse();
6037 if (!par->isEmpty())
6038 {
6039 if (lastPar) lastPar->markLast(FALSE);
6040 lastPar = par;
6041 }
6042 else
6043 {
6044 children().pop_back();
6045 }
6046 if (retval.is(TokenRetval::TK_LISTITEM))
6047 {
6048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6049 }
6050 if (retval.is(TokenRetval::RetVal_Internal))
6051 {
6053 retval = children().get_last<DocInternal>()->parse(m_level+1);
6054 if (retval.is(TokenRetval::RetVal_EndInternal))
6055 {
6056 retval = Token::make_RetVal_OK();
6057 }
6058 }
6059 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6060 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
6061 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
6062 );
6063
6064 if (lastPar) lastPar->markLast();
6065
6066 while (true)
6067 {
6068 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
6069 {
6070 // then parse any number of nested sections
6071 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
6072 {
6074 2,
6076 retval = children().get_last<DocSection>()->parse();
6077 }
6078 break;
6079 }
6080 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
6081 {
6082 if ((m_level <= 1) &&
6083 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6084 {
6085 warn_doc_error(parser()->context.fileName,
6086 parser()->tokenizer.getLineNr(),
6087 "Unexpected subsubsection command found inside {}!",
6089 }
6090 // then parse any number of nested sections
6091 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
6092 {
6094 3,
6096 retval = children().get_last<DocSection>()->parse();
6097 }
6098 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
6099 }
6100 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
6101 {
6102 if ((m_level <= 2) &&
6103 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6104 {
6105 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6106 "Unexpected paragraph command found inside {}!",
6108 }
6109 // then parse any number of nested sections
6110 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
6111 {
6113 4,
6115 retval = children().get_last<DocSection>()->parse();
6116 }
6117 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
6118 }
6119 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
6120 {
6121 if ((m_level <= 3) &&
6122 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6123 {
6124 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6125 "Unexpected subparagraph command found inside {}!",
6127 }
6128 // then parse any number of nested sections
6129 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
6130 {
6132 5,
6134 retval = children().get_last<DocSection>()->parse();
6135 }
6136 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
6137 }
6138 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
6139 {
6140 if ((m_level <= 4) &&
6141 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6142 {
6143 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6144 "Unexpected subsubparagraph command found inside {}!",
6146 }
6147 // then parse any number of nested sections
6148 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
6149 {
6151 6,
6153 retval = children().get_last<DocSection>()->parse();
6154 }
6155 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
6156 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
6157 }
6158 else
6159 {
6160 break;
6161 }
6162 }
6163
6164 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
6165 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6166 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
6167 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
6168 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
6169 );
6170
6171 AUTO_TRACE_EXIT("retval={}", retval.to_string());
6172 return retval;
6173}
6174
6175//--------------------------------------------------------------------------
6176
6178{
6179 AUTO_TRACE();
6180 auto ns = AutoNodeStack(parser(),thisVariant());
6182
6183 Token tok = parser()->tokenizer.lex();
6184 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
6185 {
6186 switch(tok.value())
6187 {
6188 case TokenRetval::TK_WORD:
6190 break;
6191 case TokenRetval::TK_WHITESPACE:
6193 break;
6194 case TokenRetval::TK_SYMBOL:
6195 {
6196 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
6198 {
6200 }
6201 else
6202 {
6203 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
6204 parser()->context.token->name);
6205 }
6206 }
6207 break;
6208 case TokenRetval::TK_COMMAND_AT:
6209 // fall through
6210 case TokenRetval::TK_COMMAND_BS:
6211 switch (Mappers::cmdMapper->map(parser()->context.token->name))
6212 {
6215 break;
6218 break;
6221 break;
6224 break;
6227 break;
6230 break;
6233 break;
6236 break;
6239 break;
6243 break;
6248 break;
6251 break;
6254 break;
6257 break;
6260 break;
6263 break;
6266 break;
6269 break;
6270 default:
6271 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6272 parser()->context.token->name);
6273 break;
6274 }
6275 break;
6276 default:
6277 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6278 tok.to_string());
6279 break;
6280 }
6281 tok = parser()->tokenizer.lex();
6282 }
6283
6285
6286}
6287
6288
6289//--------------------------------------------------------------------------
6290
6292{
6293 AUTO_TRACE();
6294 auto ns = AutoNodeStack(parser(),thisVariant());
6296 Token retval = Token::make_TK_NONE();
6297
6298 // first parse any number of paragraphs
6299 bool isFirst=TRUE;
6300 DocPara *lastPar = nullptr;
6301 do
6302 {
6303 {
6305 DocPara *par = children().get_last<DocPara>();
6306 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6307 retval=par->parse();
6308 if (par->isEmpty() && par->attribs().empty())
6309 {
6310 children().pop_back();
6311 }
6312 else
6313 {
6314 lastPar = par;
6315 }
6316 }
6317 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6318 if (retval == t)
6319 {
6320 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6321 {
6322 warn_doc_error(parser()->context.fileName,
6323 parser()->tokenizer.getLineNr(),
6324 "found {} command (id: '{}') outside of {} context!",
6325 sectionType,parser()->context.token->sectionId,parentSectionType);
6326 }
6327 while (retval==t)
6328 {
6329 if (!parser()->context.token->sectionId.isEmpty())
6330 {
6331 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6332 if (sec)
6333 {
6335 level,
6337 retval = children().get_last<DocSection>()->parse();
6338 }
6339 else
6340 {
6341 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6342 sectionType,parser()->context.token->sectionId,sectionType);
6343 retval = Token::make_TK_NONE();
6344 }
6345 }
6346 else
6347 {
6348 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6349 retval = Token::make_TK_NONE();
6350 }
6351 }
6352 }
6353 };
6354 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6355 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6356 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6357 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6358 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6359
6360 if (retval.is(TokenRetval::TK_LISTITEM))
6361 {
6362 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6363 }
6364 if (retval.is(TokenRetval::RetVal_Internal))
6365 {
6367 retval = children().get_last<DocInternal>()->parse(1);
6368 }
6369 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6370 if (lastPar) lastPar->markLast();
6371
6372 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6373 // then parse any number of level1 sections
6374 while (retval.is(TokenRetval::RetVal_Section))
6375 {
6376 if (!parser()->context.token->sectionId.isEmpty())
6377 {
6378 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6379 if (sec)
6380 {
6382 1,
6384 retval = children().get_last<DocSection>()->parse();
6385 }
6386 else
6387 {
6388 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6389 retval = Token::make_TK_NONE();
6390 }
6391 }
6392 else
6393 {
6394 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6395 retval = Token::make_TK_NONE();
6396 }
6397 }
6398
6400}
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:85
QCString anchorPrefix() const
Definition cite.cpp:128
const CiteInfo * find(const QCString &label) const
Return the citation info for a given label.
Definition cite.cpp:102
static CitationManager & instance()
Definition cite.cpp:86
QCString fileName() const
Definition cite.cpp:123
static CiteInfoOption makeYear()
Definition cite.h:31
static CiteInfoOption makeNumber()
Definition cite.h:29
void setNoCite()
Definition cite.h:35
bool isUnknown() const
Definition cite.h:37
void changeToNumber()
Definition cite.h:33
static CiteInfoOption makeShortAuthor()
Definition cite.h:30
void setNoPar()
Definition cite.h:34
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 SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
virtual bool isLinkable() const =0
virtual DefType definitionType() const =0
virtual QCString briefDescription(bool abbreviate=FALSE) const =0
virtual QCString getReference() const =0
virtual QCString getSourceFileBase() const =0
virtual QCString documentation() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
virtual const QCString & name() const =0
DocAnchor(DocParser *parser, DocNodeVariant *parent, const QCString &id, bool newAnchor)
Definition docnode.cpp:209
QCString m_anchor
Definition docnode.h:238
QCString m_file
Definition docnode.h:239
Node representing an auto List.
Definition docnode.h:571
int m_depth
Definition docnode.h:590
bool isCheckedList() const
Definition docnode.h:582
bool isEnumList() const
Definition docnode.h:580
int depth() const
Definition docnode.h:583
int m_indent
Definition docnode.h:587
Token parse()
Definition docnode.cpp:2974
bool m_isCheckedList
Definition docnode.h:589
int indent() const
Definition docnode.h:581
DocAutoList(DocParser *parser, DocNodeVariant *parent, int indent, bool isEnumList, int depth, bool isCheckedList)
Definition docnode.cpp:2967
bool m_isEnumList
Definition docnode.h:588
Node representing an item of a auto list.
Definition docnode.h:595
DocAutoListItem(DocParser *parser, DocNodeVariant *parent, int indent, int num)
Definition docnode.cpp:2927
Node representing a citation of some bibliographic reference.
Definition docnode.h:245
QCString m_anchor
Definition docnode.h:260
QCString getText() const
Definition docnode.cpp:952
QCString m_target
Definition docnode.h:261
QCString m_relPath
Definition docnode.h:258
QCString m_ref
Definition docnode.h:259
QCString target() const
Definition docnode.h:252
DocCite(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context, CiteInfoOption opt)
Definition docnode.cpp:916
QCString m_file
Definition docnode.h:257
CiteInfoOption m_option
Definition docnode.h:262
DocNodeList & children()
Definition docnode.h:143
DocCompoundNode(DocParser *parser, DocNodeVariant *parent)
Definition docnode.h:141
bool parse()
Definition docnode.cpp:1188
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1181
QCString srcFile() const
Definition docnode.h:691
std::unique_ptr< Private > p
Definition docnode.h:708
int srcLine() const
Definition docnode.h:692
DocDiagramFileBase(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.h:681
QCString context() const
Definition docnode.h:690
QCString name() const
Definition docnode.h:684
bool parse()
Definition docnode.cpp:1110
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1103
Node representing an emoji.
Definition docnode.h:341
DocEmoji(DocParser *parser, DocNodeVariant *parent, const QCString &symName)
Definition docnode.cpp:160
int m_index
Definition docnode.h:349
QCString m_symName
Definition docnode.h:348
Node representing an item of a cross-referenced list.
Definition docnode.h:529
QCString m_relPath
Definition docnode.h:546
QCString m_text
Definition docnode.h:545
int id() const
Definition docnode.h:535
QCString m_name
Definition docnode.h:544
DocFormula(DocParser *parser, DocNodeVariant *parent, int id)
Definition docnode.cpp:515
QCString relPath() const
Definition docnode.h:534
Token parse()
Definition docnode.cpp:1502
Node representing a horizontal ruler.
Definition docnode.h:216
Node representing an HTML blockquote.
Definition docnode.h:1291
HtmlAttribList m_attribs
Definition docnode.h:1238
bool m_hasCaptionId
Definition docnode.h:1239
DocHtmlCaption(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs)
Definition docnode.cpp:1709
QCString m_file
Definition docnode.h:1240
const HtmlAttribList & attribs() const
Definition docnode.h:1231
QCString m_anchor
Definition docnode.h:1241
Node representing a HTML table cell.
Definition docnode.h:1193
Valignment valignment() const
Definition docnode.cpp:1913
void setColumnIndex(uint32_t idx)
Definition docnode.h:1217
bool isFirst() const
Definition docnode.h:1201
Token parseXml()
Definition docnode.cpp:1817
void setRowIndex(uint32_t idx)
Definition docnode.h:1216
void markLast(bool v=TRUE)
Definition docnode.h:1204
uint32_t rowSpan() const
Definition docnode.cpp:1851
void markFirst(bool v=TRUE)
Definition docnode.h:1203
Alignment alignment() const
Definition docnode.cpp:1875
bool isHeading() const
Definition docnode.h:1200
const HtmlAttribList & attribs() const
Definition docnode.h:1205
Token parse()
Definition docnode.cpp:1783
uint32_t colSpan() const
Definition docnode.cpp:1863
Node representing a HTML description data.
Definition docnode.h:1181
HtmlAttribList m_attribs
Definition docnode.h:1188
Node representing a Html description list.
Definition docnode.h:901
Node representing a Html description item.
Definition docnode.h:888
Node Html details.
Definition docnode.h:857
const HtmlAttribList & attribs() const
Definition docnode.h:861
void parseSummary(DocNodeVariant *, HtmlAttribList &attribs)
Definition docnode.cpp:1492
const DocNodeVariant * summary() const
Definition docnode.h:864
std::unique_ptr< DocNodeVariant > m_summary
Definition docnode.h:868
Node Html heading.
Definition docnode.h:873
Token parse()
Definition docnode.cpp:1317
Node representing a Html list.
Definition docnode.h:1000
Type m_type
Definition docnode.h:1011
Token parseXml()
Definition docnode.cpp:2774
Token parse()
Definition docnode.cpp:2699
Node representing a HTML list item.
Definition docnode.h:1165
Node representing a HTML table row.
Definition docnode.h:1246
Token parseXml(bool header)
Definition docnode.cpp:2117
void setVisibleCells(uint32_t n)
Definition docnode.h:1256
bool isHeading() const
Definition docnode.cpp:1935
void setRowIndex(uint32_t idx)
Definition docnode.h:1261
Token parse()
Definition docnode.cpp:2010
Node Html summary.
Definition docnode.h:844
Node representing a HTML table.
Definition docnode.h:1269
Token parseXml()
Definition docnode.cpp:2284
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1284
Token parse()
Definition docnode.cpp:2197
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2341
size_t m_numCols
Definition docnode.h:1286
const DocNodeVariant * caption() const
Definition docnode.cpp:2183
bool hasCaption() const
Definition docnode.cpp:2178
const DocNodeVariant * firstRow() const
Definition docnode.cpp:2188
const HtmlAttribList & attribs() const
Definition docnode.h:656
QCString relPath() const
Definition docnode.h:652
QCString name() const
Definition docnode.h:648
QCString url() const
Definition docnode.h:653
DocImage(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs, const QCString &name, Type t, const QCString &url=QCString(), bool inlineImage=TRUE)
Definition docnode.cpp:1294
std::unique_ptr< Private > p
Definition docnode.h:675
void parse()
Definition docnode.cpp:1309
bool isSVG() const
Definition docnode.cpp:1300
Node representing a include/dontinclude operator block.
Definition docnode.h:477
bool m_stripCodeComments
Definition docnode.h:521
const char * typeAsString() const
Definition docnode.h:486
QCString m_includeFileName
Definition docnode.h:524
QCString context() const
Definition docnode.h:501
Type type() const
Definition docnode.h:485
QCString m_pattern
Definition docnode.h:517
void markLast(bool v=TRUE)
Definition docnode.h:505
QCString m_text
Definition docnode.h:516
bool m_showLineNo
Definition docnode.h:515
Node representing an included text block from file.
Definition docnode.h:435
void parse()
Definition docnode.cpp:268
QCString m_text
Definition docnode.h:465
Type m_type
Definition docnode.h:466
@ LatexInclude
Definition docnode.h:437
@ SnippetWithLines
Definition docnode.h:438
@ DontIncWithLines
Definition docnode.h:439
@ IncWithLines
Definition docnode.h:438
@ HtmlInclude
Definition docnode.h:437
@ VerbInclude
Definition docnode.h:437
@ DontInclude
Definition docnode.h:437
@ DocbookInclude
Definition docnode.h:439
QCString m_blockId
Definition docnode.h:472
bool m_stripCodeComments
Definition docnode.h:467
QCString context() const
Definition docnode.h:453
QCString m_file
Definition docnode.h:463
Node representing an entry in the index.
Definition docnode.h:552
QCString m_entry
Definition docnode.h:562
Token parse()
Definition docnode.cpp:1612
Node representing an internal section of documentation.
Definition docnode.h:969
Token parse(int)
Definition docnode.cpp:1552
QCString m_file
Definition docnode.h:816
QCString m_anchor
Definition docnode.h:818
DocInternalRef(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:670
QCString relPath() const
Definition docnode.h:812
QCString m_relPath
Definition docnode.h:817
Node representing a line break.
Definition docnode.h:202
QCString m_word
Definition docnode.h:178
QCString m_anchor
Definition docnode.h:182
QCString file() const
Definition docnode.h:171
QCString relPath() const
Definition docnode.h:172
QCString ref() const
Definition docnode.h:173
QCString word() const
Definition docnode.h:170
QCString m_file
Definition docnode.h:180
QCString anchor() const
Definition docnode.h:174
QCString m_ref
Definition docnode.h:179
QCString m_relPath
Definition docnode.h:181
DocLinkedWord(DocParser *parser, DocNodeVariant *parent, const QCString &word, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &tooltip)
Definition docnode.cpp:192
QCString m_tooltip
Definition docnode.h:183
QCString tooltip() const
Definition docnode.h:175
DocMscFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1141
bool parse()
Definition docnode.cpp:1148
DocNode(DocParser *parser, DocNodeVariant *parent)
Definition docnode.h:85
void setInsidePreformatted(bool p)
Definition docnode.h:109
DocNodeVariant * thisVariant()
Definition docnode.h:93
DocParser * parser()
Definition docnode.h:98
DocNodeVariant * parent()
Definition docnode.h:90
@ Unknown
Definition docnode.h:110
@ Table
Definition docnode.h:110
@ Section
Definition docnode.h:110
@ Anchor
Definition docnode.h:110
Node representing an block of paragraphs.
Definition docnode.h:979
Token parse()
Definition docnode.cpp:2868
Node representing a paragraph in the documentation tree.
Definition docnode.h:1080
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3396
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3911
void handleInheritDoc()
Definition docnode.cpp:4169
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3449
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3390
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3979
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4206
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3585
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4084
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3872
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3788
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3426
void markLast(bool v=TRUE)
Definition docnode.h:1086
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4956
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3554
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3812
bool isFirst() const
Definition docnode.h:1087
void markFirst(bool v=TRUE)
Definition docnode.h:1085
void handleRef(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3952
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3774
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1115
bool m_isFirst
Definition docnode.h:1118
Token parse()
Definition docnode.cpp:5702
void handleVhdlFlow()
Definition docnode.cpp:3904
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:4115
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3704
bool m_isLast
Definition docnode.h:1119
Token handleXRefItem()
Definition docnode.cpp:3683
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5429
Token handleStartCode()
Definition docnode.cpp:4133
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:4126
DocNodeList m_paramTypes
Definition docnode.h:1144
DocNodeList m_paragraphs
Definition docnode.h:1142
void markFirst(bool b=TRUE)
Definition docnode.h:1134
Token parseXml(const QCString &paramName)
Definition docnode.cpp:3279
void markLast(bool b=TRUE)
Definition docnode.h:1135
Token parse(const QCString &cmdName)
Definition docnode.cpp:3200
DocParamSect::Type m_type
Definition docnode.h:1145
DocNodeList m_params
Definition docnode.h:1143
Node representing a parameter section.
Definition docnode.h:1053
friend class DocParamList
Definition docnode.h:1054
Token parse(const QCString &cmdName, bool xmlContext, Direction d)
Definition docnode.cpp:3347
bool m_hasInOutSpecifier
Definition docnode.h:1074
Type type() const
Definition docnode.h:1068
bool defaultHandleToken(DocNodeVariant *parent, Token tok, DocNodeList &children, bool handleWord=TRUE)
void handleLinkedWord(DocNodeVariant *parent, DocNodeList &children, bool ignoreAutoLinkFlag=FALSE)
DocTokenizer tokenizer
void handleInternalRef(DocNodeVariant *parent, DocNodeList &children)
void handleParameterType(DocNodeVariant *parent, DocNodeList &children, const QCString &paramTypes)
void checkRetvalName()
void readTextFileByName(const QCString &file, QCString &text)
Token handleAHref(DocNodeVariant *parent, DocNodeList &children, const HtmlAttribList &tagHtmlAttribs)
Token internalValidatingParseDoc(DocNodeVariant *parent, DocNodeList &children, const QCString &doc)
void handleInitialStyleCommands(DocNodeVariant *parent, DocNodeList &children)
void handleStyleLeave(DocNodeVariant *parent, DocNodeList &children, DocStyleChange::Style s, const QCString &tagName)
void handlePendingStyleCommands(DocNodeVariant *parent, DocNodeList &children)
void popContext()
Definition docparser.cpp:74
void handleImage(DocNodeVariant *parent, DocNodeList &children)
void handleStyleEnter(DocNodeVariant *parent, DocNodeList &children, DocStyleChange::Style s, const QCString &tagName, const HtmlAttribList *attribs)
void handlePrefix(DocNodeVariant *parent, DocNodeList &children)
Token handleStyleArgument(DocNodeVariant *parent, DocNodeList &children, const QCString &cmdName)
void checkArgumentName()
DocParserContext context
void handleAnchor(DocNodeVariant *parent, DocNodeList &children)
void handleImg(DocNodeVariant *parent, DocNodeList &children, const HtmlAttribList &tagHtmlAttribs)
void defaultHandleTitleAndSize(const CommandType cmd, DocNodeVariant *parent, DocNodeList &children, QCString &width, QCString &height)
void handleUnclosedStyleCommands()
void pushContext()
Definition docparser.cpp:60
void errorHandleDefaultToken(DocNodeVariant *parent, Token tok, DocNodeList &children, const QCString &txt)
DocPlantUmlFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1220
Node representing a reference to some item.
Definition docnode.h:778
QCString anchor() const
Definition docnode.h:785
QCString m_file
Definition docnode.h:798
SectionType m_sectionType
Definition docnode.h:796
QCString m_text
Definition docnode.h:802
void parse()
Definition docnode.cpp:870
QCString m_ref
Definition docnode.h:800
QCString m_relPath
Definition docnode.h:799
DocRef(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context)
Definition docnode.cpp:705
RefType m_refType
Definition docnode.h:795
QCString m_anchor
Definition docnode.h:801
bool m_isSubPage
Definition docnode.h:797
void parse()
Definition docnode.cpp:6291
Node representing a reference to a section.
Definition docnode.h:935
QCString m_file
Definition docnode.h:951
QCString m_target
Definition docnode.h:948
QCString relPath() const
Definition docnode.h:941
bool m_isSubPage
Definition docnode.h:950
QCString m_anchor
Definition docnode.h:954
QCString target() const
Definition docnode.h:938
QCString m_ref
Definition docnode.h:953
DocSecRefItem(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:534
QCString m_relPath
Definition docnode.h:952
RefType m_refType
Definition docnode.h:949
Node representing a list of section references.
Definition docnode.h:959
Node representing a normal section.
Definition docnode.h:914
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:928
QCString m_id
Definition docnode.h:927
QCString m_file
Definition docnode.h:930
Token parse()
Definition docnode.cpp:6007
DocSection(DocParser *parser, DocNodeVariant *parent, int level, const QCString &id)
Definition docnode.h:916
const DocNodeVariant * title() const
Definition docnode.h:919
QCString m_anchor
Definition docnode.h:929
int m_level
Definition docnode.h:926
Node representing a simple list.
Definition docnode.h:990
Token parse()
Definition docnode.cpp:2912
Node representing a simple list item.
Definition docnode.h:1153
std::unique_ptr< DocNodeVariant > m_paragraph
Definition docnode.h:1160
DocSimpleListItem(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:2893
Node representing a simple section.
Definition docnode.h:1017
QCString typeString() const
Definition docnode.cpp:3171
Type type() const
Definition docnode.h:1026
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:3061
Token parseRcs()
Definition docnode.cpp:3098
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:3051
const DocNodeVariant * title() const
Definition docnode.h:1033
Token parseXml()
Definition docnode.cpp:3115
void appendLinkWord(const QCString &word)
Definition docnode.cpp:3151
bool hasTitle() const
Definition docnode.cpp:3056
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:1037
Node representing a separator between two simple sections of the same type.
Definition docnode.h:1044
Node representing a style change.
Definition docnode.h:268
const char * styleString() const
Definition docnode.cpp:125
Style m_style
Definition docnode.h:318
Node representing a special symbol.
Definition docnode.h:328
static HtmlEntityMapper::SymType decodeSymbol(const QCString &symName)
Definition docnode.cpp:153
void parse()
Definition docnode.cpp:6177
Node representing a simple section title.
Definition docnode.h:608
void parse()
Definition docnode.cpp:3020
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:3038
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:188
Node representing a verbatim, unparsed text fragment.
Definition docnode.h:376
DocVerbatim(DocParser *parser, DocNodeVariant *parent, const QCString &context, const QCString &text, Type t, bool isExample, const QCString &exampleFile, bool isBlock=FALSE, const QCString &lang=QCString())
Definition docnode.cpp:258
std::unique_ptr< Private > p
Definition docnode.h:429
bool isBlock() const
Definition docnode.h:389
bool isExample() const
Definition docnode.h:385
QCString context() const
Definition docnode.h:384
QCString text() const
Definition docnode.h:383
QCString exampleFile() const
Definition docnode.h:386
QCString relPath() const
Definition docnode.h:387
void setEngine(const QCString &e)
Definition docnode.h:402
@ JavaDocLiteral
Definition docnode.h:378
Node representing a VHDL flow chart.
Definition docnode.h:749
DocVhdlFlow(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:1264
void parse()
Definition docnode.cpp:1268
Node representing some amount of white space.
Definition docnode.h:354
Node representing a word.
Definition docnode.h:153
DocWord(DocParser *parser, DocNodeVariant *parent, const QCString &word)
Definition docnode.cpp:180
QCString m_word
Definition docnode.h:159
QCString word() const
Definition docnode.h:156
Node representing an item of a cross-referenced list.
Definition docnode.h:621
QCString m_anchor
Definition docnode.h:635
DocXRefItem(DocParser *parser, DocNodeVariant *parent, int id, const QCString &key)
Definition docnode.cpp:473
QCString key() const
Definition docnode.h:628
QCString relPath() const
Definition docnode.h:627
QCString m_file
Definition docnode.h:634
QCString m_key
Definition docnode.h:633
QCString m_title
Definition docnode.h:636
bool parse()
Definition docnode.cpp:478
QCString m_relPath
Definition docnode.h:637
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 DirLinkedMap * dirLinkedMap
Definition doxygen.h:129
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:178
static constexpr int Anchor
Definition section.h:40
static constexpr int Table
Definition section.h:41
constexpr int level() const
Definition section.h:45
static constexpr int Page
Definition section.h:31
bool is(TokenRetval rv) const
TOKEN_SPECIFICATIONS RETVAL_SPECIFICATIONS const char * to_string() const
TokenRetval value() const
bool is_any_of(ARGS... args) const
char command_to_char() const
static void createFlowChart(const MemberDef *)
Class representing a regular expression.
Definition regex.h:39
Class to iterate through matches.
Definition regex.h:232
CommandType
Definition cmdmapper.h:29
@ CMD_ENDSECREFLIST
Definition cmdmapper.h:53
@ CMD_ENDLATEXONLY
Definition cmdmapper.h:51
@ CMD_ENDVERBATIM
Definition cmdmapper.h:54
@ CMD_DONTINCLUDE
Definition cmdmapper.h:46
@ CMD_SUBSUBSECTION
Definition cmdmapper.h:89
@ CMD_SUBSUBPARAGRAPH
Definition cmdmapper.h:161
@ CMD_INTERNALREF
Definition cmdmapper.h:65
@ CMD_ENDHTMLONLY
Definition cmdmapper.h:50
@ CMD_VERBINCLUDE
Definition cmdmapper.h:98
@ CMD_DOCBOOKINCLUDE
Definition cmdmapper.h:145
@ CMD_HTMLINCLUDE
Definition cmdmapper.h:60
@ CMD_SNIPWITHLINES
Definition cmdmapper.h:141
HtmlTagType
Definition cmdmapper.h:169
#define Config_getList(name)
Definition config.h:38
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
std::unordered_set< std::string > StringUnorderedSet
Definition containers.h:29
std::vector< std::string > StringVector
Definition containers.h:33
QCString formatDateTime(const QCString &format, const std::tm &dt, int &formatUsed)
Return a string representation for a given std::tm value that is formatted according to the pattern g...
Definition datetime.cpp:175
QCString dateTimeFromString(const QCString &spec, std::tm &dt, int &format)
Returns the filled in std::tm for a given string representing a date and/or time.
Definition datetime.cpp:134
constexpr const char * SF_bit2str(int bitNumber)
Helper function that returns the name related one of the SF bits.
Definition datetime.h:32
constexpr int SF_NumBits
number of bits in SF vector
Definition datetime.h:27
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
#define AUTO_TRACE_ADD(...)
Definition docnode.cpp:47
static const char * g_sectionLevelToName[]
Definition docnode.cpp:56
#define AUTO_TRACE(...)
Definition docnode.cpp:46
static QCString stripKnownExtensions(const QCString &text)
Definition docnode.cpp:103
static void unescapeCRef(QCString &s)
Definition docnode.cpp:81
static const StringUnorderedSet g_plantumlEngine
Definition docnode.cpp:69
#define INTERNAL_ASSERT(x)
Definition docnode.cpp:51
static void flattenParagraphs(DocNodeVariant *root, DocNodeList &children)
Definition docnode.cpp:838
static Token skipSpacesForTable(DocParser *parser)
Definition docnode.cpp:1950
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4940
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2335
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:118
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5650
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:67
constexpr bool holds_one_of_alternatives(const DocNodeVariant &v)
returns true iff v holds one of types passed as template parameters
Definition docnode.h:1366
DocNodeList * call_method_children(DocNodeVariant *v)
Definition docnode.h:1385
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:1330
std::unique_ptr< DocNodeVariant > createDocNode(Args &&...args)
Definition docnode.h:1495
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:1939
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:2330
uint32_t column
Definition docnode.cpp:2331
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2329
Citation-related data.
Definition cite.h:70
virtual QCString text() const =0
virtual QCString shortAuthor() const =0
virtual QCString label() const =0
virtual QCString year() const =0
void move_append(DocNodeList &l)
moves the element of list l at the end of this list.
Definition docnode.cpp:829
void append(Args &&... args)
Append a new DocNodeVariant to the list by constructing it with type T and parameters Args.
Definition docnode.h:1399
T * get_last()
Returns a pointer to the last element in the list if that element exists and holds a T,...
Definition docnode.h:1410
StringMultiSet retvalsFound
Definition docparser_p.h:76
bool includeFileShowLineNo
Definition docparser_p.h:90
DocStyleChangeStack styleStack
Definition docparser_p.h:68
size_t includeFileLength
Definition docparser_p.h:88
QCString fileName
Definition docparser_p.h:71
DocNodeStack nodeStack
Definition docparser_p.h:67
StringMultiSet paramsFound
Definition docparser_p.h:77
DefinitionStack copyStack
Definition docparser_p.h:70
QCString exampleName
Definition docparser_p.h:80
const Definition * scope
Definition docparser_p.h:61
QCString includeFileText
Definition docparser_p.h:86
TokenInfo * token
Definition docparser_p.h:93
QCString includeFileName
Definition docparser_p.h:85
size_t includeFileOffset
Definition docparser_p.h:87
const MemberDef * memberDef
Definition docparser_p.h:78
QCString verb
bool isEnumList
QCString text
QCString sectionId
QCString chars
HtmlAttribList attribs
bool isCheckedList
QCString simpleSectText
QCString name
QCString attribsStr
bool isEMailAddr
QCString simpleSectName
QCString linkToText(SrcLangExt lang, const QCString &link, bool isFileName)
Definition util.cpp:3221
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5724
QCString stripIndentation(const QCString &s, bool skipFirstLine)
Definition util.cpp:6468
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3545
QCString stripScope(const QCString &name)
Definition util.cpp:4295
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, SrcLangExt lang, const QCString &prefix)
Definition util.cpp:3247
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:4020
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:7135
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5543
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:3417
A bunch of utility functions.