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 }
111 {
112 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
113 }
114 return result;
115}
116
117static void setParent(DocNodeVariant *n,DocNodeVariant *newParent)
118{
119 std::visit([&](auto &&x)->decltype(auto) { return x.setParent(newParent); }, *n);
120}
121
122//----------- DocStyleChange
123
125{
126 switch (m_style)
127 {
128 case DocStyleChange::Bold: return "b";
129 case DocStyleChange::Italic: return "em";
130 case DocStyleChange::Code: return "code";
131 case DocStyleChange::Center: return "center";
132 case DocStyleChange::Small: return "small";
133 case DocStyleChange::Cite: return "cite";
134 case DocStyleChange::Subscript: return "subscript";
135 case DocStyleChange::Superscript: return "superscript";
136 case DocStyleChange::Preformatted: return "pre";
137 case DocStyleChange::Div: return "div";
138 case DocStyleChange::Span: return "span";
139 case DocStyleChange::Strike: return "strike";
140 case DocStyleChange::S: return "s";
141 case DocStyleChange::Del: return "del";
142 case DocStyleChange::Underline: return "u";
143 case DocStyleChange::Ins: return "ins";
144 case DocStyleChange::Kbd: return "kbd";
145 case DocStyleChange::Typewriter: return "tt";
146 }
147 return "<invalid>";
148}
149
150//----------- DocSymbol
151
156
157//----------- DocEmoji
158
160 DocNode(parser,parent), m_symName(symName), m_index(-1)
161{
162 QCString locSymName = symName;
163 size_t len=locSymName.length();
164 if (len>0)
165 {
166 if (locSymName.at(len-1)!=':') locSymName.append(":");
167 if (locSymName.at(0)!=':') locSymName.prepend(":");
168 }
169 m_symName = locSymName;
171 if (m_index==-1)
172 {
173 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Found unsupported emoji symbol '{}'",m_symName);
174 }
175}
176
177//---------------------------------------------------------------------------
178
181{
182 //printf("new word %s url=%s\n",qPrint(word),qPrint(parser->context.searchUrl));
183 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
184 {
185 Doxygen::searchIndex.addWord(word,false);
186 }
187}
188
189//---------------------------------------------------------------------------
190
192 const QCString &ref,const QCString &file,
193 const QCString &anchor,const QCString &tooltip) :
197{
198 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
199 // qPrint(word),qPrint(parser->context.searchUrl),qPrint(tooltip));
200 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
201 {
202 Doxygen::searchIndex.addWord(word,false);
203 }
204}
205
206//---------------------------------------------------------------------------
207
209{
210 if (id.isEmpty())
211 {
212 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Empty anchor label");
213 return;
214 }
215
217 QCString anchorPrefix = ct.anchorPrefix();
218 if (id.left(anchorPrefix.length()) == anchorPrefix)
219 {
220 const CiteInfo *cite = ct.find(id.mid(anchorPrefix.length()));
221 if (cite)
222 {
224 m_anchor = id;
225 }
226 else
227 {
228 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid cite anchor id '{}'",id);
229 m_anchor = "invalid";
230 m_file = "invalid";
231 }
232 }
233 else if (newAnchor) // found <a name="label">
234 {
235 m_anchor = id;
236 }
237 else // found \anchor label
238 {
239 const SectionInfo *sec = SectionManager::instance().find(id);
240 if (sec)
241 {
242 //printf("Found anchor %s\n",qPrint(id));
243 m_file = sec->fileName();
244 m_anchor = sec->label();
245 }
246 else
247 {
248 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid anchor id '{}'",id);
249 m_anchor = "invalid";
250 m_file = "invalid";
251 }
252 }
253}
254
255//---------------------------------------------------------------------------
256
263
264
265//---------------------------------------------------------------------------
266
268{
269 AUTO_TRACE("file={} text={}",m_file,Trace::trunc(m_text));
270 switch(m_type)
271 {
272 case DontIncWithLines:
273 // fall through
274 case IncWithLines:
275 // fall through
276 case Include:
277 // fall through
278 case DontInclude:
287 //printf("parser->context.includeFile=<<%s>>\n",qPrint(parser->context.includeFileText));
288 break;
289 case VerbInclude:
290 // fall through
291 case HtmlInclude:
292 case LatexInclude:
298 break;
299 case Snippet:
300 case SnippetWithLines:
302 // check here for the existence of the blockId inside the file, so we
303 // only generate the warning once.
304 int count = 0;
305 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
306 {
307 warn_doc_error(parser()->context.fileName,
308 parser()->tokenizer.getLineNr(),
309 "block marked with {} for \\snippet should appear twice in file {}, found it {:d} times",
310 m_blockId,m_file,count);
311 }
312 break;
313 }
314}
315
316//---------------------------------------------------------------------------
317
319{
320 if (parser()->context.includeFileName.isEmpty())
321 {
322 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
323 "No previous '\\include' or '\\dontinclude' command for '\\{}' present",
324 typeAsString());
325 }
326 bool found = false;
327
329 const char *p = parser()->context.includeFileText.data();
330 size_t l = parser()->context.includeFileLength;
331 size_t o = parser()->context.includeFileOffset;
332 int il = parser()->context.includeFileLine;
333 AUTO_TRACE("text={} off={} len={}",Trace::trunc(p),o,l);
334 size_t so = o, bo = 0;
335 bool nonEmpty = FALSE;
336 switch(type())
337 {
338 case Line:
339 while (o<l)
340 {
341 char c = p[o];
342 if (c=='\n')
343 {
345 if (nonEmpty) break; // we have a pattern to match
346 so=o+1; // no pattern, skip empty line
347 }
348 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
349 {
350 nonEmpty=TRUE;
351 }
352 o++;
353 }
354 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
355 {
356 m_line = il;
358 found = true;
359 AUTO_TRACE_ADD("\\line {}",Trace::trunc(m_text));
360 }
361 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
364 break;
365 case SkipLine:
366 while (o<l)
367 {
368 so=o;
369 while (o<l)
370 {
371 char c = p[o];
372 if (c=='\n')
373 {
375 if (nonEmpty) break; // we have a pattern to match
376 so=o+1; // no pattern, skip empty line
377 }
378 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
379 {
380 nonEmpty=TRUE;
381 }
382 o++;
383 }
384 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
385 {
386 m_line = il;
388 found = true;
389 AUTO_TRACE_ADD("\\skipline {}",Trace::trunc(m_text));
390 break;
391 }
392 o++; // skip new line
393 }
394 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
397 break;
398 case Skip:
399 while (o<l)
400 {
401 so=o;
402 while (o<l)
403 {
404 char c = p[o];
405 if (c=='\n')
406 {
408 if (nonEmpty) break; // we have a pattern to match
409 so=o+1; // no pattern, skip empty line
410 }
411 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
412 {
413 nonEmpty=TRUE;
414 }
415 o++;
416 }
417 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
418 {
419 found = true;
420 break;
421 }
422 o++; // skip new line
423 }
424 parser()->context.includeFileOffset = so; // set pointer to start of new line
427 break;
428 case Until:
429 bo=o;
430 while (o<l)
431 {
432 so=o;
433 while (o<l)
434 {
435 char c = p[o];
436 if (c=='\n')
437 {
439 if (nonEmpty) break; // we have a pattern to match
440 so=o+1; // no pattern, skip empty line
441 }
442 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
443 {
444 nonEmpty=TRUE;
445 }
446 o++;
447 }
448 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
449 {
450 m_line = il;
452 found = true;
453 AUTO_TRACE_ADD("\\until {}",Trace::trunc(m_text));
454 break;
455 }
456 o++; // skip new line
457 }
458 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
461 break;
462 }
463 if (!found)
464 {
465 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
466 "referenced pattern '{}' for command '\\{}' not found",m_pattern,typeAsString());
467 }
468}
469
470//---------------------------------------------------------------------------
471
476
478{
480 if (refList && refList->isEnabled())
481 {
482 RefItem *item = refList->find(m_id);
483 ASSERT(item!=nullptr);
484 if (item)
485 {
486 if (parser()->context.memberDef && parser()->context.memberDef->name().at(0)=='@')
487 {
488 m_file = "@"; // can't cross reference anonymous enum
489 m_anchor = "@";
490 }
491 else
492 {
493 m_file = refList->fileName();
494 m_anchor = item->anchor();
495 }
496 m_title = refList->sectionTitle();
497 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
498 // qPrint(m_file),qPrint(m_anchor),qPrint(m_title));
499
500 if (!item->text().isEmpty())
501 {
502 parser()->pushContext();
504 parser()->popContext();
505 }
506 }
507 return TRUE;
508 }
509 return FALSE;
510}
511
512//---------------------------------------------------------------------------
513
515 m_relPath(parser->context.relPath)
516{
517 const Formula *formula = FormulaManager::instance().findFormula(id);
518 if (formula && !formula->text().isEmpty())
519 {
520 m_id = id;
521 m_name.sprintf("form_%d",m_id);
522 m_text = formula->text();
523 }
524 else // wrong \_form#<n> command
525 {
526 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Wrong formula id {:d}",id);
527 m_id = -1;
528 }
529}
530
531//---------------------------------------------------------------------------
532
537
539{
540 AUTO_TRACE();
541 auto ns = AutoNodeStack(parser(),thisVariant());
542
544 Token tok = parser()->tokenizer.lex();
545 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
546 {
547 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
548 {
549 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\refitem");
550 }
551 tok = parser()->tokenizer.lex();
552 }
555
556 if (!m_target.isEmpty())
557 {
559 if (sec==nullptr && parser()->context.lang==SrcLangExt::Markdown) // lookup as markdown file
560 {
562 }
563 if (sec) // ref to section or anchor
564 {
565 // set defaults
566 m_ref = sec->ref();
569 m_anchor = sec->label();
570 m_isSubPage = false;
571 // adjust if needed
572 switch (sec->type().level())
573 {
575 {
577 m_isSubPage = pd && pd->hasParentPage();
578 if (!m_isSubPage)
579 {
580 m_anchor="";
581 }
582 }
583 break;
586 break;
589 break;
590 default:
591 break;
592 }
593 //printf("m_ref=%s,m_file=%s,type=%d\n",
594 // qPrint(m_ref),qPrint(m_file),m_refType);
595 }
596 else
597 {
598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to unknown section {}",m_target);
599 }
600 }
601 else
602 {
603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to empty target");
604 }
605}
606
607//---------------------------------------------------------------------------
608
610{
611 AUTO_TRACE();
612 auto ns = AutoNodeStack(parser(),thisVariant());
613
614 Token tok=parser()->tokenizer.lex();
615 // skip white space
616 while (tok.is_any_of(TokenRetval::TK_WHITESPACE, TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
617 // handle items
618 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
619 {
620 if (tok.is_any_of(TokenRetval::TK_COMMAND_AT, TokenRetval::TK_COMMAND_BS))
621 {
622 switch (Mappers::cmdMapper->map(parser()->context.token->name))
623 {
625 {
626 tok=parser()->tokenizer.lex();
627 if (!tok.is(TokenRetval::TK_WHITESPACE))
628 {
629 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\refitem command");
630 break;
631 }
632 tok=parser()->tokenizer.lex();
633 if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
634 {
635 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\refitem",
636 tok.to_string());
637 break;
638 }
639
642 }
643 break;
645 return;
646 default:
647 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\secreflist",
648 tok.command_to_char(),qPrint(parser()->context.token->name));
649 return;
650 }
651 }
652 else if (tok.is(TokenRetval::TK_WHITESPACE))
653 {
654 // ignore whitespace
655 }
656 else
657 {
658 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} inside section reference list",
659 tok.to_string());
660 return;
661 }
662 tok=parser()->tokenizer.lex();
663 }
664
665}
666
667//---------------------------------------------------------------------------
668
671{
672 int i=ref.find('#');
673 if (i!=-1)
674 {
675 m_anchor = ref.right(static_cast<int>(ref.length())-i-1);
676 m_file = ref.left(i);
677 }
678 else
679 {
680 m_file = ref;
681 }
682}
683
685{
686 AUTO_TRACE();
687 auto ns = AutoNodeStack(parser(),thisVariant());
688
689 Token tok = parser()->tokenizer.lex();
690 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
691 {
692 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
693 {
695 }
696 tok=parser()->tokenizer.lex();
697 }
698
700}
701
702//---------------------------------------------------------------------------
703
706{
707 const Definition *compound = nullptr;
709 AUTO_TRACE("target='{}',context='{}'",target,context);
710 ASSERT(!target.isEmpty());
711 m_relPath = parser->context.relPath;
712 auto lang = parser->context.lang;
713 const SectionInfo *sec = SectionManager::instance().find(parser->context.prefix+target);
714 if (sec==nullptr && !parser->context.prefix.isEmpty())
715 {
716 sec = SectionManager::instance().find(target);
717 }
718
719 if (sec==nullptr && getLanguageFromFileName(target)==SrcLangExt::Markdown) // lookup as markdown file
720 {
722 }
723 if (sec) // ref to section or anchor
724 {
725 PageDef *pd = nullptr;
726 int secLevel = sec->type().level();
727 if (secLevel==SectionType::Page)
728 {
729 pd = Doxygen::pageLinkedMap->find(target);
730 }
731 m_text = sec->title();
732 if (m_text.isEmpty()) m_text = sec->label();
733
734 m_ref = sec->ref();
736 if (secLevel==SectionType::Anchor)
737 {
739 }
740 else if (secLevel==SectionType::Table)
741 {
743 }
744 else
745 {
747 }
748 m_isSubPage = pd && pd->hasParentPage();
749 if (secLevel!=SectionType::Page || m_isSubPage)
750 {
751 m_anchor = pd ? pd->getOutputFileBase() : sec->label();
752 }
753 m_sectionType = sec->type();
754 //printf("m_text=%s,m_ref=%s,m_file=%s,type=%d\n",
755 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),m_refType);
756 AUTO_TRACE_EXIT("section");
757 return;
758 }
759 else if (Config_getBool(IMPLICIT_DIR_DOCS) && target.lower().endsWith("/readme.md"))
760 {
761 QCString dirTarget = target.left(target.length() - 9); // strip readme.md part
762 const auto &dd = Doxygen::dirLinkedMap->find(dirTarget);
763 if (dd)
764 {
765 m_text = target;
766 m_file = dd->getOutputFileBase();
767 AUTO_TRACE_EXIT("directory");
768 return;
769 }
770 }
771 else if (resolveLink(context,target,true,&compound,anchor,lang,parser->context.prefix))
772 {
773 bool isFile = compound ?
774 (compound->definitionType()==Definition::TypeFile ||
776 FALSE;
777 if (compound && lang==SrcLangExt::Markdown) lang = compound->getLanguage();
778 m_text = linkToText(lang,target,isFile);
780 if (compound && compound->isLinkable()) // ref to compound
781 {
782 if (anchor.isEmpty() && /* compound link */
783 compound->definitionType()==Definition::TypeGroup && /* is group */
784 !toGroupDef(compound)->groupTitle().isEmpty() /* with title */
785 )
786 {
787 m_text=(toGroupDef(compound))->groupTitle(); // use group's title as link
788 }
789 else if (compound->definitionType()==Definition::TypeMember &&
790 toMemberDef(compound)->isObjCMethod())
791 {
792 // Objective C Method
793 const MemberDef *member = toMemberDef(compound);
794 bool localLink = parser->context.memberDef ? member->getClassDef()==parser->context.memberDef->getClassDef() : FALSE;
795 m_text = member->objCMethodName(localLink,parser->context.inSeeBlock);
796 }
797 else if (Config_getBool(HIDE_SCOPE_NAMES))
798 {
800 }
801
802 m_file = compound->getOutputFileBase();
803 m_ref = compound->getReference();
804 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
805 // compound->definitionType());
806 AUTO_TRACE_EXIT("compound");
807 return;
808 }
809 else if (compound && compound->definitionType()==Definition::TypeFile &&
810 toFileDef(compound)->generateSourceFile()
811 ) // undocumented file that has source code we can link to
812 {
813 m_file = compound->getSourceFileBase();
814 m_ref = compound->getReference();
815 AUTO_TRACE_EXIT("source");
816 return;
817 }
818 else
819 {
820 AUTO_TRACE_EXIT("compound '{}' not linkable",compound?compound->name():"none");
821 }
822 }
823 m_text = target;
824 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\ref command",
825 target);
826}
827
829{
830 for (auto &&elem : elements)
831 {
832 emplace_back(std::move(elem));
833 }
834 elements.clear();
835}
836
837static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
838{
839 DocNodeList newChildren;
840 for (auto &dn : children)
841 {
842 DocPara *para = std::get_if<DocPara>(&dn);
843 if (para)
844 {
845 //// move the children of the paragraph to the end of the newChildren list
846 newChildren.move_append(para->children());
847 }
848 }
849
850 // replace the children list by the newChildren list
851 children.clear();
852 children.move_append(newChildren);
853 // reparent the children
854 for (auto &cn : children)
855 {
856 setParent(&cn,root);
857 // we also need to set the parent for each child of cn, as cn's address may have changed.
858 auto opt_children = call_method_children(&cn);
859 if (opt_children)
860 {
861 for (auto &ccn : *opt_children)
862 {
863 setParent(&ccn,&cn);
864 }
865 }
866 }
867}
868
870{
871 AUTO_TRACE();
872 auto ns = AutoNodeStack(parser(),thisVariant());
873
874 Token tok = parser()->tokenizer.lex();
875 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
876 {
877 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
878 {
879 switch (tok.value())
880 {
881 case TokenRetval::TK_HTMLTAG:
882 break;
883 default:
885 break;
886 }
887 }
888 tok=parser()->tokenizer.lex();
889 }
890
891 if (children().empty() && !m_text.isEmpty())
892 {
893 QCString text = m_text;
894 if (parser()->context.insideHtmlLink)
895 {
896 // we already in a link/title only output anchor
897 text = m_anchor;
898 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
899 "Potential recursion while resolving \\ref command!");
900 }
902 parser()->pushContext();
904 parser()->popContext();
908 }
909
911}
912
913//---------------------------------------------------------------------------
914
916{
917 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
918 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
919 ASSERT(!target.isEmpty());
920 m_relPath = parser->context.relPath;
922 const CiteInfo *cite = ct.find(target);
923 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
924 m_option = opt;
926 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
927 {
928 m_ref = "";
929 m_anchor = ct.anchorPrefix()+cite->label();
931 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
932 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
933 return;
934 }
935 if (numBibFiles==0)
936 {
937 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
938 }
939 else if (cite==nullptr)
940 {
941 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\cite command",
942 target);
943 }
944 else
945 {
946 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '{}' does not have an associated number",
947 target);
948 }
949}
950
952{
953 QCString txt;
954 auto opt = m_option;
956 const CiteInfo *citeInfo = ct.find(m_target);
957
958 if (!opt.noPar()) txt += "[";
959
960 if (citeInfo)
961 {
962 if (opt.isNumber()) txt += citeInfo->text();
963 else if (opt.isShortAuthor()) txt += citeInfo->shortAuthor();
964 else if (opt.isYear()) txt += citeInfo->year();
965 }
966
967 if (!opt.noPar()) txt += "]";
968 return txt;
969}
970
971
972//---------------------------------------------------------------------------
973
975{
976 const Definition *compound = nullptr;
978 m_refText = target;
979 m_relPath = parser->context.relPath;
980 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
981 {
982 m_refText = m_refText.right(m_refText.length()-1);
983 }
984 if (resolveLink(parser->context.context,stripKnownExtensions(target),
985 parser->context.inSeeBlock,&compound,anchor,
986 parser->context.lang,parser->context.prefix))
987 {
988 m_anchor = anchor;
989 if (compound && compound->isLinkable())
990 {
991 m_file = compound->getOutputFileBase();
992 m_ref = compound->getReference();
993 }
994 else if (compound && compound->definitionType()==Definition::TypeFile &&
995 (toFileDef(compound))->generateSourceFile()
996 ) // undocumented file that has source code we can link to
997 {
998 m_file = compound->getSourceFileBase();
999 m_ref = compound->getReference();
1000 }
1001 return;
1002 }
1003
1004 // bogus link target
1005 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '{}' for \\link command",
1006 target);
1007}
1008
1009
1010QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
1011{
1012 AUTO_TRACE();
1013 QCString result;
1014 auto ns = AutoNodeStack(parser(),thisVariant());
1015
1016 Token tok = parser()->tokenizer.lex();
1017 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1018 {
1019 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
1020 {
1021 switch (tok.value())
1022 {
1023 case TokenRetval::TK_COMMAND_AT:
1024 // fall through
1025 case TokenRetval::TK_COMMAND_BS:
1026 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1027 {
1029 if (isJavaLink)
1030 {
1031 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{{@link...' ended with '{:c}{}' command",
1032 tok.command_to_char(),parser()->context.token->name);
1033 }
1034 goto endlink;
1035 default:
1036 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\link",
1037 tok.command_to_char(),parser()->context.token->name);
1038 break;
1039 }
1040 break;
1041 case TokenRetval::TK_SYMBOL:
1042 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a \\link",
1043 parser()->context.token->name);
1044 break;
1045 case TokenRetval::TK_HTMLTAG:
1046 if (parser()->context.token->name!="see" || !isXmlLink)
1047 {
1048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command {} found as part of a \\link",
1049 parser()->context.token->name);
1050 }
1051 goto endlink;
1052 case TokenRetval::TK_LNKWORD:
1053 case TokenRetval::TK_WORD:
1054 if (isJavaLink) // special case to detect closing }
1055 {
1057 int p = 0;
1058 if (w=="}")
1059 {
1060 goto endlink;
1061 }
1062 else if ((p=w.find('}'))!=-1)
1063 {
1064 int l = static_cast<int>(w.length());
1066 if (p<l-1) // something left after the } (for instance a .)
1067 {
1068 result=w.right(l-p-1);
1069 }
1070 goto endlink;
1071 }
1072 }
1074 break;
1075 default:
1076 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",tok.to_string());
1077 break;
1078 }
1079 }
1080 tok = parser()->tokenizer.lex();
1081 }
1082 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1083 {
1084 warn_doc_error(parser()->context.fileName,
1085 parser()->tokenizer.getLineNr(),
1086 "Unexpected end of comment while inside link command");
1087 }
1088endlink:
1089
1090 if (children().empty()) // no link text
1091 {
1093 }
1094
1096 return result;
1097}
1098
1099
1100//---------------------------------------------------------------------------
1101
1108
1110{
1111 bool ok = false;
1113
1114 bool ambig = false;
1116 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1117 {
1118 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1119 }
1120 if (fd)
1121 {
1122 p->file = fd->absFilePath();
1123 ok = true;
1124 if (ambig)
1125 {
1126 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '{}' is ambiguous.\n"
1127 "Possible candidates:\n{}",p->name,
1129 );
1130 }
1131 }
1132 else
1133 {
1134 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '{}' is not found "
1135 "in any of the paths specified via DOTFILE_DIRS!",p->name);
1136 }
1137 return ok;
1138}
1139
1146
1148{
1149 bool ok = false;
1151
1152 bool ambig = false;
1154 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1155 {
1156 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1157 }
1158 if (fd)
1159 {
1160 p->file = fd->absFilePath();
1161 ok = true;
1162 if (ambig)
1163 {
1164 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '{}' is ambiguous.\n"
1165 "Possible candidates:\n{}",qPrint(p->name),
1167 );
1168 }
1169 }
1170 else
1171 {
1172 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '{}' is not found "
1173 "in any of the paths specified via MSCFILE_DIRS!",p->name);
1174 }
1175 return ok;
1176}
1177
1178//---------------------------------------------------------------------------
1179
1186
1188{
1189 bool ok = false;
1191
1192 bool ambig = false;
1194 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1195 {
1196 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
1197 }
1198 if (fd)
1199 {
1200 p->file = fd->absFilePath();
1201 ok = true;
1202 if (ambig)
1203 {
1204 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file name '{}' is ambiguous.\n"
1205 "Possible candidates:\n{}",p->name,
1207 );
1208 }
1209 }
1210 else
1211 {
1212 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file '{}' is not found "
1213 "in any of the paths specified via DIAFILE_DIRS!",p->name);
1214 }
1215 return ok;
1216}
1217//---------------------------------------------------------------------------
1218
1225
1227{
1228 bool ok = false;
1230
1231 bool ambig = false;
1233 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1234 {
1235 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1236 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1237 {
1238 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1239 }
1240 }
1241 if (fd)
1242 {
1243 p->file = fd->absFilePath();
1244 ok = true;
1245 if (ambig)
1246 {
1247 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '{}' is ambiguous.\n"
1248 "Possible candidates:\n{}",p->name,
1250 );
1251 }
1252 }
1253 else
1254 {
1255 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '{}' is not found "
1256 "in any of the paths specified via PLANTUMLFILE_DIRS!",p->name);
1257 }
1258 return ok;
1259}
1260
1261//---------------------------------------------------------------------------
1262
1266
1268{
1269 AUTO_TRACE();
1270 auto ns = AutoNodeStack(parser(),thisVariant());
1271
1273 Token tok = parser()->tokenizer.lex();
1274 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1275 {
1276 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1277 {
1278 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1279 }
1280 tok = parser()->tokenizer.lex();
1281 }
1282 parser()->tokenizer.lex();
1283
1286
1287 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1288}
1289
1290
1291//---------------------------------------------------------------------------
1292
1294 Type t,const QCString &url, bool inlineImage) :
1295 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1296{
1297}
1298
1300{
1301 QCString locName = p->url.isEmpty() ? p->name : p->url;
1302 int len = static_cast<int>(locName.length());
1303 int fnd = locName.find('?'); // ignore part from ? until end
1304 if (fnd==-1) fnd=len;
1305 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1306}
1307
1312
1313
1314//---------------------------------------------------------------------------
1315
1317{
1318 AUTO_TRACE();
1319 Token retval(TokenRetval::RetVal_OK);
1320 auto ns = AutoNodeStack(parser(),thisVariant());
1321
1322 Token tok = parser()->tokenizer.lex();
1323 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1324 {
1325 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1326 {
1327 switch (tok.value())
1328 {
1329 case TokenRetval::TK_HTMLTAG:
1330 {
1331 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1332 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1333 {
1334 if (m_level!=1)
1335 {
1336 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h1>",
1337 m_level);
1338 }
1339 goto endheader;
1340 }
1341 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1342 {
1343 if (m_level!=2)
1344 {
1345 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h2>",
1346 m_level);
1347 }
1348 goto endheader;
1349 }
1350 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1351 {
1352 if (m_level!=3)
1353 {
1354 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h3>",
1355 m_level);
1356 }
1357 goto endheader;
1358 }
1359 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1360 {
1361 if (m_level!=4)
1362 {
1363 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h4>",
1364 m_level);
1365 }
1366 goto endheader;
1367 }
1368 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1369 {
1370 if (m_level!=5)
1371 {
1372 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h5>",
1373 m_level);
1374 }
1375 goto endheader;
1376 }
1377 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1378 {
1379 if (m_level!=6)
1380 {
1381 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h6>",
1382 m_level);
1383 }
1384 goto endheader;
1385 }
1386 else if (tagId==HtmlTagType::HTML_A)
1387 {
1388 if (!parser()->context.token->endTag)
1389 {
1390 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1391 }
1392 }
1393 else if (tagId==HtmlTagType::HTML_BR)
1394 {
1396 }
1397 else
1398 {
1399 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <h{:d}> context",
1400 parser()->context.token->endTag?"/":"",parser()->context.token->name,m_level);
1401 }
1402 }
1403 break;
1404 default:
1405 char tmp[20];
1406 qsnprintf(tmp,20,"<h%d> tag",m_level);
1408 }
1409 }
1410 tok = parser()->tokenizer.lex();
1411 }
1412 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1413 {
1414 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1415 " <h{:d}> tag",m_level);
1416 }
1417endheader:
1419 return retval;
1420}
1421//---------------------------------------------------------------------------
1422
1424{
1425 AUTO_TRACE();
1426 auto ns = AutoNodeStack(parser(),thisVariant());
1428 Token tok = parser()->tokenizer.lex();
1429 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1430 {
1432 // check of </summary>
1433 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1434 (tagId=Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1435 parser()->context.token->endTag
1436 )
1437 {
1438 break;
1439 }
1440 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1441 {
1442 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1443 }
1444 tok = parser()->tokenizer.lex();
1445 }
1447 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1448 {
1449 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1450 " <summary> tag");
1451 }
1452}
1453
1454//---------------------------------------------------------------------------
1455
1457{
1458 AUTO_TRACE();
1459 Token retval(TokenRetval::TK_NONE);
1460 auto ns = AutoNodeStack(parser(),thisVariant());
1461
1462 // parse one or more paragraphs
1463 bool isFirst=TRUE;
1464 DocPara *par=nullptr;
1465 do
1466 {
1468 par = children().get_last<DocPara>();
1469 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1470 retval=par->parse();
1471 }
1472 while (retval.is(TokenRetval::TK_NEWPARA));
1473 if (par) par->markLast();
1474
1475 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1476 {
1477 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1478 }
1479
1480 if (!summary())
1481 {
1482 HtmlAttribList summaryAttribs;
1484 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1485 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1486 }
1487 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1488 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1489}
1490
1498
1499//---------------------------------------------------------------------------
1500
1502{
1503 AUTO_TRACE();
1504 Token retval(TokenRetval::RetVal_OK);
1505 auto ns = AutoNodeStack(parser(),thisVariant());
1506
1507 Token tok = parser()->tokenizer.lex();
1508 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1509 {
1510 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1511 {
1512 switch (tok.value())
1513 {
1514 case TokenRetval::TK_HTMLTAG:
1515 {
1516 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1517 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1518 {
1519 goto endhref;
1520 }
1521 else if (tagId==HtmlTagType::HTML_BR)
1522 {
1524 }
1525 else
1526 {
1527 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <a href=...> context",
1528 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1529 }
1530 }
1531 break;
1532 default:
1533 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1534 break;
1535 }
1536 }
1537 tok = parser()->tokenizer.lex();
1538 }
1539 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1540 {
1541 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1542 " <a href=...> tag");
1543 }
1544endhref:
1546 return retval;
1547}
1548
1549//---------------------------------------------------------------------------
1550
1552{
1553 AUTO_TRACE();
1554 Token retval(TokenRetval::RetVal_OK);
1555 auto ns = AutoNodeStack(parser(),thisVariant());
1556
1557 // first parse any number of paragraphs
1558 bool isFirst=TRUE;
1559 DocPara *lastPar=nullptr;
1560 do
1561 {
1563 DocPara *par = children().get_last<DocPara>();
1564 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1565 retval=par->parse();
1566 if (!par->isEmpty())
1567 {
1568 if (lastPar) lastPar->markLast(FALSE);
1569 lastPar=par;
1570 }
1571 else
1572 {
1573 children().pop_back();
1574 }
1575 if (retval.is(TokenRetval::TK_LISTITEM))
1576 {
1577 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1578 }
1579 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1580 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1581 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1582 TokenRetval::RetVal_EndInternal));
1583 if (lastPar) lastPar->markLast();
1584
1585 // then parse any number of level-n sections
1586 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1587 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1588 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1589 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1590 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1591 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1592 )
1593 {
1595 level,
1597 retval = children().get_last<DocSection>()->parse();
1598 }
1599
1600 if (retval.is(TokenRetval::RetVal_Internal))
1601 {
1602 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1603 }
1604
1605 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1606 return retval;
1607}
1608
1609//---------------------------------------------------------------------------
1610
1612{
1613 AUTO_TRACE();
1614 Token retval(TokenRetval::RetVal_OK);
1615 auto ns = AutoNodeStack(parser(),thisVariant());
1616 Token tok=parser()->tokenizer.lex();
1617 if (!tok.is(TokenRetval::TK_WHITESPACE))
1618 {
1619 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1620 goto endindexentry;
1621 }
1623 m_entry="";
1624 tok = parser()->tokenizer.lex();
1625 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1626 {
1627 switch (tok.value())
1628 {
1629 case TokenRetval::TK_WHITESPACE:
1630 m_entry+=" ";
1631 break;
1632 case TokenRetval::TK_WORD:
1633 case TokenRetval::TK_LNKWORD:
1635 break;
1636 case TokenRetval::TK_SYMBOL:
1637 {
1638 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1639 switch (s)
1640 {
1641 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1642 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1643 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1644 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1645 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1646 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1647 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1648 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1649 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1650 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1651 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1652 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1653 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1654 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1655 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1656 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1657 default:
1658 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '{}' found as argument of \\addindex",parser()->context.token->name);
1659 break;
1660 }
1661 }
1662 break;
1663 case TokenRetval::TK_COMMAND_AT:
1664 // fall through
1665 case TokenRetval::TK_COMMAND_BS:
1666 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1667 {
1668 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1669 case CommandType::CMD_AT: m_entry+='@'; break;
1670 case CommandType::CMD_LESS: m_entry+='<'; break;
1671 case CommandType::CMD_GREATER: m_entry+='>'; break;
1672 case CommandType::CMD_AMP: m_entry+='&'; break;
1673 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1674 case CommandType::CMD_HASH: m_entry+='#'; break;
1675 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1676 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1677 case CommandType::CMD_NDASH: m_entry+="--"; break;
1678 case CommandType::CMD_MDASH: m_entry+="---"; break;
1679 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1680 case CommandType::CMD_PUNT: m_entry+='.'; break;
1681 case CommandType::CMD_PLUS: m_entry+='+'; break;
1682 case CommandType::CMD_MINUS: m_entry+='-'; break;
1683 case CommandType::CMD_EQUAL: m_entry+='='; break;
1684 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1685 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1686 default:
1687 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command {} found as argument of \\addindex",
1688 parser()->context.token->name);
1689 break;
1690 }
1691 break;
1692 default:
1693 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
1694 tok.to_string());
1695 break;
1696 }
1697 tok = parser()->tokenizer.lex();
1698 }
1700 m_entry = m_entry.stripWhiteSpace();
1701endindexentry:
1702 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1703 return retval;
1704}
1705
1706//---------------------------------------------------------------------------
1707
1710{
1712 for (const auto &opt : attribs)
1713 {
1714 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1715 {
1716 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1717 if (sec)
1718 {
1719 //printf("Found anchor %s\n",qPrint(id));
1720 m_file = sec->fileName();
1721 m_anchor = sec->label();
1723 }
1724 else
1725 {
1726 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '{}'",opt.value);
1727 }
1728 }
1729 else // copy attribute
1730 {
1731 m_attribs.push_back(opt);
1732 }
1733 }
1734}
1735
1737{
1738 AUTO_TRACE();
1739 Token retval = Token::make_TK_NONE();
1740 auto ns = AutoNodeStack(parser(),thisVariant());
1741 Token tok = parser()->tokenizer.lex();
1742 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1743 {
1744 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1745 {
1746 switch (tok.value())
1747 {
1748 case TokenRetval::TK_HTMLTAG:
1749 {
1750 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1751 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1752 {
1753 retval = Token::make_RetVal_OK();
1754 goto endcaption;
1755 }
1756 else
1757 {
1758 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <caption> context",
1759 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1760 }
1761 }
1762 break;
1763 default:
1764 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1765 break;
1766 }
1767 }
1768 tok = parser()->tokenizer.lex();
1769 }
1770 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1771 {
1772 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1773 " <caption> tag");
1774 }
1775endcaption:
1777 return retval;
1778}
1779
1780//---------------------------------------------------------------------------
1781
1783{
1784 AUTO_TRACE();
1785 Token retval = Token::make_RetVal_OK();
1786 auto ns = AutoNodeStack(parser(),thisVariant());
1787
1788 // parse one or more paragraphs
1789 bool isFirst=TRUE;
1790 DocPara *par=nullptr;
1791 do
1792 {
1794 par = children().get_last<DocPara>();
1795 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1796 retval=par->parse();
1797 if (retval.is(TokenRetval::TK_HTMLTAG))
1798 {
1799 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1800 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1801 {
1802 retval = Token::make_TK_NEWPARA(); // ignore the tag
1803 }
1804 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1805 {
1806 retval = Token::make_TK_NEWPARA(); // ignore the tag
1807 }
1808 }
1809 }
1810 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1811 if (par) par->markLast();
1812
1813 return retval;
1814}
1815
1817{
1818 AUTO_TRACE();
1819 Token retval = Token::make_RetVal_OK();
1820 auto ns = AutoNodeStack(parser(),thisVariant());
1821
1822 // parse one or more paragraphs
1823 bool isFirst=TRUE;
1824 DocPara *par=nullptr;
1825 do
1826 {
1828 par = children().get_last<DocPara>();
1829 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1830 retval=par->parse();
1831 if (retval.is(TokenRetval::TK_HTMLTAG))
1832 {
1833 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1834 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1835 {
1836 retval = Token::make_TK_NEWPARA(); // ignore the tag
1837 }
1838 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1839 {
1840 retval = Token::make_TK_NEWPARA(); // ignore the tag
1841 }
1842 }
1843 }
1844 while (retval.is(TokenRetval::TK_NEWPARA));
1845 if (par) par->markLast();
1846
1847 return retval;
1848}
1849
1850uint32_t DocHtmlCell::rowSpan() const
1851{
1852 for (const auto &attr : attribs())
1853 {
1854 if (attr.name.lower()=="rowspan")
1855 {
1856 return attr.value.toUInt();
1857 }
1858 }
1859 return 0;
1860}
1861
1862uint32_t DocHtmlCell::colSpan() const
1863{
1864 for (const auto &attr : attribs())
1865 {
1866 if (attr.name.lower()=="colspan")
1867 {
1868 return std::max(1u,attr.value.toUInt());
1869 }
1870 }
1871 return 1;
1872}
1873
1875{
1876 for (const auto &attr : attribs())
1877 {
1878 QCString attrName = attr.name.lower();
1879 QCString attrValue = attr.value.lower();
1880 if (attrName=="align")
1881 {
1882 if (attrValue=="center")
1883 return Center;
1884 else if (attrValue=="right")
1885 return Right;
1886 else return Left;
1887 }
1888 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1889 {
1890 if (attrValue=="markdowntableheadcenter")
1891 return Center;
1892 else if (attrValue=="markdowntableheadright")
1893 return Right;
1894 else if (attrValue=="markdowntableheadleft")
1895 return Left;
1896 else if (attrValue=="markdowntableheadnone")
1897 return Center;
1898 else if (attrValue=="markdowntablebodycenter")
1899 return Center;
1900 else if (attrValue=="markdowntablebodyright")
1901 return Right;
1902 else if (attrValue=="markdowntablebodyleft")
1903 return Left;
1904 else if (attrValue=="markdowntablebodynone")
1905 return Left;
1906 else return Left;
1907 }
1908 }
1909 return Left;
1910}
1911
1913{
1914 for (const auto &attr : attribs())
1915 {
1916 QCString attrName = attr.name.lower();
1917 QCString attrValue = attr.value.lower();
1918 if (attrName=="valign")
1919 {
1920 if (attrValue=="top")
1921 return Top;
1922 else if (attrValue=="bottom")
1923 return Bottom;
1924 else if (attrValue=="middle")
1925 return Middle;
1926 else return Middle;
1927 }
1928 }
1929 return Middle;
1930}
1931
1932//---------------------------------------------------------------------------
1933
1935{ // a row is a table heading if all cells are marked as such
1936 bool heading=TRUE;
1937 for (const auto &n : children())
1938 {
1939 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1940 if (cell && !cell->isHeading())
1941 {
1942 heading = FALSE;
1943 break;
1944 }
1945 }
1946 return !children().empty() && heading;
1947}
1948
1950{
1951 AUTO_TRACE();
1952 // get next token
1953 Token tok=parser->tokenizer.lex();
1954 // skip whitespace and tbody, thead and tfoot tags
1955 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA,TokenRetval::TK_HTMLTAG,
1956 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS))
1957 {
1958 if (tok.is(TokenRetval::TK_HTMLTAG))
1959 {
1960 AUTO_TRACE_ADD("html_tag={}",parser->context.token->name);
1962 // skip over tbody, thead, tfoot tags
1963 if (tagId==HtmlTagType::HTML_TBODY ||
1964 tagId==HtmlTagType::HTML_THEAD ||
1966 {
1967 tok=parser->tokenizer.lex();
1968 }
1969 else
1970 {
1971 break;
1972 }
1973 }
1974 else if (tok.is(TokenRetval::TK_COMMAND_AT) || tok.is(TokenRetval::TK_COMMAND_BS))
1975 {
1976 QCString cmdName=parser->context.token->name;
1977 AUTO_TRACE_ADD("command={}",cmdName);
1978 auto cmdType = Mappers::cmdMapper->map(cmdName);
1979 if (cmdType==CommandType::CMD_ILINE)
1980 {
1981 parser->tokenizer.pushState();
1982 parser->tokenizer.setStateILine();
1983 tok = parser->tokenizer.lex();
1984 if (!tok.is(TokenRetval::TK_WORD))
1985 {
1986 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
1987 tok.command_to_char(),cmdName);
1988 }
1989 parser->tokenizer.popState();
1990 tok = parser->tokenizer.lex();
1991 }
1992 else
1993 {
1994 break;
1995 }
1996 }
1997 else
1998 {
1999 AUTO_TRACE_ADD("skip whitespace");
2000 tok=parser->tokenizer.lex();
2001 }
2002 }
2003 return tok;
2004}
2005
2006
2007
2008
2010{
2011 AUTO_TRACE();
2012 Token retval = Token::make_RetVal_OK();
2013 auto ns = AutoNodeStack(parser(),thisVariant());
2014
2015 bool isHeading=FALSE;
2016 bool isFirst=TRUE;
2017 DocHtmlCell *cell=nullptr;
2018
2020 // should find a html tag now
2021 if (tok.is(TokenRetval::TK_HTMLTAG))
2022 {
2023 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2024 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
2025 {
2026 }
2027 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
2028 {
2030 }
2031 else // found some other tag
2032 {
2033 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
2034 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2035 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2036 goto endrow;
2037 }
2038 }
2039 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2040 {
2041 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2042 " for a html description title");
2043 goto endrow;
2044 }
2045 else // token other than html token
2046 {
2047 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2048 tok.to_string());
2049 goto endrow;
2050 }
2051
2052 // parse one or more cells
2053 do
2054 {
2057 isHeading);
2058 cell = children().get_last<DocHtmlCell>();
2059 cell->markFirst(isFirst);
2060 isFirst=FALSE;
2061 retval=cell->parse();
2062 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
2063 //printf("DocHtmlRow:retval=%s\n",retval.to_string());
2064 if (retval.is(TokenRetval::RetVal_EndTableCell))
2065 {
2066 // get next token
2067 retval = skipSpacesForTable(parser());
2068 //printf("DocHtmlRow:retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2069 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2070 if (tok.is(TokenRetval::TK_HTMLTAG))
2071 {
2072 if ((tagId==HtmlTagType::HTML_TD || tagId==HtmlTagType::HTML_TH) &&
2073 !parser()->context.token->endTag) // found new <td> or <td> tag
2074 {
2075 retval = Token::make_RetVal_TableCell();
2077 }
2078 else if (tagId==HtmlTagType::HTML_TR)
2079 {
2080 if (parser()->context.token->endTag) // found </tr> tag
2081 {
2082 retval = Token::make_RetVal_EndTableRow();
2083 }
2084 else // found <tr> tag
2085 {
2086 retval = Token::make_RetVal_TableRow();
2087 }
2088 }
2089 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag) // found </table>
2090 {
2091 retval = Token::make_RetVal_EndTable();
2092 }
2093 else // found some other tag
2094 {
2095 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but "
2096 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2097 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2098 goto endrow;
2099 }
2100 }
2101 else // token other than html token
2102 {
2103 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but found {} token instead!",
2104 tok.to_string());
2105 goto endrow;
2106 }
2107 }
2108 }
2109 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2110 cell->markLast(TRUE);
2111
2112endrow:
2113 return retval;
2114}
2115
2117{
2118 AUTO_TRACE();
2119 Token retval = Token::make_RetVal_OK();
2120 auto ns = AutoNodeStack(parser(),thisVariant());
2121
2122 bool isFirst=TRUE;
2123 DocHtmlCell *cell=nullptr;
2124
2125 // get next token
2126 Token tok=parser()->tokenizer.lex();
2127 // skip whitespace
2128 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2129 // should find a html tag now
2130 if (tok.is(TokenRetval::TK_HTMLTAG))
2131 {
2132 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2133 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
2134 {
2135 }
2136 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
2137 {
2138 }
2139 else // found some other tag
2140 {
2141 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
2142 "found <{}> instead!",parser()->context.token->name);
2143 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2144 goto endrow;
2145 }
2146 }
2147 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2148 {
2149 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2150 " for a html description title");
2151 goto endrow;
2152 }
2153 else // token other than html token
2154 {
2155 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2156 tok.to_string());
2157 goto endrow;
2158 }
2159
2160 do
2161 {
2163 cell = children().get_last<DocHtmlCell>();
2164 cell->markFirst(isFirst);
2165 isFirst=FALSE;
2166 retval=cell->parseXml();
2167 }
2168 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2169 cell->markLast(TRUE);
2170
2171endrow:
2172 return retval;
2173}
2174
2175//---------------------------------------------------------------------------
2176
2178{
2179 return m_caption!=nullptr;
2180}
2181
2183{
2184 return m_caption.get();
2185}
2186
2188{
2189 size_t hl = 0;
2190 for (auto &rowNode : children())
2191 {
2192 const DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2193 if (row)
2194 {
2195 if (!row->isHeading()) break;
2196 hl++;
2197 }
2198 }
2199 return hl;
2200}
2201
2203{
2204 AUTO_TRACE();
2205 Token retval = Token::make_RetVal_OK();
2206 auto ns = AutoNodeStack(parser(),thisVariant());
2207
2208getrow:
2209 // skip whitespace and tbody, thead and tfoot tags
2211 // should find a html tag now
2212 if (tok.is(TokenRetval::TK_HTMLTAG))
2213 {
2214 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2215 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2216 {
2217 // no caption, just rows
2218 retval = Token::make_RetVal_TableRow();
2219 }
2220 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2221 {
2222 if (m_caption)
2223 {
2224 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2225 }
2226 else
2227 {
2228 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2229 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2230
2231 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2232 {
2233 goto getrow;
2234 }
2235 }
2236 }
2237 else // found wrong token
2238 {
2239 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2240 "found <{}{}> instead!", parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2241 }
2242 }
2243 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2244 {
2245 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2246 " for a <tr> or <caption> tag");
2247 }
2248 else // token other than html token
2249 {
2250 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found {} token instead!",
2251 tok.to_string());
2252 }
2253
2254 // parse one or more rows
2255 while (retval.is(TokenRetval::RetVal_TableRow))
2256 {
2258 retval = children().get_last<DocHtmlRow>()->parse();
2259 //printf("DocHtmlTable::retval=%s\n",retval.to_string());
2260 if (retval.is(TokenRetval::RetVal_EndTableRow))
2261 {
2262 // get next token
2263 retval = skipSpacesForTable(parser());
2264 //printf("DocHtmlTable::retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2265 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2266 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag)
2267 {
2268 retval = Token::make_RetVal_TableRow();
2269 }
2270 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag)
2271 {
2272 retval = Token::make_RetVal_EndTable();
2273 }
2274 else // found some other tag
2275 {
2276 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or </table> tag but "
2277 "found token {} instead!",retval.to_string());
2278 retval=Token::make_RetVal_OK();
2279 break;
2280 }
2281 }
2282 }
2283
2285
2286 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2287}
2288
2290{
2291 AUTO_TRACE();
2292 Token retval = Token::make_RetVal_OK();
2293 auto ns = AutoNodeStack(parser(),thisVariant());
2294
2295 // get next token
2296 Token tok=parser()->tokenizer.lex();
2297 // skip whitespace
2298 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2299 // should find a html tag now
2301 bool isHeader=FALSE;
2302 if (tok.is(TokenRetval::TK_HTMLTAG))
2303 {
2304 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2305 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2306 {
2307 retval = Token::make_RetVal_TableRow();
2308 }
2309 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2310 {
2311 retval = Token::make_RetVal_TableRow();
2312 isHeader=TRUE;
2313 }
2314 }
2315
2316 // parse one or more rows
2317 while (retval.is(TokenRetval::RetVal_TableRow))
2318 {
2321 retval=tr->parseXml(isHeader);
2322 isHeader=FALSE;
2323 }
2324
2326
2327 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2328 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2329}
2330
2331/** Helper class to compute the grid for an HTML style table */
2333{
2334 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2335 uint32_t rowsLeft;
2336 uint32_t column;
2337};
2338
2339/** List of ActiveRowSpan classes. */
2340typedef std::vector<ActiveRowSpan> RowSpanList;
2341
2342/** determines the location of all cells in a grid, resolving row and
2343 column spans. For each the total number of visible cells is computed,
2344 and the total number of visible columns over all rows is stored.
2345 */
2347{
2348 //printf("computeTableGrid()\n");
2349 RowSpanList rowSpans;
2350 uint32_t maxCols=0;
2351 uint32_t rowIdx=1;
2352 for (auto &rowNode : children())
2353 {
2354 uint32_t colIdx=1;
2355 uint32_t cells=0;
2356 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2357 if (row)
2358 {
2359 for (auto &cellNode : row->children())
2360 {
2361 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2362 if (cell)
2363 {
2364 uint32_t rs = cell->rowSpan();
2365 uint32_t cs = cell->colSpan();
2366
2367 for (size_t i=0;i<rowSpans.size();i++)
2368 {
2369 if (rowSpans[i].rowsLeft>0 &&
2370 rowSpans[i].column==colIdx)
2371 {
2372 colIdx=rowSpans[i].column+1;
2373 cells++;
2374 }
2375 }
2376 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2377 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2378 cell->setRowIndex(rowIdx);
2379 cell->setColumnIndex(colIdx);
2380 colIdx+=cs;
2381 cells++;
2382 }
2383 }
2384 for (size_t i=0;i<rowSpans.size();i++)
2385 {
2386 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2387 }
2388 row->setVisibleCells(cells);
2389 row->setRowIndex(rowIdx);
2390 rowIdx++;
2391 }
2392 if (colIdx-1>maxCols) maxCols=colIdx-1;
2393 }
2394 m_numCols = maxCols;
2395}
2396
2397//---------------------------------------------------------------------------
2398
2400{
2401 AUTO_TRACE();
2402 Token retval = Token::make_TK_NONE();
2403 auto ns = AutoNodeStack(parser(),thisVariant());
2404
2405 Token tok = parser()->tokenizer.lex();
2406 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2407 {
2408 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2409 {
2410 switch (tok.value())
2411 {
2412 case TokenRetval::TK_COMMAND_AT:
2413 // fall through
2414 case TokenRetval::TK_COMMAND_BS:
2415 {
2416 QCString cmdName=parser()->context.token->name;
2417 bool isJavaLink=FALSE;
2418 switch (Mappers::cmdMapper->map(cmdName))
2419 {
2421 {
2422 tok=parser()->tokenizer.lex();
2423 if (!tok.is(TokenRetval::TK_WHITESPACE))
2424 {
2425 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
2426 tok.command_to_char(),cmdName);
2427 }
2428 else
2429 {
2431 tok=parser()->tokenizer.lex(); // get the reference id
2432 if (!tok.is(TokenRetval::TK_WORD))
2433 {
2434 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}' command",
2435 tok.to_string(),tok.command_to_char(),cmdName);
2436 }
2437 else
2438 {
2440 children().get_last<DocRef>()->parse();
2441 }
2443 }
2444 }
2445 break;
2447 isJavaLink=TRUE;
2448 // fall through
2450 {
2451 tok=parser()->tokenizer.lex();
2452 if (!tok.is(TokenRetval::TK_WHITESPACE))
2453 {
2454 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
2455 cmdName);
2456 }
2457 else
2458 {
2460 tok=parser()->tokenizer.lex();
2461 if (!tok.is(TokenRetval::TK_WORD))
2462 {
2463 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\{} command",
2464 tok.to_string(),cmdName);
2465 }
2466 else
2467 {
2470 DocLink *lnk = children().get_last<DocLink>();
2471 QCString leftOver = lnk->parse(isJavaLink);
2472 if (!leftOver.isEmpty())
2473 {
2474 children().append<DocWord>(parser(),thisVariant(),leftOver);
2475 }
2476 }
2477 }
2478 }
2479
2480 break;
2481 default:
2482 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' found as part of a <dt> tag",
2483 tok.command_to_char(),cmdName);
2484 }
2485 }
2486 break;
2487 case TokenRetval::TK_SYMBOL:
2488 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a <dt> tag",
2489 parser()->context.token->name);
2490 break;
2491 case TokenRetval::TK_HTMLTAG:
2492 {
2493 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2494 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2495 {
2496 retval = Token::make_RetVal_DescData();
2497 goto endtitle;
2498 }
2499 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2500 {
2501 // ignore </dt> tag.
2502 }
2503 else if (tagId==HtmlTagType::HTML_DT)
2504 {
2505 // missing <dt> tag.
2506 retval = Token::make_RetVal_DescTitle();
2507 goto endtitle;
2508 }
2509 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2510 {
2511 retval = Token::make_RetVal_EndDesc();
2512 goto endtitle;
2513 }
2514 else if (tagId==HtmlTagType::HTML_A)
2515 {
2516 if (!parser()->context.token->endTag)
2517 {
2518 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2519 }
2520 }
2521 else
2522 {
2523 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <dt> context",
2524 parser()->context.token->endTag?"/":"",parser()->context.token->name);
2525 }
2526 }
2527 break;
2528 default:
2529 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} found as part of a <dt> tag",
2530 tok.to_string());
2531 break;
2532 }
2533 }
2534 tok = parser()->tokenizer.lex();
2535 }
2536 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2537 {
2538 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2539 " <dt> tag");
2540 }
2541endtitle:
2543 return retval;
2544}
2545
2546//---------------------------------------------------------------------------
2547
2549{
2550 AUTO_TRACE();
2552 Token retval = Token::make_TK_NONE();
2553 auto ns = AutoNodeStack(parser(),thisVariant());
2554
2555 bool isFirst=TRUE;
2556 DocPara *par=nullptr;
2557 do
2558 {
2560 par = children().get_last<DocPara>();
2561 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2562 retval=par->parse();
2563 }
2564 while (retval.is(TokenRetval::TK_NEWPARA));
2565 if (par) par->markLast();
2566
2567 return retval;
2568}
2569
2570//---------------------------------------------------------------------------
2571
2573{
2574 AUTO_TRACE();
2575 Token retval = Token::make_RetVal_OK();
2576 auto ns = AutoNodeStack(parser(),thisVariant());
2577
2578 // get next token
2579 Token tok=parser()->tokenizer.lex();
2580 // skip whitespace
2581 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2582 // should find a html tag now
2583 if (tok.is(TokenRetval::TK_HTMLTAG))
2584 {
2585 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2586 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2587 {
2588 // continue
2589 }
2590 else // found some other tag
2591 {
2592 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2593 "found <{}> instead!",parser()->context.token->name);
2594 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2595 goto enddesclist;
2596 }
2597 }
2598 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2599 {
2600 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2601 " for a html description title");
2602 goto enddesclist;
2603 }
2604 else // token other than html token
2605 {
2606 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found {} token instead!",
2607 tok.to_string());
2608 goto enddesclist;
2609 }
2610
2611 do
2612 {
2617 retval=dt->parse();
2618 if (retval.is(TokenRetval::RetVal_DescData))
2619 {
2620 retval=dd->parse();
2621 while (retval.is(TokenRetval::RetVal_DescData))
2622 {
2625 retval=dd->parse();
2626 }
2627 }
2628 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2629 {
2630 // error
2631 break;
2632 }
2633 } while (retval.is(TokenRetval::RetVal_DescTitle));
2634
2635 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2636 {
2637 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2638 }
2639
2640enddesclist:
2641
2642 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2643}
2644
2645//---------------------------------------------------------------------------
2646
2648{
2649 AUTO_TRACE();
2650 Token retval = Token::make_TK_NONE();
2651 auto ns = AutoNodeStack(parser(),thisVariant());
2652
2653 // parse one or more paragraphs
2654 bool isFirst=TRUE;
2655 DocPara *par=nullptr;
2656 do
2657 {
2659 par = children().get_last<DocPara>();
2660 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2661 retval=par->parse();
2662 }
2663 while (retval.is(TokenRetval::TK_NEWPARA));
2664 if (par) par->markLast();
2665
2666 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2667 return retval;
2668}
2669
2671{
2672 AUTO_TRACE();
2673 Token retval = Token::make_TK_NONE();
2674 auto ns = AutoNodeStack(parser(),thisVariant());
2675
2676 // parse one or more paragraphs
2677 bool isFirst=TRUE;
2678 DocPara *par=nullptr;
2679 do
2680 {
2682 par = children().get_last<DocPara>();
2683 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2684 retval=par->parse();
2685 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2686
2687 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2688 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2689 if (retval.is(TokenRetval::RetVal_ListItem))
2690 {
2691 break;
2692 }
2693 }
2694 while (!retval.is(TokenRetval::RetVal_CloseXml));
2695
2696 if (par) par->markLast();
2697
2698 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2699 return retval;
2700}
2701
2702//---------------------------------------------------------------------------
2703
2705{
2706 AUTO_TRACE();
2707 Token retval = Token::make_RetVal_OK();
2708 int num=1;
2709 auto ns = AutoNodeStack(parser(),thisVariant());
2710
2711 // get next token
2712 Token tok=parser()->tokenizer.lex();
2713 // skip whitespace and paragraph breaks
2714 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2715 // should find a html tag now
2716 if (tok.is(TokenRetval::TK_HTMLTAG))
2717 {
2718 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2719 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2720 {
2721 // ok, we can go on.
2722 }
2723 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2725 ) && parser()->context.token->endTag
2726 ) // found empty list
2727 {
2728 // add dummy item to obtain valid HTML
2730 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2731 retval = Token::make_RetVal_EndList();
2732 goto endlist;
2733 }
2734 else // found some other tag
2735 {
2736 // add dummy item to obtain valid HTML
2738 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2739 "found <{}{}> instead!",parser()->context.token->endTag?"/":"",parser()->context.token->name);
2740 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2741 goto endlist;
2742 }
2743 }
2744 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2745 {
2746 // add dummy item to obtain valid HTML
2748 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2749 " for a html list item");
2750 goto endlist;
2751 }
2752 else // token other than html token
2753 {
2754 // add dummy item to obtain valid HTML
2756 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found {} token instead!",
2757 tok.to_string());
2758 goto endlist;
2759 }
2760
2761 do
2762 {
2765 retval=li->parse();
2766 } while (retval.is(TokenRetval::RetVal_ListItem));
2767
2768 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2769 {
2770 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <{:c}l> block",
2771 m_type==Unordered ? 'u' : 'o');
2772 }
2773
2774endlist:
2775 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2776 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2777}
2778
2780{
2781 AUTO_TRACE();
2782 Token retval = Token::make_RetVal_OK();
2783 int num=1;
2784 auto ns = AutoNodeStack(parser(),thisVariant());
2785
2786 // get next token
2787 Token tok=parser()->tokenizer.lex();
2788 // skip whitespace and paragraph breaks
2789 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2790 // should find a html tag now
2791 if (tok.is(TokenRetval::TK_HTMLTAG))
2792 {
2793 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2794 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2795 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2796 {
2797 // ok, we can go on.
2798 }
2799 else // found some other tag
2800 {
2801 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2802 "found <{}> instead!",parser()->context.token->name);
2803 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2804 goto endlist;
2805 }
2806 }
2807 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2808 {
2809 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2810 " for a html list item");
2811 goto endlist;
2812 }
2813 else // token other than html token
2814 {
2815 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found {} token instead!",
2816 tok.to_string());
2817 goto endlist;
2818 }
2819
2820 do
2821 {
2824 retval=li->parseXml();
2825 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2826 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2827 } while (retval.is(TokenRetval::RetVal_ListItem));
2828
2829 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2830 {
2831 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"{}\"> block",
2832 m_type==Unordered ? "bullet" : "number");
2833 }
2834
2835endlist:
2836 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2837 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2838 Token::make_RetVal_OK() : retval;
2839}
2840
2841//--------------------------------------------------------------------------
2842
2844{
2845 AUTO_TRACE();
2846 Token retval = Token::make_TK_NONE();
2847 auto ns = AutoNodeStack(parser(),thisVariant());
2848
2849 // parse one or more paragraphs
2850 bool isFirst=TRUE;
2851 DocPara *par=nullptr;
2852 do
2853 {
2855 par = children().get_last<DocPara>();
2856 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2857 retval=par->parse();
2858 }
2859 while (retval.is(TokenRetval::TK_NEWPARA));
2860 if (par) par->markLast();
2861
2862 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2863 {
2864 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2865 }
2866
2867 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2868 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2869}
2870
2871//---------------------------------------------------------------------------
2872
2874{
2875 AUTO_TRACE();
2876 Token retval = Token::make_TK_NONE();
2877 auto ns = AutoNodeStack(parser(),thisVariant());
2878
2879 // parse one or more paragraphs
2880 bool isFirst=TRUE;
2881 DocPara *par=nullptr;
2882 do
2883 {
2885 par = children().get_last<DocPara>();
2886 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2887 retval=par->parse();
2888 }
2889 while (retval.is(TokenRetval::TK_NEWPARA));
2890 if (par) par->markLast();
2891
2892 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2893 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2894}
2895
2896//---------------------------------------------------------------------------
2897
2902
2903
2905{
2906 auto ns = AutoNodeStack(parser(),thisVariant());
2908 DocPara *par = &std::get<DocPara>(*m_paragraph);
2909 Token rv=par->parse();
2910 par->markFirst();
2911 par->markLast();
2912 return rv;
2913}
2914
2915//--------------------------------------------------------------------------
2916
2918{
2919 auto ns = AutoNodeStack(parser(),thisVariant());
2920 Token rv = Token::make_TK_NONE();
2921 do
2922 {
2925 rv=li->parse();
2926 } while (rv.is(TokenRetval::RetVal_ListItem));
2927 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2928}
2929
2930//--------------------------------------------------------------------------
2931
2936
2938{
2939 AUTO_TRACE();
2940 Token retval = Token::make_RetVal_OK();
2941 auto ns = AutoNodeStack(parser(),thisVariant());
2942
2943 // first parse any number of paragraphs
2944 bool isFirst=TRUE;
2945 DocPara *lastPar=nullptr;
2946 do
2947 {
2949 DocPara *par = children().get_last<DocPara>();
2950 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2951 retval=par->parse();
2952 if (!par->isEmpty())
2953 {
2954 if (lastPar) lastPar->markLast(FALSE);
2955 lastPar=par;
2956 }
2957 else
2958 {
2959 children().pop_back();
2960 }
2961 // next paragraph should be more indented than the - marker to belong
2962 // to this item
2963 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2964 if (lastPar) lastPar->markLast();
2965
2966 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2967 return retval;
2968}
2969
2970//--------------------------------------------------------------------------
2971
2978
2980{
2981 AUTO_TRACE();
2982 Token retval = Token::make_RetVal_OK();
2983 int num=1;
2984 auto ns = AutoNodeStack(parser(),thisVariant());
2986 // first item or sub list => create new list
2987 do
2988 {
2989 switch (parser()->context.token->id)
2990 {
2991 case -1:
2992 break;
2993 case DocAutoList::Unchecked: // unchecked
2994 case DocAutoList::Checked_x: // checked with x
2995 case DocAutoList::Checked_X: // checked with X
2996 num = parser()->context.token->id;
2997 break;
2998 default: // explicitly numbered list
2999 num=parser()->context.token->id; // override num with real number given
3000 break;
3001 }
3002
3004 retval = children().get_last<DocAutoListItem>()->parse();
3005 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
3006 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
3007 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
3008 // qPrint(parser()->context.token->name));
3009 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
3010 }
3011 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
3012 m_indent==parser()->context.token->indent && // at same indent level
3013 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
3014 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
3015 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
3016 );
3017
3019 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3020 return retval;
3021}
3022
3023//--------------------------------------------------------------------------
3024
3026{
3027 AUTO_TRACE();
3028 auto ns = AutoNodeStack(parser(),thisVariant());
3030 Token tok = parser()->tokenizer.lex();
3031 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
3032 {
3033 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
3034 {
3035 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
3036 }
3037 tok = parser()->tokenizer.lex();
3038 }
3041}
3042
3044{
3046 parser()->pushContext(); // this will create a new parser->context.token
3048 parser()->popContext(); // this will restore the old parser->context.token
3052}
3053
3054//--------------------------------------------------------------------------
3055
3060
3062{
3063 return m_title && std::get<DocTitle>(*m_title).hasTitle();
3064}
3065
3066Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
3067{
3068 AUTO_TRACE();
3069 auto ns = AutoNodeStack(parser(),thisVariant());
3070
3071 // handle case for user defined title
3072 if (userTitle)
3073 {
3075 std::get_if<DocTitle>(m_title.get())->parse();
3076 }
3077
3078 // add new paragraph as child
3079 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3080 {
3081 std::get<DocPara>(children().back()).markLast(FALSE);
3082 }
3083 bool markFirst = children().empty();
3084 if (needsSeparator)
3085 {
3087 }
3089 DocPara *par = children().get_last<DocPara>();
3090 if (markFirst)
3091 {
3092 par->markFirst();
3093 }
3094 par->markLast();
3095
3096 // parse the contents of the paragraph
3097 Token retval = par->parse();
3098
3099 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3100 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
3101}
3102
3104{
3105 AUTO_TRACE();
3106 auto ns = AutoNodeStack(parser(),thisVariant());
3107
3109 DocTitle *title = &std::get<DocTitle>(*m_title);
3110 title->parseFromString(thisVariant(),parser()->context.token->name);
3111
3112 QCString text = parser()->context.token->text;
3113 parser()->pushContext(); // this will create a new parser->context.token
3115 parser()->popContext(); // this will restore the old parser->context.token
3116
3117 return Token::make_RetVal_OK();
3118}
3119
3121{
3122 AUTO_TRACE();
3123 auto ns = AutoNodeStack(parser(),thisVariant());
3124
3125 Token retval = Token::make_RetVal_OK();
3126 for (;;)
3127 {
3128 // add new paragraph as child
3129 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3130 {
3131 std::get<DocPara>(children().back()).markLast(false);
3132 }
3133 bool markFirst = children().empty();
3135 DocPara *par = children().get_last<DocPara>();
3136 if (markFirst)
3137 {
3138 par->markFirst();
3139 }
3140 par->markLast();
3141
3142 // parse the contents of the paragraph
3143 retval = par->parse();
3144 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3145 if (retval.is(TokenRetval::RetVal_CloseXml))
3146 {
3147 retval = Token::make_RetVal_OK();
3148 break;
3149 }
3150 }
3151
3152 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3153 return retval;
3154}
3155
3157{
3158 DocPara *p=nullptr;
3159 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
3160 {
3162 p = children().get_last<DocPara>();
3163 }
3164 else
3165 {
3166 // Comma-separate <seealso> links.
3167 p->injectToken(Token::make_TK_WORD(),",");
3168 p->injectToken(Token::make_TK_WHITESPACE()," ");
3169 }
3170
3172 p->injectToken(Token::make_TK_LNKWORD(),word);
3174}
3175
3177{
3178 switch (m_type)
3179 {
3180 case Unknown: break;
3181 case See: return "see";
3182 case Return: return "return";
3183 case Author: // fall through
3184 case Authors: return "author";
3185 case Version: return "version";
3186 case Since: return "since";
3187 case Date: return "date";
3188 case Note: return "note";
3189 case Warning: return "warning";
3190 case Pre: return "pre";
3191 case Post: return "post";
3192 case Copyright: return "copyright";
3193 case Invar: return "invariant";
3194 case Remark: return "remark";
3195 case Attention: return "attention";
3196 case Important: return "important";
3197 case User: return "user";
3198 case Rcs: return "rcs";
3199 }
3200 return "unknown";
3201}
3202
3203//--------------------------------------------------------------------------
3204
3206{
3207 AUTO_TRACE();
3208 Token retval = Token::make_RetVal_OK();
3209 auto ns = AutoNodeStack(parser(),thisVariant());
3210 DocPara *par=nullptr;
3211 QCString saveCmdName = cmdName;
3212
3213 Token tok=parser()->tokenizer.lex();
3214 if (!tok.is(TokenRetval::TK_WHITESPACE))
3215 {
3216 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3217 saveCmdName);
3218 retval = Token::make_RetVal_EndParBlock();
3219 goto endparamlist;
3220 }
3222 tok=parser()->tokenizer.lex();
3223 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3224 {
3226 {
3227 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3228 if (typeSeparator!=-1)
3229 {
3230 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3231 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3234 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3235 {
3236 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3237 }
3238 }
3239 else
3240 {
3243 }
3244 }
3245 else if (m_type==DocParamSect::RetVal)
3246 {
3249 }
3250 //m_params.append(parser()->context.token->name);
3252 tok=parser()->tokenizer.lex();
3253 }
3255 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3256 {
3257 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3258 "argument of command {}",saveCmdName);
3259 retval = Token::make_RetVal_EndParBlock();
3260 goto endparamlist;
3261 }
3262 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3263 {
3264 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3265 {
3266 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3267 "argument of command {}",tok.to_string(),saveCmdName);
3268 }
3269 retval = Token::make_RetVal_EndParBlock();
3270 goto endparamlist;
3271 }
3272
3274 par = m_paragraphs.get_last<DocPara>();
3275 retval = par->parse();
3276 par->markFirst();
3277 par->markLast();
3278
3279endparamlist:
3280 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3281 return retval;
3282}
3283
3285{
3286 AUTO_TRACE();
3287 Token retval = Token::make_RetVal_OK();
3288 auto ns = AutoNodeStack(parser(),thisVariant());
3289
3290 parser()->context.token->name = paramName;
3292 {
3295 }
3296 else if (m_type==DocParamSect::RetVal)
3297 {
3300 }
3301
3303
3304 do
3305 {
3307 DocPara *par = m_paragraphs.get_last<DocPara>();
3308 retval = par->parse();
3309 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3310 // after </para> and before </param>
3311 {
3312 m_paragraphs.pop_back();
3313 break;
3314 }
3315 else // append the paragraph to the list
3316 {
3317 if (!m_paragraphs.empty())
3318 {
3319 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3320 }
3321 bool markFirst = m_paragraphs.empty();
3322 par = &std::get<DocPara>(m_paragraphs.back());
3323 if (markFirst)
3324 {
3325 par->markFirst();
3326 }
3327 par->markLast();
3328 }
3329
3330 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3331
3332 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3333 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3334 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3335 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3336
3337 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3338 {
3339 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3340 }
3341 else
3342 {
3343 retval = Token::make_RetVal_OK();
3344 }
3345
3346 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3347 return retval;
3348}
3349
3350//--------------------------------------------------------------------------
3351
3352Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3353{
3354 AUTO_TRACE();
3355 Token retval = Token::make_RetVal_OK();
3356 auto ns = AutoNodeStack(parser(),thisVariant());
3357
3358 if (d!=Unspecified)
3359 {
3361 }
3362
3363 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3364 {
3365 DocParamList &lastPl = std::get<DocParamList>(children().back());
3366 lastPl.markLast(false);
3367 }
3368 bool markFirst = children().empty();
3371 if (markFirst)
3372 {
3373 pl->markFirst();
3374 }
3375 pl->markLast();
3376 if (xmlContext)
3377 {
3378 retval = pl->parseXml(cmdName);
3379 }
3380 else
3381 {
3382 retval = pl->parse(cmdName);
3383 }
3384 if (retval.is(TokenRetval::RetVal_EndParBlock))
3385 {
3386 retval = Token::make_RetVal_OK();
3387 }
3388
3389 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3390 return retval;
3391}
3392
3393//--------------------------------------------------------------------------
3394
3400
3402{
3403 AUTO_TRACE();
3404 DocSimpleSect *ss=nullptr;
3405 bool needsSeparator = FALSE;
3406 if (!children().empty() && // has previous element
3407 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3408 ss->type()==t && // of same type
3409 t!=DocSimpleSect::User) // but not user defined
3410 {
3411 // append to previous section
3412 needsSeparator = TRUE;
3413 }
3414 else // start new section
3415 {
3418 }
3419 Token rv = Token::make_RetVal_OK();
3420 if (xmlContext)
3421 {
3422 return ss->parseXml();
3423 }
3424 else
3425 {
3426 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3427 }
3428 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3429}
3430
3433 bool xmlContext=FALSE,
3434 int direction=DocParamSect::Unspecified)
3435{
3436 AUTO_TRACE();
3437 DocParamSect *ps = nullptr;
3438 if (!children().empty() && // previous element
3439 (ps=children().get_last<DocParamSect>()) && // was a param sect
3440 ps->type()==t) // of same type
3441 { // append to previous section ps
3442 }
3443 else // start new section
3444 {
3446 ps = children().get_last<DocParamSect>();
3447 }
3448 Token rv=ps->parse(cmdName,xmlContext,
3449 static_cast<DocParamSect::Direction>(direction));
3450 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3451 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3452}
3453
3454void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3455{
3456 AUTO_TRACE();
3457 QCString saveCmdName = cmdName;
3458 // get the argument of the cite command.
3459 Token tok=parser()->tokenizer.lex();
3460
3461 CiteInfoOption option;
3462 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3463 {
3465 parser()->tokenizer.lex();
3466 StringVector optList=split(parser()->context.token->name.str(),",");
3467 for (auto const &opt : optList)
3468 {
3469 if (opt == "number")
3470 {
3471 if (!option.isUnknown())
3472 {
3473 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3474 }
3475 else
3476 {
3477 option = CiteInfoOption::makeNumber();
3478 }
3479 }
3480 else if (opt == "year")
3481 {
3482 if (!option.isUnknown())
3483 {
3484 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3485 }
3486 else
3487 {
3488 option = CiteInfoOption::makeYear();
3489 }
3490 }
3491 else if (opt == "shortauthor")
3492 {
3493 if (!option.isUnknown())
3494 {
3495 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3496 }
3497 else
3498 {
3500 }
3501 }
3502 else if (opt == "nopar")
3503 {
3504 option.setNoPar();
3505 }
3506 else if (opt == "nocite")
3507 {
3508 option.setNoCite();
3509 }
3510 else
3511 {
3512 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unknown option specified with \\{}, discarding '{}'", saveCmdName, opt);
3513 }
3514 }
3515
3516 if (option.isUnknown()) option.changeToNumber();
3517
3519 tok=parser()->tokenizer.lex();
3520 if (!tok.is(TokenRetval::TK_WHITESPACE))
3521 {
3522 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3523 saveCmdName);
3524 return;
3525 }
3526 }
3527 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3528 {
3529 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3530 cmdChar,saveCmdName);
3531 return;
3532 }
3533 else
3534 {
3535 option = CiteInfoOption::makeNumber();
3536 }
3537
3539 tok=parser()->tokenizer.lex();
3540 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3541 {
3542 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"THE ONE unexpected end of comment block while parsing the "
3543 "argument of command '{:c}{}'",cmdChar,saveCmdName);
3544 return;
3545 }
3546 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3547 {
3548 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3549 tok.to_string(),cmdChar,saveCmdName);
3550 return;
3551 }
3555
3557}
3558
3559void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3560{
3561 AUTO_TRACE();
3562 // get the argument of the emoji command.
3563 Token tok=parser()->tokenizer.lex();
3564 if (!tok.is(TokenRetval::TK_WHITESPACE))
3565 {
3566 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3567 cmdChar,cmdName);
3568 return;
3569 }
3571 tok=parser()->tokenizer.lex();
3572 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3573 {
3574 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3575 "argument of command '{:c}{}'",cmdChar,cmdName);
3577 return;
3578 }
3579 else if (!tok.is(TokenRetval::TK_WORD))
3580 {
3581 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3582 tok.to_string(),cmdChar,cmdName);
3584 return;
3585 }
3588}
3589
3590void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3591{
3592 // get the argument of the cite command.
3593 Token tok=parser()->tokenizer.lex();
3594 if (!tok.is(TokenRetval::TK_WHITESPACE))
3595 {
3596 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3597 cmdChar,cmdName);
3598 return;
3599 }
3601 tok=parser()->tokenizer.lex();
3602 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3603 {
3604 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3605 "argument of command '{:c}{}'",cmdChar,cmdName);
3606 return;
3607 }
3608 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3609 {
3610 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3611 tok.to_string(),cmdChar,cmdName);
3612 return;
3613 }
3614 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3615 if (opt)
3616 {
3617 QCString optionValue;
3618 switch (opt->kind())
3619 {
3621 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3622 break;
3624 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3625 break;
3627 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3628 break;
3630 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3631 break;
3633 {
3634 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3635 optionValue="";
3636 if (!lst->empty())
3637 {
3638 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3639 static const reg::Ex marker(R"(@(\d+))");
3640 reg::Iterator it(lstFormat,marker);
3642 size_t index=0;
3643 // now replace all markers with the real text
3644 for ( ; it!=end ; ++it)
3645 {
3646 const auto &match = *it;
3647 size_t newIndex = match.position();
3648 size_t matchLen = match.length();
3649 optionValue += lstFormat.substr(index,newIndex-index);
3650 unsigned long entryIndex = std::stoul(match[1].str());
3651 if (entryIndex<(unsigned long)lst->size())
3652 {
3653 optionValue += lst->at(entryIndex);
3654 }
3655 index=newIndex+matchLen;
3656 }
3657 optionValue+=lstFormat.substr(index);
3658 }
3659 }
3660 break;
3662 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3663 cmdChar,cmdName,parser()->context.token->name);
3664 break;
3666 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3667 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3668 cmdChar,cmdName,parser()->context.token->name);
3669 break;
3671 // nothing to show here
3672 break;
3673 }
3674 if (!optionValue.isEmpty())
3675 {
3676 children().append<DocWord>(parser(),thisVariant(),optionValue);
3677 }
3678 }
3679 else
3680 {
3681 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3682 cmdChar,cmdName,parser()->context.token->name);
3684 }
3686}
3687
3689{
3690 AUTO_TRACE();
3691 Token retval=parser()->tokenizer.lex();
3692 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3694 retval=parser()->tokenizer.lex();
3695 if (retval.is(TokenRetval::RetVal_OK))
3696 {
3700 if (!ref->parse())
3701 {
3702 children().pop_back();
3703 }
3704 }
3706 return retval;
3707}
3708
3709void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3710{
3711 AUTO_TRACE();
3712 QCString fmt;
3713 QCString date;
3714 Token tok=parser()->tokenizer.lex();
3715 if (!tok.is(TokenRetval::TK_WHITESPACE))
3716 {
3717 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3718 cmdChar,cmdName);
3719 return;
3720 }
3722 tok = parser()->tokenizer.lex();
3723 if (!tok.is(TokenRetval::TK_WORD))
3724 {
3725 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3726 cmdChar,cmdName);
3728 return;
3729 }
3730 fmt = parser()->context.token->name;
3731
3733 tok = parser()->tokenizer.lex();
3734
3735 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3736 QCString specDate = specDateRaw.stripWhiteSpace();
3737 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3738 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3739 {
3740 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3741 cmdChar,cmdName);
3743 return;
3744 }
3745
3746 std::tm dat{};
3747 int specFormat=0;
3748 QCString err = dateTimeFromString(specDate,dat,specFormat);
3749 if (!err.isEmpty())
3750 {
3751 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3752 cmdChar,cmdName,err);
3754 return;
3755 }
3756
3757 int usedFormat=0;
3758 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3759
3760 // warn the user if the format contains markers that are not explicitly filled in
3761 for (int i=0;i<SF_NumBits;i++)
3762 {
3763 int bitMask = 1<<i;
3764 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3765 {
3766 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.",
3767 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3768 }
3769 }
3770
3771 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3772 if (specDateOnlyWS) // specDate is only whitespace
3773 {
3775 }
3777}
3778
3779void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3780{
3781 AUTO_TRACE();
3783 Token tok = parser()->tokenizer.lex();
3784 if (!tok.is(TokenRetval::TK_WORD))
3785 {
3786 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
3787 cmdChar,cmdName);
3788 return;
3789 }
3791}
3792
3793void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3794{
3795 AUTO_TRACE();
3796 Token tok=parser()->tokenizer.lex();
3797 if (!tok.is(TokenRetval::TK_WHITESPACE))
3798 {
3799 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3800 cmdChar,cmdName);
3801 return;
3802 }
3804 tok=parser()->tokenizer.lex();
3806 if (!tok.is(TokenRetval::TK_WORD))
3807 {
3808 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3809 tok.to_string(),cmdChar,cmdName);
3810 return;
3811 }
3814}
3815
3816
3818{
3819 AUTO_TRACE("cmdName={}",cmdName);
3820 QCString saveCmdName = cmdName;
3821 Token tok=parser()->tokenizer.lex();
3822 if (!tok.is(TokenRetval::TK_WHITESPACE))
3823 {
3824 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3825 saveCmdName);
3826 return;
3827 }
3829 tok=parser()->tokenizer.lex();
3831 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3832 {
3833 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3834 "argument of command {}", saveCmdName);
3835 return;
3836 }
3837 else if (!tok.is(TokenRetval::TK_WORD))
3838 {
3839 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3840 tok.to_string(),saveCmdName);
3841 return;
3842 }
3843 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3844 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3845 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3846 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3847 //TODO get from context the stripCodeComments()
3848 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3852 stripCodeComments,
3855 );
3857 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3858 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3859 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3860 bool isFirst = !n1 || // no last node
3861 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3862 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3863 op->markFirst(isFirst);
3864 op->markLast(true);
3865 if (n1_docIncOp)
3866 {
3867 n1_docIncOp->markLast(false);
3868 }
3869 else if (n1_docWs && n2_docIncOp)
3870 {
3871 n2_docIncOp->markLast(false);
3872 }
3873 op->parse();
3874}
3875
3876template<class T>
3877void DocPara::handleFile(const QCString &cmdName)
3878{
3879 AUTO_TRACE("cmdName={}",cmdName);
3880 QCString saveCmdName = cmdName;
3881 Token tok=parser()->tokenizer.lex();
3882 if (!tok.is(TokenRetval::TK_WHITESPACE))
3883 {
3884 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3885 saveCmdName);
3886 return;
3887 }
3889 tok=parser()->tokenizer.lex();
3891 if (!tok.is(TokenRetval::TK_WORD))
3892 {
3893 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3894 tok.to_string(),saveCmdName);
3895 return;
3896 }
3897 QCString name = parser()->context.token->name;
3898 children().append<T>(parser(),thisVariant(),name,
3902 auto df = children().get_last<T>();
3903 if (!df->parse())
3904 {
3905 children().pop_back();
3906 }
3907}
3908
3915
3916void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3917{
3918 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3919 QCString saveCmdName = cmdName;
3920 Token tok=parser()->tokenizer.lex();
3921 if (!tok.is(TokenRetval::TK_WHITESPACE))
3922 {
3923 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3924 saveCmdName);
3925 return;
3926 }
3928 tok=parser()->tokenizer.lex();
3929 if (!tok.is(TokenRetval::TK_WORD))
3930 {
3931 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3932 tok.to_string(),saveCmdName);
3933 return;
3934 }
3935 if (saveCmdName == "javalink")
3936 {
3938 parser()->context.nodeStack.size(),
3939 DocStyleChange::Code,cmdName,TRUE);
3940 }
3943 DocLink *lnk = children().get_last<DocLink>();
3944 if (saveCmdName == "javalink")
3945 {
3947 parser()->context.nodeStack.size(),
3948 DocStyleChange::Code,cmdName,FALSE);
3949 }
3950 QCString leftOver = lnk->parse(isJavaLink);
3951 if (!leftOver.isEmpty())
3952 {
3953 children().append<DocWord>(parser(),thisVariant(),leftOver);
3954 }
3955}
3956
3957void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3958{
3959 AUTO_TRACE("cmdName={}",cmdName);
3960 QCString saveCmdName = cmdName;
3961 Token tok=parser()->tokenizer.lex();
3962 if (!tok.is(TokenRetval::TK_WHITESPACE))
3963 {
3964 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3965 cmdChar,qPrint(saveCmdName));
3966 return;
3967 }
3969 tok=parser()->tokenizer.lex(); // get the reference id
3970 if (!tok.is(TokenRetval::TK_WORD))
3971 {
3972 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3973 tok.to_string(),cmdChar,saveCmdName);
3974 goto endref;
3975 }
3979 children().get_last<DocRef>()->parse();
3980endref:
3982}
3983
3985{
3986 AUTO_TRACE("cmdName={}",cmdName);
3987 QCString saveCmdName = cmdName;
3988 Token tok=parser()->tokenizer.lex();
3989 bool isBlock = false;
3990 bool trimLeft = false;
3991 bool localScope = false;
3992 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3993 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3994 {
3996 parser()->tokenizer.lex();
3998 StringVector optList=split(parser()->context.token->name.str(),",");
3999 auto contains = [&optList](const char *kw)
4000 {
4001 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
4002 };
4003 localScope = contains("local");
4004 if (contains("nostrip"))
4005 {
4006 stripCodeComments = false;
4007 }
4008 else if (contains("strip"))
4009 {
4010 stripCodeComments = true;
4011 }
4012 if (t==DocInclude::Snippet && contains("trimleft"))
4013 {
4014 trimLeft = true;
4015 }
4016
4017 if (contains("lineno"))
4018 {
4022 }
4023 tok=parser()->tokenizer.lex();
4024 if (!tok.is(TokenRetval::TK_WHITESPACE))
4025 {
4026 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4027 saveCmdName);
4028 return;
4029 }
4030 }
4031 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
4032 {
4034 parser()->tokenizer.lex();
4035 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
4037 parser()->tokenizer.lex();
4038 }
4039 else if (!tok.is(TokenRetval::TK_WHITESPACE))
4040 {
4041 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4042 saveCmdName);
4043 return;
4044 }
4046 tok=parser()->tokenizer.lex();
4048 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4049 {
4050 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4051 "argument of command {}",saveCmdName);
4052 return;
4053 }
4054 else if (!tok.is(TokenRetval::TK_WORD))
4055 {
4056 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
4057 tok.to_string(),saveCmdName);
4058 return;
4059 }
4060 QCString fileName = parser()->context.token->name;
4061 QCString blockId;
4063 {
4064 if (fileName == "this") fileName=parser()->context.fileName;
4066 tok=parser()->tokenizer.lex();
4068 if (!tok.is(TokenRetval::TK_WORD))
4069 {
4070 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
4071 tok.to_string(),saveCmdName);
4072 return;
4073 }
4074 blockId = "["+parser()->context.token->name+"]";
4075 }
4076
4078 thisVariant(),
4079 fileName,
4080 localScope ? parser()->context.context : "",
4081 t,
4082 stripCodeComments,
4085 blockId,isBlock,trimLeft);
4087}
4088
4089void DocPara::handleSection(char cmdChar,const QCString &cmdName)
4090{
4091 AUTO_TRACE("cmdName={}",cmdName);
4092 QCString saveCmdName = cmdName;
4093 // get the argument of the section command.
4094 Token tok=parser()->tokenizer.lex();
4095 if (!tok.is(TokenRetval::TK_WHITESPACE))
4096 {
4097 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
4098 cmdChar,saveCmdName);
4099 return;
4100 }
4101 tok=parser()->tokenizer.lex();
4102 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4103 {
4104 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4105 "argument of command '{:c}{}'", cmdChar,saveCmdName);
4106 return;
4107 }
4108 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
4109 {
4110 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
4111 tok.to_string(),cmdChar,saveCmdName);
4112 return;
4113 }
4116 parser()->tokenizer.lex();
4118}
4119
4120Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
4121{
4122 AUTO_TRACE();
4123 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
4124 Token retval = children().get_last<DocHtmlHeader>()->parse();
4125 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
4126}
4127
4128// For XML tags whose content is stored in attributes rather than
4129// contained within the element, we need a way to inject the attribute
4130// text into the current paragraph.
4131bool DocPara::injectToken(Token tok,const QCString &tokText)
4132{
4133 AUTO_TRACE();
4134 parser()->context.token->name = tokText;
4135 return parser()->defaultHandleToken(thisVariant(),tok,children());
4136}
4137
4139{
4140 AUTO_TRACE();
4141 Token retval = parser()->tokenizer.lex();
4142 QCString lang = parser()->context.token->name;
4143 if (!lang.isEmpty() && lang.at(0)!='.')
4144 {
4145 lang="."+lang;
4146 }
4147 if (parser()->context.xmlComment)
4148 {
4149 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
4150 }
4151 // search for the first non-whitespace line, index is stored in li
4152 size_t i=0,li=0,l=parser()->context.token->verb.length();
4153 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
4154 {
4155 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
4156 i++;
4157 }
4160 stripIndentation(parser()->context.token->verb.mid(li)),
4164 FALSE,lang);
4165 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4166 {
4167 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
4168 }
4170 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4171 return retval;
4172}
4173
4175{
4176 if (parser()->context.memberDef) // inheriting docs from a member
4177 {
4178 const MemberDef *reMd = parser()->context.memberDef->reimplements();
4179 if (reMd) // member from which was inherited.
4180 {
4181 const MemberDef *thisMd = parser()->context.memberDef;
4182 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
4183 parser()->pushContext();
4184 parser()->context.scope=reMd->getOuterScope();
4185 if (parser()->context.scope!=Doxygen::globalScope)
4186 {
4188 }
4189 parser()->context.memberDef=reMd;
4190 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
4191 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
4192 parser()->context.copyStack.push_back(reMd);
4195 parser()->context.copyStack.pop_back();
4196 auto hasParamCommand = parser()->context.hasParamCommand;
4197 auto hasReturnCommand = parser()->context.hasReturnCommand;
4198 auto retvalsFound = parser()->context.retvalsFound;
4199 auto paramsFound = parser()->context.paramsFound;
4200 parser()->popContext();
4201 parser()->context.hasParamCommand = hasParamCommand;
4202 parser()->context.hasReturnCommand = hasReturnCommand;
4203 parser()->context.retvalsFound = retvalsFound;
4204 parser()->context.paramsFound = paramsFound;
4205 parser()->context.memberDef = thisMd;
4206 }
4207 }
4208}
4209
4210
4211Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
4212{
4213 AUTO_TRACE("cmdName={}",cmdName);
4214 Token retval = Token::make_RetVal_OK();
4215 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
4216 switch (cmdId)
4217 {
4219 {
4220 std::string str{cmdChar};
4221 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
4222 if (isAliasCmd(cmdName.view()))
4223 {
4224 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
4225 }
4226 else
4227 {
4228 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
4229 }
4230 }
4231 break;
4234 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4236 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4237 break;
4240 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4242 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4243 break;
4246 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4248 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4249 break;
4252 break;
4255 break;
4258 break;
4261 break;
4264 break;
4267 break;
4270 break;
4273 break;
4276 break;
4279 break;
4283 break;
4288 break;
4291 break;
4294 break;
4297 break;
4300 break;
4303 break;
4306 break;
4309 break;
4314 break;
4318 break;
4321 break;
4324 break;
4327 break;
4330 break;
4333 break;
4336 break;
4339 break;
4342 break;
4345 break;
4348 break;
4351 break;
4354 break;
4357 break;
4360 break;
4363 break;
4365 {
4367 retval = children().get_last<DocSimpleList>()->parse();
4368 }
4369 break;
4371 {
4372 handleSection(cmdChar,cmdName);
4373 retval = Token::make_RetVal_Section();
4374 }
4375 break;
4377 {
4378 handleSection(cmdChar,cmdName);
4379 retval = Token::make_RetVal_Subsection();
4380 }
4381 break;
4383 {
4384 handleSection(cmdChar,cmdName);
4385 retval = Token::make_RetVal_Subsubsection();
4386 }
4387 break;
4389 {
4390 handleSection(cmdChar,cmdName);
4391 retval = Token::make_RetVal_Paragraph();
4392 }
4393 break;
4395 {
4396 handleSection(cmdChar,cmdName);
4397 retval = Token::make_RetVal_SubParagraph();
4398 }
4399 break;
4401 {
4402 handleSection(cmdChar,cmdName);
4403 retval = Token::make_RetVal_SubSubParagraph();
4404 }
4405 break;
4407 {
4409 retval = handleStartCode();
4410 }
4411 break;
4413 {
4415 retval = handleStartCode();
4416 }
4417 break;
4419 {
4421 retval = parser()->tokenizer.lex();
4423 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4424 {
4425 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4426 }
4428 }
4429 break;
4431 {
4433 retval = parser()->tokenizer.lex();
4435 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4436 {
4437 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4438 }
4440 }
4441 break;
4443 {
4445 retval = parser()->tokenizer.lex();
4447 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4448 {
4449 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4450 }
4452 }
4453 break;
4455 {
4457 retval = parser()->tokenizer.lex();
4459 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4460 {
4461 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4462 }
4464 }
4465 break;
4467 {
4469 retval = parser()->tokenizer.lex();
4471 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4472 {
4473 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4474 }
4476 }
4477 break;
4479 {
4481 retval = parser()->tokenizer.lex();
4483 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4484 {
4485 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4486 }
4488 }
4489 break;
4491 {
4494 parser()->tokenizer.lex();
4495
4496 QCString fullMatch = parser()->context.token->verb;
4497 int idx = fullMatch.find('{');
4498 int idxEnd = fullMatch.find("}",idx+1);
4499 StringVector optList;
4500 if (idx != -1) // options present
4501 {
4502 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4503 optList = split(optStr.str(),",");
4504 for (const auto &opt : optList)
4505 {
4506 if (opt.empty()) continue;
4507 QCString locOpt(opt);
4508 locOpt = locOpt.stripWhiteSpace().lower();
4509 if (locOpt == "code")
4510 {
4512 }
4513 else if (!locOpt.isEmpty())
4514 {
4515 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4516 }
4517 }
4518 }
4519
4521 retval = parser()->tokenizer.lex();
4523 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4524 {
4525 if (t == DocVerbatim::JavaDocCode)
4526 {
4527 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4528 }
4529 else
4530 {
4531 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4532 }
4533 }
4535 }
4536 break;
4539 {
4540 if (cmdId == CommandType::CMD_VERBATIM)
4541 {
4543 }
4544 else
4545 {
4547 }
4548 retval = parser()->tokenizer.lex();
4550 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4551 {
4552 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4553 }
4555 }
4556 break;
4558 {
4567 QCString width,height;
4568 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4570 retval = parser()->tokenizer.lex();
4571 dv->setText(parser()->context.token->verb);
4572 dv->setWidth(width);
4573 dv->setHeight(height);
4574 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4575 if (!Config_getBool(HAVE_DOT))
4576 {
4577 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4578 children().pop_back();
4579 }
4580 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4581 {
4582 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4583 }
4585 }
4586 break;
4588 {
4597 QCString width,height;
4598 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4600 retval = parser()->tokenizer.lex();
4601 dv->setText(parser()->context.token->verb);
4602 dv->setWidth(width);
4603 dv->setHeight(height);
4604 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4605 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4606 {
4607 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4608 }
4610 }
4611 break;
4613 {
4614 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4616 parser()->tokenizer.lex();
4617 QCString fullMatch = parser()->context.token->sectionId;
4618 QCString sectionId = "";
4619 int idx = fullMatch.find('{');
4620 int idxEnd = fullMatch.find("}",idx+1);
4621 StringVector optList;
4622 QCString engine;
4623 if (idx != -1) // options present
4624 {
4625 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4626 optList = split(optStr.str(),",");
4627 for (const auto &opt : optList)
4628 {
4629 if (opt.empty()) continue;
4630 bool found = false;
4631 QCString locOpt(opt);
4632 locOpt = locOpt.stripWhiteSpace().lower();
4633 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4634 {
4635 if (!engine.isEmpty())
4636 {
4637 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4638 }
4639 engine = locOpt;
4640 found = true;
4641 }
4642 if (!found)
4643 {
4644 if (sectionId.isEmpty())
4645 {
4646 sectionId = opt;
4647 }
4648 else
4649 {
4650 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4651 }
4652 }
4653 }
4654 }
4655 else
4656 {
4657 sectionId = parser()->context.token->sectionId;
4658 }
4659 if (engine.isEmpty()) engine = "uml";
4660
4661 if (sectionId.isEmpty())
4662 {
4664 retval = parser()->tokenizer.lex();
4665 assert(retval.is(TokenRetval::RetVal_OK));
4666
4667 sectionId = parser()->context.token->sectionId;
4668 sectionId = sectionId.stripWhiteSpace();
4669 }
4670
4671 QCString plantFile(sectionId);
4676 FALSE,plantFile);
4678 dv->setEngine(engine);
4680 QCString width,height;
4681 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4683 retval = parser()->tokenizer.lex();
4684 int line = 0;
4685 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4686 if (engine == "ditaa")
4687 {
4688 dv->setUseBitmap(true);
4689 }
4690 else if (engine == "uml")
4691 {
4692 int i = trimmedVerb.find('\n');
4693 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4694 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4695 }
4696 dv->setText(trimmedVerb);
4697 dv->setWidth(width);
4698 dv->setHeight(height);
4699 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4700 if (jarPath.isEmpty())
4701 {
4702 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4703 children().pop_back();
4704 }
4705 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4706 {
4707 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4708 }
4710 }
4711 break;
4713 retval = Token::make_RetVal_EndParBlock();
4714 break;
4730 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4731 break;
4733 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4734 break;
4736 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4737 break;
4739 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4740 break;
4743 break;
4745 retval = handleXRefItem();
4746 break;
4748 {
4750 }
4751 break;
4754 {
4756 }
4757 break;
4759 {
4761 }
4762 break;
4764 {
4768 retval = children().get_last<DocIndexEntry>()->parse();
4769 }
4770 break;
4772 retval = Token::make_RetVal_Internal();
4773 break;
4775 retval = Token::make_RetVal_EndInternal();
4776 break;
4778 {
4780 retval = children().get_last<DocParBlock>()->parse();
4781 }
4782 break;
4783 case CommandType::CMD_COPYDOC: // fall through
4784 case CommandType::CMD_COPYBRIEF: // fall through
4786 //retval = Token::make_RetVal_CopyDoc();
4787 // these commands should already be resolved by processCopyDoc()
4788 break;
4791 break;
4794 break;
4797 break;
4800 break;
4803 break;
4806 break;
4809 break;
4812 break;
4815 break;
4818 break;
4821 break;
4824 break;
4827 break;
4830 break;
4833 break;
4836 break;
4839 break;
4841 if (!Config_getBool(HAVE_DOT))
4842 {
4843 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4844 "ignoring \\dotfile command because HAVE_DOT is not set");
4845 }
4846 else
4847 {
4848 handleFile<DocDotFile>(cmdName);
4849 }
4850 break;
4853 break;
4855 handleFile<DocMscFile>(cmdName);
4856 break;
4858 handleFile<DocDiaFile>(cmdName);
4859 break;
4862 break;
4864 handleLink(cmdName,FALSE);
4865 break;
4867 handleLink(cmdName,TRUE);
4868 break;
4870 handleCite(cmdChar,cmdName);
4871 break;
4873 handleEmoji(cmdChar,cmdName);
4874 break;
4876 handleDoxyConfig(cmdChar,cmdName);
4877 break;
4878 case CommandType::CMD_REF: // fall through
4880 handleRef(cmdChar,cmdName);
4881 break;
4883 {
4886 }
4887 break;
4889 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4890 break;
4892 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4893 break;
4895 {
4897 }
4898 break;
4899 //case CommandType::CMD_LANGSWITCH:
4900 // retval = handleLanguageSwitch();
4901 // break;
4903 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4904 {
4907 }
4908 break;
4911 break;
4913 handleShowDate(cmdChar,cmdName);
4914 break;
4916 handleILine(cmdChar,cmdName);
4917 break;
4919 handleIFile(cmdChar,cmdName);
4920 break;
4922 {
4924 (void)parser()->tokenizer.lex();
4926 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4928 }
4929 break;
4930 default:
4931 // we should not get here!
4932 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4933 break;
4934 }
4935 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4936 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4937 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4938 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4939 TokenRetval::RetVal_EndInternal)
4940 );
4941 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4942 return retval;
4943}
4944
4945static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4946 const char *attrName,
4947 QCString *result)
4948{
4949
4950 for (const auto &opt : tagHtmlAttribs)
4951 {
4952 if (opt.name==attrName)
4953 {
4954 *result = opt.value;
4955 return TRUE;
4956 }
4957 }
4958 return FALSE;
4959}
4960
4961Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4962{
4963 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4964 Token retval = Token::make_RetVal_OK();
4965 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4966 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4969 {
4970 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4971 tagName);
4972 }
4973 switch (tagId)
4974 {
4976 if (!parser()->context.token->emptyTag)
4977 {
4979 tagHtmlAttribs,DocHtmlList::Unordered);
4980 retval=children().get_last<DocHtmlList>()->parse();
4981 }
4982 break;
4984 if (!parser()->context.token->emptyTag)
4985 {
4987 tagHtmlAttribs,DocHtmlList::Ordered);
4988 retval=children().get_last<DocHtmlList>()->parse();
4989 }
4990 break;
4992 if (parser()->context.token->emptyTag) break;
4994 {
4995 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4996 }
4997 else
4998 {
4999 retval = Token::make_RetVal_ListItem();
5000 }
5001 break;
5003 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
5004 break;
5006 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
5007 break;
5009 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
5010 break;
5012 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
5013 break;
5015 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
5016 break;
5018 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
5019 break;
5021 if (parser()->context.token->emptyTag) break;
5022 if (parser()->context.xmlComment)
5023 // for C# source or inside a <summary> or <remark> section we
5024 // treat <code> as an XML tag (so similar to @code)
5025 {
5027 retval = handleStartCode();
5028 }
5029 else // normal HTML markup
5030 {
5031 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5032 }
5033 break;
5035 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
5036 break;
5038 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Typewriter,tagName,&parser()->context.token->attribs);
5039 break;
5041 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
5042 break;
5044 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
5045 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
5046 break;
5048 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
5049 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
5050 break;
5052 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
5053 break;
5055 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
5056 break;
5058 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
5059 break;
5061 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
5062 break;
5064 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
5065 break;
5067 if (parser()->context.token->emptyTag) break;
5068 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
5071 break;
5073 retval = Token::make_TK_NEWPARA();
5074 break;
5076 if (!parser()->context.token->emptyTag)
5077 {
5078 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
5079 retval=children().get_last<DocHtmlDescList>()->parse();
5080 }
5081 break;
5083 if (insideDL(thisVariant()))
5084 {
5085 retval = Token::make_RetVal_DescTitle();
5086 }
5087 else
5088 {
5089 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
5090 }
5091 break;
5093 if (insideDL(thisVariant()))
5094 {
5095 retval = Token::make_RetVal_DescData();
5096 }
5097 else
5098 {
5099 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
5100 }
5101 break;
5103 if (!parser()->context.token->emptyTag)
5104 {
5105 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
5106 retval=children().get_last<DocHtmlTable>()->parse();
5107 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5108 }
5109 break;
5111 retval = Token::make_RetVal_TableRow();
5112 break;
5114 retval = Token::make_RetVal_TableCell();
5115 break;
5117 retval = Token::make_RetVal_TableHCell();
5118 break;
5122 // for time being ignore </t....> tag
5123 break;
5125 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
5126 break;
5128 {
5129 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
5130 }
5131 break;
5133 {
5134 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
5135 }
5136 break;
5138 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
5139 break;
5141 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
5142 break;
5144 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
5145 break;
5147 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
5148 break;
5150 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
5151 break;
5153 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
5154 break;
5156 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
5157 break;
5159 {
5160 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
5161 }
5162 break;
5164 if (!parser()->context.token->emptyTag)
5165 {
5166 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
5167 retval=children().get_last<DocHtmlDetails>()->parse();
5168 }
5169 break;
5171 if (!parser()->context.token->emptyTag)
5172 {
5173 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
5174 retval = children().get_last<DocHtmlBlockQuote>()->parse();
5175 }
5176 break;
5177
5180 {
5181 if (!parser()->context.token->emptyTag)
5182 {
5184 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
5185 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
5186 if (d)
5187 {
5188 if (!d->summary()) // details section does not have a summary yet
5189 {
5190 d->parseSummary(n,parser()->context.token->attribs);
5191 }
5192 else
5193 {
5194 retval = Token::make_TK_NEWPARA();
5195 }
5196 }
5197 }
5198 }
5199 break;
5203 // fall through
5206 if (!children().empty())
5207 {
5208 retval = Token::make_TK_NEWPARA();
5209 }
5210 break;
5212 if (insideTable(thisVariant()))
5213 {
5214 retval = Token::make_RetVal_TableCell();
5215 }
5216 break;
5217 case HtmlTagType::XML_C:
5218 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5219 break;
5222 {
5224 QCString paramName;
5225 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5226 {
5227 if (paramName.isEmpty())
5228 {
5229 if (Config_getBool(WARN_NO_PARAMDOC))
5230 {
5231 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5232 }
5233 }
5234 else
5235 {
5236 retval = handleParamSection(paramName,
5238 TRUE);
5239 }
5240 }
5241 else
5242 {
5243 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5244 }
5245 }
5246 break;
5249 {
5250 QCString paramName;
5251 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5252 {
5253 //printf("paramName=%s\n",qPrint(paramName));
5255 children().append<DocWord>(parser(),thisVariant(),paramName);
5257 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5258 }
5259 else
5260 {
5261 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5262 }
5263 }
5264 break;
5266 {
5268 QCString exceptName;
5269 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5270 {
5271 unescapeCRef(exceptName);
5272 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5273 }
5274 else
5275 {
5276 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5277 }
5278 }
5279 break;
5282 if (insideTable(thisVariant()))
5283 {
5284 retval = Token::make_RetVal_TableRow();
5285 }
5286 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5287 {
5288 retval = Token::make_RetVal_ListItem();
5289 }
5290 else
5291 {
5292 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5293 }
5294 break;
5299 break;
5301 if (insideTable(thisVariant()))
5302 {
5303 retval = Token::make_RetVal_TableCell();
5304 }
5305 break;
5307 // I'm not sure if <see> is the same as <seealso> or if it
5308 // should you link a member without producing a section. The
5309 // C# specification is extremely vague about this (but what else
5310 // can we expect from Microsoft...)
5311 {
5312 QCString cref;
5313 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5314 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5315 {
5316 unescapeCRef(cref);
5317 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5318 {
5319 bool inSeeBlock = parser()->context.inSeeBlock;
5320 parser()->context.token->name = cref;
5323 parser()->context.inSeeBlock = inSeeBlock;
5324 }
5325 else // <see cref="...">...</see> style
5326 {
5327 //DocRef *ref = new DocRef(this,cref);
5328 //children().append(ref);
5329 //ref->parse();
5332 DocLink *lnk = children().get_last<DocLink>();
5333 QCString leftOver = lnk->parse(FALSE,TRUE);
5334 if (!leftOver.isEmpty())
5335 {
5336 children().append<DocWord>(parser(),thisVariant(),leftOver);
5337 }
5338 }
5339 }
5340 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5341 {
5342 bool inSeeBlock = parser()->context.inSeeBlock;
5343 parser()->context.token->name = cref;
5348 parser()->context.inSeeBlock = inSeeBlock;
5349 }
5350 else
5351 {
5352 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5353 }
5354 }
5355 break;
5357 {
5359 QCString cref;
5360 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5361 {
5362 unescapeCRef(cref);
5363 // Look for an existing "see" section
5364 DocNodeVariant *vss=nullptr;
5365 for (auto &n : children())
5366 {
5367 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5368 if (candidate && candidate->type()==DocSimpleSect::See)
5369 {
5370 vss = &n;
5371 }
5372 }
5373
5374 if (!vss) // start new section
5375 {
5377 vss = &children().back();
5378 }
5379
5380 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5381 retval = Token::make_RetVal_OK();
5382 }
5383 else
5384 {
5385 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5386 }
5387 }
5388 break;
5390 {
5391 QCString type;
5392 findAttribute(tagHtmlAttribs,"type",&type);
5394 HtmlAttribList emptyList;
5395 if (type=="number")
5396 {
5397 listType=DocHtmlList::Ordered;
5398 }
5399 if (type=="table")
5400 {
5401 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5402 retval=children().get_last<DocHtmlTable>()->parseXml();
5403 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5404 }
5405 else
5406 {
5407 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5408 retval=children().get_last<DocHtmlList>()->parseXml();
5409 }
5410 }
5411 break;
5414 // These tags are defined in .Net but are currently unsupported
5416 break;
5418 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5419 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5420 break;
5423 break;
5424 default:
5425 // we should not get here!
5426 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5427 ASSERT(0);
5428 break;
5429 }
5430 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5431 return retval;
5432}
5433
5435{
5436 AUTO_TRACE("tagName={}",tagName);
5437 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5438 Token retval = Token::make_RetVal_OK();
5439 switch (tagId)
5440 {
5442 if (!insideUL(thisVariant()))
5443 {
5444 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5445 }
5446 else
5447 {
5448 retval = Token::make_RetVal_EndList();
5449 }
5450 break;
5452 if (!insideOL(thisVariant()))
5453 {
5454 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5455 }
5456 else
5457 {
5458 retval = Token::make_RetVal_EndList();
5459 }
5460 break;
5462 if (!insideLI(thisVariant()))
5463 {
5464 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5465 }
5466 else
5467 {
5468 // ignore </li> tags
5469 }
5470 break;
5472 if (!insideDetails(thisVariant()))
5473 {
5474 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5475 }
5476 else
5477 {
5478 retval = Token::make_RetVal_EndHtmlDetails();
5479 }
5480 break;
5483 {
5484 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5485 }
5486 else
5487 {
5488 retval = Token::make_RetVal_EndBlockQuote();
5489 }
5490 break;
5493 break;
5496 break;
5499 break;
5502 break;
5505 break;
5508 break;
5511 break;
5514 break;
5517 break;
5520 break;
5523 break;
5526 break;
5529 break;
5532 break;
5535 break;
5538 break;
5541 break;
5546 break;
5548 retval = Token::make_TK_NEWPARA();
5549 break;
5551 retval = Token::make_RetVal_EndDesc();
5552 break;
5554 // ignore </dt> tag
5555 break;
5557 // ignore </dd> tag
5558 break;
5560 retval = Token::make_RetVal_EndTable();
5561 break;
5563 retval = Token::make_RetVal_EndTableRow();
5564 break;
5566 retval = Token::make_RetVal_EndTableCell();
5567 break;
5569 retval = Token::make_RetVal_EndTableCell();
5570 break;
5574 // for time being ignore </t....> tag
5575 break;
5577 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5578 break;
5580 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5581 break;
5583 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5584 break;
5586 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5587 break;
5589 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5590 break;
5592 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5593 break;
5595 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5596 break;
5598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5599 break;
5601 break;
5603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5604 break;
5606 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5607 // ignore </a> tag (can be part of <a name=...></a>
5608 break;
5609
5611 break;
5613 retval = Token::make_TK_NEWPARA();
5614 break;
5627 retval = Token::make_RetVal_CloseXml();
5628 break;
5629 case HtmlTagType::XML_C:
5631 break;
5639 // These tags are defined in .Net but are currently unsupported
5640 break;
5642 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5643 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5644 break;
5645 default:
5646 // we should not get here!
5647 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5648 ASSERT(0);
5649 break;
5650 }
5651 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5652 return retval;
5653}
5654
5656{
5657 // expected hierarchy:
5658 // 1. DocAutoListItem <- n
5659 // 2. DocAutoList <- parent(n)
5660 // 3. DocPara <- parent(parent(n))
5661
5662 // step 1
5663 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5664 {
5665 return false;
5666 }
5667
5668 // step 2
5669 n = parent(n);
5670 int indent = 0;
5671 const auto docAutoList = std::get_if<DocAutoList>(n);
5672 if (docAutoList) // capture indent
5673 {
5674 indent = docAutoList->indent();
5675 }
5676 else
5677 {
5678 return false;
5679 }
5680
5681 // step 3
5682 n = parent(n);
5683 const auto docPara = std::get_if<DocPara>(n);
5684 if (docPara)
5685 {
5686 QCString tagNameLower = QCString(parser->context.token->name).lower();
5687 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5688 {
5689 return std::get<DocStyleChange>(*stack.top());
5690 };
5691
5692 if (parser->context.styleStack.empty() || // no style change
5693 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5694 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5695 )
5696 {
5697 // insert an artificial 'end of autolist' marker and parse again
5698 QCString indentStr;
5699 indentStr.fill(' ',indent);
5700 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5701 return true;
5702 }
5703 }
5704 return false;
5705}
5706
5708{
5709 AUTO_TRACE();
5710 auto ns = AutoNodeStack(parser(),thisVariant());
5711 // handle style commands "inherited" from the previous paragraph
5713 Token tok=parser()->tokenizer.lex();
5714 Token retval = Token::make_TK_NONE();
5715 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5716 {
5717reparsetoken:
5718 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5719 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5720 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5721 )
5722 {
5723 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5724 }
5725 switch(tok.value())
5726 {
5727 case TokenRetval::TK_WORD:
5729 break;
5730 case TokenRetval::TK_LNKWORD:
5732 break;
5733 case TokenRetval::TK_URL:
5735 break;
5736 case TokenRetval::TK_WHITESPACE:
5737 {
5738 // prevent leading whitespace and collapse multiple whitespace areas
5739 if (insidePRE(thisVariant()) || // all whitespace is relevant
5740 (
5741 // remove leading whitespace
5742 !children().empty() &&
5743 // and whitespace after certain constructs
5747 )
5748 )
5749 {
5751 }
5752 }
5753 break;
5754 case TokenRetval::TK_LISTITEM:
5755 {
5756 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5757 const DocNodeVariant *n=parent();
5758 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5759 const DocAutoList *al = std::get_if<DocAutoList>(n);
5760 if (al) // we found an auto list up in the hierarchy
5761 {
5762 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5763 if (al->indent()>=parser()->context.token->indent)
5764 // new item at the same or lower indent level
5765 {
5766 retval = Token::make_TK_LISTITEM();
5767 goto endparagraph;
5768 }
5769 }
5770
5771 // determine list depth
5772 int depth = 0;
5773 n=parent();
5774 while (n)
5775 {
5776 al = std::get_if<DocAutoList>(n);
5777 if (al && al->isEnumList()) depth++;
5778 n=::parent(n);
5779 }
5780
5781 // first item or sub list => create new list
5782 do
5783 {
5786 parser()->context.token->isEnumList,depth,
5788 al = children().get_last<DocAutoList>();
5789 retval = children().get_last<DocAutoList>()->parse();
5790 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5791 al->indent()==parser()->context.token->indent // at same indent level
5792 );
5793
5794 // check the return value
5795 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5796 {
5797 // Reparse the token that ended the section at this level,
5798 // so a new simple section will be started at this level.
5799 // This is the same as unputting the last read token and continuing.
5801 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5802 {
5805 tok = Token::make_TK_RCSTAG();
5806 }
5807 else // other section
5808 {
5809 tok = Token::make_TK_COMMAND_BS();
5810 }
5811 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5812 goto reparsetoken;
5813 }
5814 else if (retval.is(TokenRetval::TK_ENDLIST))
5815 {
5816 if (al->indent()>parser()->context.token->indent) // end list
5817 {
5818 goto endparagraph;
5819 }
5820 else // continue with current paragraph
5821 {
5822 }
5823 }
5824 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5825 {
5826 goto endparagraph;
5827 }
5828 }
5829 break;
5830 case TokenRetval::TK_ENDLIST:
5831 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5832 if (std::get_if<DocAutoListItem>(parent()))
5833 {
5834 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5835 if (al && al->indent()>=parser()->context.token->indent)
5836 {
5837 // end of list marker ends this paragraph
5838 retval = Token::make_TK_ENDLIST();
5839 goto endparagraph;
5840 }
5841 else
5842 {
5843 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5844 "has invalid indent level");
5845 }
5846 }
5847 else
5848 {
5849 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5850 "list items");
5851 }
5852 break;
5853 case TokenRetval::TK_COMMAND_AT:
5854 // fall through
5855 case TokenRetval::TK_COMMAND_BS:
5856 {
5857 // see if we have to start a simple section
5858 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5859 const DocNodeVariant *n=parent();
5860 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5861 !std::holds_alternative<DocParamSect>(*n))
5862 {
5863 n=::parent(n);
5864 }
5866 {
5867 if (n) // already in a simple section
5868 {
5869 // simple section cannot start in this paragraph, need
5870 // to unwind the stack and remember the command.
5872 retval = Token::make_RetVal_SimpleSec();
5873 goto endparagraph;
5874 }
5875 }
5876 // see if we are in a simple list
5877 n=parent();
5878 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5879 if (n)
5880 {
5881 if (cmd==CommandType::CMD_LI)
5882 {
5883 retval = Token::make_RetVal_ListItem();
5884 goto endparagraph;
5885 }
5886 }
5887
5888 // handle the command
5889 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5890 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5891
5892 // check the return value
5893 if (retval.is(TokenRetval::RetVal_SimpleSec))
5894 {
5895 // Reparse the token that ended the section at this level,
5896 // so a new simple section will be started at this level.
5897 // This is the same as unputting the last read token and continuing.
5899 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5900 {
5903 tok = Token::make_TK_RCSTAG();
5904 }
5905 else // other section
5906 {
5907 tok = Token::make_TK_COMMAND_BS();
5908 }
5909 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5910 goto reparsetoken;
5911 }
5912 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5913 {
5914 // the command ended with a new command, reparse this token
5915 tok = retval;
5916 goto reparsetoken;
5917 }
5918 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5919 // or some auto list marker
5920 {
5921 goto endparagraph;
5922 }
5923 }
5924 break;
5925 case TokenRetval::TK_HTMLTAG:
5926 {
5927 if (!parser()->context.token->endTag) // found a start tag
5928 {
5929 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5930 }
5931 else // found an end tag
5932 {
5934 {
5935 break; // new code has been pushed back to the scanner, need to reparse
5936 }
5937 retval = handleHtmlEndTag(parser()->context.token->name);
5938 }
5939 if (!retval.is(TokenRetval::RetVal_OK))
5940 {
5941 goto endparagraph;
5942 }
5943 }
5944 break;
5945 case TokenRetval::TK_SYMBOL:
5946 {
5947 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5949 {
5951 }
5952 else
5953 {
5955 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5956 parser()->context.token->name);
5957 }
5958 break;
5959 }
5960 case TokenRetval::TK_NEWPARA:
5961 retval = Token::make_TK_NEWPARA();
5962 goto endparagraph;
5963 case TokenRetval::TK_RCSTAG:
5964 {
5965 const DocNodeVariant *n=parent();
5966 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5967 !std::holds_alternative<DocParamSect>(*n))
5968 {
5969 n=::parent(n);
5970 }
5971 if (n) // already in a simple section
5972 {
5973 // simple section cannot start in this paragraph, need
5974 // to unwind the stack and remember the command.
5977 retval = Token::make_RetVal_SimpleSec();
5978 goto endparagraph;
5979 }
5980
5981 // see if we are in a simple list
5983 children().get_last<DocSimpleSect>()->parseRcs();
5984 }
5985 break;
5986 default:
5987 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5988 "Found unexpected token (id={})",tok.to_string());
5989 break;
5990 }
5991 tok=parser()->tokenizer.lex();
5992 }
5993 retval=Token::make_TK_NONE();
5994endparagraph:
5996 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5997 if (!parser()->context.token->endTag && par &&
5998 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5999 {
6000 par->setAttribs(parser()->context.token->attribs);
6001 }
6002 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
6003 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
6004 );
6005
6006 AUTO_TRACE_EXIT("retval={}",retval.to_string());
6007 return retval;
6008}
6009
6010//--------------------------------------------------------------------------
6011
6013{
6014 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
6015 Token retval = Token::make_RetVal_OK();
6016 auto ns = AutoNodeStack(parser(),thisVariant());
6017
6018 if (!m_id.isEmpty())
6019 {
6021 if (sec)
6022 {
6023 m_file = sec->fileName();
6024 m_anchor = sec->label();
6025 QCString titleStr = sec->title();
6026 if (titleStr.isEmpty()) titleStr = sec->label();
6028 DocTitle *title = &std::get<DocTitle>(*m_title);
6029 title->parseFromString(thisVariant(),titleStr);
6030 }
6031 }
6032
6033 // first parse any number of paragraphs
6034 bool isFirst=TRUE;
6035 DocPara *lastPar=nullptr;
6036 do
6037 {
6039 DocPara *par = children().get_last<DocPara>();
6040 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6041 retval=par->parse();
6042 if (!par->isEmpty())
6043 {
6044 if (lastPar) lastPar->markLast(FALSE);
6045 lastPar = par;
6046 }
6047 else
6048 {
6049 children().pop_back();
6050 }
6051 if (retval.is(TokenRetval::TK_LISTITEM))
6052 {
6053 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6054 }
6055 if (retval.is(TokenRetval::RetVal_Internal))
6056 {
6058 retval = children().get_last<DocInternal>()->parse(m_level+1);
6059 if (retval.is(TokenRetval::RetVal_EndInternal))
6060 {
6061 retval = Token::make_RetVal_OK();
6062 }
6063 }
6064 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6065 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
6066 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
6067 );
6068
6069 if (lastPar) lastPar->markLast();
6070
6071 while (true)
6072 {
6073 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
6074 {
6075 // then parse any number of nested sections
6076 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
6077 {
6079 2,
6081 retval = children().get_last<DocSection>()->parse();
6082 }
6083 break;
6084 }
6085 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
6086 {
6087 if ((m_level <= 1) &&
6088 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6089 {
6090 warn_doc_error(parser()->context.fileName,
6091 parser()->tokenizer.getLineNr(),
6092 "Unexpected subsubsection command found inside {}!",
6094 }
6095 // then parse any number of nested sections
6096 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
6097 {
6099 3,
6101 retval = children().get_last<DocSection>()->parse();
6102 }
6103 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
6104 }
6105 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
6106 {
6107 if ((m_level <= 2) &&
6108 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6109 {
6110 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6111 "Unexpected paragraph command found inside {}!",
6113 }
6114 // then parse any number of nested sections
6115 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
6116 {
6118 4,
6120 retval = children().get_last<DocSection>()->parse();
6121 }
6122 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
6123 }
6124 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
6125 {
6126 if ((m_level <= 3) &&
6127 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6128 {
6129 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6130 "Unexpected subparagraph command found inside {}!",
6132 }
6133 // then parse any number of nested sections
6134 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
6135 {
6137 5,
6139 retval = children().get_last<DocSection>()->parse();
6140 }
6141 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
6142 }
6143 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
6144 {
6145 if ((m_level <= 4) &&
6146 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6147 {
6148 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6149 "Unexpected subsubparagraph command found inside {}!",
6151 }
6152 // then parse any number of nested sections
6153 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
6154 {
6156 6,
6158 retval = children().get_last<DocSection>()->parse();
6159 }
6160 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
6161 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
6162 }
6163 else
6164 {
6165 break;
6166 }
6167 }
6168
6169 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
6170 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6171 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
6172 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
6173 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
6174 );
6175
6176 AUTO_TRACE_EXIT("retval={}", retval.to_string());
6177 return retval;
6178}
6179
6180//--------------------------------------------------------------------------
6181
6183{
6184 AUTO_TRACE();
6185 auto ns = AutoNodeStack(parser(),thisVariant());
6187
6188 Token tok = parser()->tokenizer.lex();
6189 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
6190 {
6191 switch(tok.value())
6192 {
6193 case TokenRetval::TK_WORD:
6195 break;
6196 case TokenRetval::TK_WHITESPACE:
6198 break;
6199 case TokenRetval::TK_SYMBOL:
6200 {
6201 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
6203 {
6205 }
6206 else
6207 {
6208 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
6209 parser()->context.token->name);
6210 }
6211 }
6212 break;
6213 case TokenRetval::TK_COMMAND_AT:
6214 // fall through
6215 case TokenRetval::TK_COMMAND_BS:
6216 switch (Mappers::cmdMapper->map(parser()->context.token->name))
6217 {
6220 break;
6223 break;
6226 break;
6229 break;
6232 break;
6235 break;
6238 break;
6241 break;
6244 break;
6248 break;
6253 break;
6256 break;
6259 break;
6262 break;
6265 break;
6268 break;
6271 break;
6274 break;
6275 default:
6276 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6277 parser()->context.token->name);
6278 break;
6279 }
6280 break;
6281 default:
6282 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6283 tok.to_string());
6284 break;
6285 }
6286 tok = parser()->tokenizer.lex();
6287 }
6288
6290
6291}
6292
6293
6294//--------------------------------------------------------------------------
6295
6297{
6298 AUTO_TRACE();
6299 auto ns = AutoNodeStack(parser(),thisVariant());
6301 Token retval = Token::make_TK_NONE();
6302
6303 // first parse any number of paragraphs
6304 bool isFirst=TRUE;
6305 DocPara *lastPar = nullptr;
6306 do
6307 {
6308 {
6310 DocPara *par = children().get_last<DocPara>();
6311 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6312 retval=par->parse();
6313 if (par->isEmpty() && par->attribs().empty())
6314 {
6315 children().pop_back();
6316 }
6317 else
6318 {
6319 lastPar = par;
6320 }
6321 }
6322 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6323 if (retval == t)
6324 {
6325 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6326 {
6327 warn_doc_error(parser()->context.fileName,
6328 parser()->tokenizer.getLineNr(),
6329 "found {} command (id: '{}') outside of {} context!",
6330 sectionType,parser()->context.token->sectionId,parentSectionType);
6331 }
6332 while (retval==t)
6333 {
6334 if (!parser()->context.token->sectionId.isEmpty())
6335 {
6336 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6337 if (sec)
6338 {
6340 level,
6342 retval = children().get_last<DocSection>()->parse();
6343 }
6344 else
6345 {
6346 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6347 sectionType,parser()->context.token->sectionId,sectionType);
6348 retval = Token::make_TK_NONE();
6349 }
6350 }
6351 else
6352 {
6353 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6354 retval = Token::make_TK_NONE();
6355 }
6356 }
6357 }
6358 };
6359 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6360 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6361 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6362 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6363 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6364
6365 if (retval.is(TokenRetval::TK_LISTITEM))
6366 {
6367 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6368 }
6369 if (retval.is(TokenRetval::RetVal_Internal))
6370 {
6372 retval = children().get_last<DocInternal>()->parse(1);
6373 }
6374 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6375 if (lastPar) lastPar->markLast();
6376
6377 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6378 // then parse any number of level1 sections
6379 while (retval.is(TokenRetval::RetVal_Section))
6380 {
6381 if (!parser()->context.token->sectionId.isEmpty())
6382 {
6383 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6384 if (sec)
6385 {
6387 1,
6389 retval = children().get_last<DocSection>()->parse();
6390 }
6391 else
6392 {
6393 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6394 retval = Token::make_TK_NONE();
6395 }
6396 }
6397 else
6398 {
6399 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6400 retval = Token::make_TK_NONE();
6401 }
6402 }
6403
6405}
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:208
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:2979
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:2972
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:2932
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:951
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:915
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:1187
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1180
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:1109
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1102
Node representing an emoji.
Definition docnode.h:341
DocEmoji(DocParser *parser, DocNodeVariant *parent, const QCString &symName)
Definition docnode.cpp:159
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:514
QCString relPath() const
Definition docnode.h:534
Token parse()
Definition docnode.cpp:1501
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:1708
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:1912
void setColumnIndex(uint32_t idx)
Definition docnode.h:1217
bool isFirst() const
Definition docnode.h:1201
Token parseXml()
Definition docnode.cpp:1816
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:1850
void markFirst(bool v=TRUE)
Definition docnode.h:1203
Alignment alignment() const
Definition docnode.cpp:1874
bool isHeading() const
Definition docnode.h:1200
const HtmlAttribList & attribs() const
Definition docnode.h:1205
Token parse()
Definition docnode.cpp:1782
uint32_t colSpan() const
Definition docnode.cpp:1862
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:1491
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:1316
Node representing a Html list.
Definition docnode.h:1000
Type m_type
Definition docnode.h:1011
Token parseXml()
Definition docnode.cpp:2779
Token parse()
Definition docnode.cpp:2704
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:2116
void setVisibleCells(uint32_t n)
Definition docnode.h:1256
bool isHeading() const
Definition docnode.cpp:1934
void setRowIndex(uint32_t idx)
Definition docnode.h:1261
Token parse()
Definition docnode.cpp:2009
Node Html summary.
Definition docnode.h:844
Node representing a HTML table.
Definition docnode.h:1269
Token parseXml()
Definition docnode.cpp:2289
size_t numberHeaderRows() const
Definition docnode.cpp:2187
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1284
Token parse()
Definition docnode.cpp:2202
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2346
size_t m_numCols
Definition docnode.h:1286
const DocNodeVariant * caption() const
Definition docnode.cpp:2182
bool hasCaption() const
Definition docnode.cpp:2177
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:1293
std::unique_ptr< Private > p
Definition docnode.h:675
void parse()
Definition docnode.cpp:1308
bool isSVG() const
Definition docnode.cpp:1299
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:267
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:1611
Node representing an internal section of documentation.
Definition docnode.h:969
Token parse(int)
Definition docnode.cpp:1551
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:669
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:191
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:1140
bool parse()
Definition docnode.cpp:1147
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:2873
Node representing a paragraph in the documentation tree.
Definition docnode.h:1080
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3401
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3916
void handleInheritDoc()
Definition docnode.cpp:4174
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3454
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3395
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3984
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4211
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3590
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4089
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3877
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3793
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3431
void markLast(bool v=TRUE)
Definition docnode.h:1086
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4961
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3559
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3817
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:3957
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3779
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1115
bool m_isFirst
Definition docnode.h:1118
Token parse()
Definition docnode.cpp:5707
void handleVhdlFlow()
Definition docnode.cpp:3909
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:4120
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3709
bool m_isLast
Definition docnode.h:1119
Token handleXRefItem()
Definition docnode.cpp:3688
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5434
Token handleStartCode()
Definition docnode.cpp:4138
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:4131
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:3284
void markLast(bool b=TRUE)
Definition docnode.h:1135
Token parse(const QCString &cmdName)
Definition docnode.cpp:3205
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:3352
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:1219
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:869
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:704
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:6296
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:533
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:6012
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:2917
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:2898
Node representing a simple section.
Definition docnode.h:1017
QCString typeString() const
Definition docnode.cpp:3176
Type type() const
Definition docnode.h:1026
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:3066
Token parseRcs()
Definition docnode.cpp:3103
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:3056
const DocNodeVariant * title() const
Definition docnode.h:1033
Token parseXml()
Definition docnode.cpp:3120
void appendLinkWord(const QCString &word)
Definition docnode.cpp:3156
bool hasTitle() const
Definition docnode.cpp:3061
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:124
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:152
void parse()
Definition docnode.cpp:6182
Node representing a simple section title.
Definition docnode.h:608
void parse()
Definition docnode.cpp:3025
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:3043
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:257
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:1263
void parse()
Definition docnode.cpp:1267
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:179
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:472
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:477
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
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
QCString & prepend(const char *s)
Definition qcstring.h:422
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
bool startsWith(const char *s) const
Definition qcstring.h:507
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition qcstring.h:241
QCString lower() const
Definition qcstring.h:249
bool endsWith(const char *s) const
Definition qcstring.h:524
char & at(size_t i)
Returns a reference to the character at index i.
Definition qcstring.h:593
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:260
QCString fill(char c, int len=-1)
Fills a string with a predefined character.
Definition qcstring.h:193
const std::string & str() const
Definition qcstring.h:552
QCString & append(char c)
Definition qcstring.h:396
QCString right(size_t len) const
Definition qcstring.h:234
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:172
std::string_view view() const
Definition qcstring.h:174
QCString left(size_t len) const
Definition qcstring.h:229
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:837
static Token skipSpacesForTable(DocParser *parser)
Definition docnode.cpp:1949
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4945
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2340
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:117
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5655
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:482
#define qsnprintf
Definition qcstring.h:49
const char * qPrint(const char *s)
Definition qcstring.h:687
#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:2335
uint32_t column
Definition docnode.cpp:2336
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2334
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:828
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.