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 {
799 int funcPos = m_text.find('(');
800 if (funcPos!=-1) // see issue #11834
801 {
802 m_text=stripScope(m_text.left(funcPos))+m_text.mid(funcPos);
803 }
804 else
805 {
807 }
808 }
809
810 m_file = compound->getOutputFileBase();
811 m_ref = compound->getReference();
812 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
813 // compound->definitionType());
814 AUTO_TRACE_EXIT("compound");
815 return;
816 }
817 else if (compound && compound->definitionType()==Definition::TypeFile &&
818 toFileDef(compound)->generateSourceFile()
819 ) // undocumented file that has source code we can link to
820 {
821 m_file = compound->getSourceFileBase();
822 m_ref = compound->getReference();
823 AUTO_TRACE_EXIT("source");
824 return;
825 }
826 else
827 {
828 AUTO_TRACE_EXIT("compound '{}' not linkable",compound?compound->name():"none");
829 }
830 }
831 m_text = target;
832 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\ref command",
833 target);
834}
835
837{
838 for (auto &&elem : elements)
839 {
840 emplace_back(std::move(elem));
841 }
842 elements.clear();
843}
844
845static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
846{
847 DocNodeList newChildren;
848 for (auto &dn : children)
849 {
850 DocPara *para = std::get_if<DocPara>(&dn);
851 if (para)
852 {
853 //// move the children of the paragraph to the end of the newChildren list
854 newChildren.move_append(para->children());
855 }
856 }
857
858 // replace the children list by the newChildren list
859 children.clear();
860 children.move_append(newChildren);
861 // reparent the children
862 for (auto &cn : children)
863 {
864 setParent(&cn,root);
865 // we also need to set the parent for each child of cn, as cn's address may have changed.
866 auto opt_children = call_method_children(&cn);
867 if (opt_children)
868 {
869 for (auto &ccn : *opt_children)
870 {
871 setParent(&ccn,&cn);
872 }
873 }
874 }
875}
876
878{
879 AUTO_TRACE();
880 auto ns = AutoNodeStack(parser(),thisVariant());
881
882 Token tok = parser()->tokenizer.lex();
883 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
884 {
885 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
886 {
887 switch (tok.value())
888 {
889 case TokenRetval::TK_HTMLTAG:
890 break;
891 default:
893 break;
894 }
895 }
896 tok=parser()->tokenizer.lex();
897 }
898
899 if (children().empty() && !m_text.isEmpty())
900 {
901 QCString text = m_text;
902 if (parser()->context.insideHtmlLink)
903 {
904 // we already in a link/title only output anchor
905 text = m_anchor;
906 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
907 "Potential recursion while resolving \\ref command!");
908 }
910 parser()->pushContext();
912 parser()->popContext();
916 }
917
919}
920
921//---------------------------------------------------------------------------
922
924{
925 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
926 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
927 ASSERT(!target.isEmpty());
928 m_relPath = parser->context.relPath;
930 const CiteInfo *cite = ct.find(target);
931 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
932 m_option = opt;
934 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
935 {
936 m_ref = "";
937 m_anchor = ct.anchorPrefix()+cite->label();
939 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
940 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
941 return;
942 }
943 if (numBibFiles==0)
944 {
945 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
946 }
947 else if (cite==nullptr)
948 {
949 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\cite command",
950 target);
951 }
952 else
953 {
954 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '{}' does not have an associated number",
955 target);
956 }
957}
958
960{
961 QCString txt;
962 auto opt = m_option;
964 const CiteInfo *citeInfo = ct.find(m_target);
965
966 if (!opt.noPar()) txt += "[";
967
968 if (citeInfo)
969 {
970 if (opt.isNumber()) txt += citeInfo->text();
971 else if (opt.isShortAuthor()) txt += citeInfo->shortAuthor();
972 else if (opt.isYear()) txt += citeInfo->year();
973 }
974
975 if (!opt.noPar()) txt += "]";
976 return txt;
977}
978
979
980//---------------------------------------------------------------------------
981
983{
984 const Definition *compound = nullptr;
986 m_refText = target;
987 m_relPath = parser->context.relPath;
988 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
989 {
990 m_refText = m_refText.right(m_refText.length()-1);
991 }
992 if (resolveLink(parser->context.context,stripKnownExtensions(target),
993 parser->context.inSeeBlock,&compound,anchor,
994 parser->context.lang,parser->context.prefix))
995 {
996 m_anchor = anchor;
997 if (compound && compound->isLinkable())
998 {
999 m_file = compound->getOutputFileBase();
1000 m_ref = compound->getReference();
1001 }
1002 else if (compound && compound->definitionType()==Definition::TypeFile &&
1003 (toFileDef(compound))->generateSourceFile()
1004 ) // undocumented file that has source code we can link to
1005 {
1006 m_file = compound->getSourceFileBase();
1007 m_ref = compound->getReference();
1008 }
1009 return;
1010 }
1011
1012 // bogus link target
1013 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '{}' for \\link command",
1014 target);
1015}
1016
1017
1018QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
1019{
1020 AUTO_TRACE();
1021 QCString result;
1022 auto ns = AutoNodeStack(parser(),thisVariant());
1023
1024 Token tok = parser()->tokenizer.lex();
1025 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1026 {
1027 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
1028 {
1029 switch (tok.value())
1030 {
1031 case TokenRetval::TK_COMMAND_AT:
1032 // fall through
1033 case TokenRetval::TK_COMMAND_BS:
1034 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1035 {
1037 if (isJavaLink)
1038 {
1039 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{{@link...' ended with '{:c}{}' command",
1040 tok.command_to_char(),parser()->context.token->name);
1041 }
1042 goto endlink;
1043 default:
1044 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\link",
1045 tok.command_to_char(),parser()->context.token->name);
1046 break;
1047 }
1048 break;
1049 case TokenRetval::TK_SYMBOL:
1050 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a \\link",
1051 parser()->context.token->name);
1052 break;
1053 case TokenRetval::TK_HTMLTAG:
1054 if (parser()->context.token->name!="see" || !isXmlLink)
1055 {
1056 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command {} found as part of a \\link",
1057 parser()->context.token->name);
1058 }
1059 goto endlink;
1060 case TokenRetval::TK_LNKWORD:
1061 case TokenRetval::TK_WORD:
1062 if (isJavaLink) // special case to detect closing }
1063 {
1065 int p = 0;
1066 if (w=="}")
1067 {
1068 goto endlink;
1069 }
1070 else if ((p=w.find('}'))!=-1)
1071 {
1072 int l = static_cast<int>(w.length());
1074 if (p<l-1) // something left after the } (for instance a .)
1075 {
1076 result=w.right(l-p-1);
1077 }
1078 goto endlink;
1079 }
1080 }
1082 break;
1083 default:
1084 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",tok.to_string());
1085 break;
1086 }
1087 }
1088 tok = parser()->tokenizer.lex();
1089 }
1090 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1091 {
1092 warn_doc_error(parser()->context.fileName,
1093 parser()->tokenizer.getLineNr(),
1094 "Unexpected end of comment while inside link command");
1095 }
1096endlink:
1097
1098 if (children().empty()) // no link text
1099 {
1101 }
1102
1104 return result;
1105}
1106
1107
1108//---------------------------------------------------------------------------
1109
1116
1118{
1119 bool ok = false;
1121
1122 bool ambig = false;
1124 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1125 {
1126 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1127 }
1128 if (fd)
1129 {
1130 p->file = fd->absFilePath();
1131 ok = true;
1132 if (ambig)
1133 {
1134 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '{}' is ambiguous.\n"
1135 "Possible candidates:\n{}",p->name,
1137 );
1138 }
1139 }
1140 else
1141 {
1142 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '{}' is not found "
1143 "in any of the paths specified via DOTFILE_DIRS!",p->name);
1144 }
1145 return ok;
1146}
1147
1154
1156{
1157 bool ok = false;
1159
1160 bool ambig = false;
1162 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1163 {
1164 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1165 }
1166 if (fd)
1167 {
1168 p->file = fd->absFilePath();
1169 ok = true;
1170 if (ambig)
1171 {
1172 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '{}' is ambiguous.\n"
1173 "Possible candidates:\n{}",qPrint(p->name),
1175 );
1176 }
1177 }
1178 else
1179 {
1180 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '{}' is not found "
1181 "in any of the paths specified via MSCFILE_DIRS!",p->name);
1182 }
1183 return ok;
1184}
1185
1186//---------------------------------------------------------------------------
1187
1194
1196{
1197 bool ok = false;
1199
1200 bool ambig = false;
1202 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1203 {
1204 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
1205 }
1206 if (fd)
1207 {
1208 p->file = fd->absFilePath();
1209 ok = true;
1210 if (ambig)
1211 {
1212 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file name '{}' is ambiguous.\n"
1213 "Possible candidates:\n{}",p->name,
1215 );
1216 }
1217 }
1218 else
1219 {
1220 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file '{}' is not found "
1221 "in any of the paths specified via DIAFILE_DIRS!",p->name);
1222 }
1223 return ok;
1224}
1225//---------------------------------------------------------------------------
1226
1233
1235{
1236 bool ok = false;
1238
1239 bool ambig = false;
1241 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1242 {
1243 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1244 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1245 {
1246 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1247 }
1248 }
1249 if (fd)
1250 {
1251 p->file = fd->absFilePath();
1252 ok = true;
1253 if (ambig)
1254 {
1255 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '{}' is ambiguous.\n"
1256 "Possible candidates:\n{}",p->name,
1258 );
1259 }
1260 }
1261 else
1262 {
1263 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '{}' is not found "
1264 "in any of the paths specified via PLANTUMLFILE_DIRS!",p->name);
1265 }
1266 return ok;
1267}
1268
1269//---------------------------------------------------------------------------
1270
1274
1276{
1277 AUTO_TRACE();
1278 auto ns = AutoNodeStack(parser(),thisVariant());
1279
1281 Token tok = parser()->tokenizer.lex();
1282 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1283 {
1284 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1285 {
1286 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1287 }
1288 tok = parser()->tokenizer.lex();
1289 }
1290 parser()->tokenizer.lex();
1291
1294
1295 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1296}
1297
1298
1299//---------------------------------------------------------------------------
1300
1302 Type t,const QCString &url, bool inlineImage) :
1303 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1304{
1305}
1306
1308{
1309 QCString locName = p->url.isEmpty() ? p->name : p->url;
1310 int len = static_cast<int>(locName.length());
1311 int fnd = locName.find('?'); // ignore part from ? until end
1312 if (fnd==-1) fnd=len;
1313 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1314}
1315
1320
1321
1322//---------------------------------------------------------------------------
1323
1325{
1326 AUTO_TRACE();
1327 Token retval(TokenRetval::RetVal_OK);
1328 auto ns = AutoNodeStack(parser(),thisVariant());
1329
1330 Token tok = parser()->tokenizer.lex();
1331 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1332 {
1333 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1334 {
1335 switch (tok.value())
1336 {
1337 case TokenRetval::TK_HTMLTAG:
1338 {
1339 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1340 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1341 {
1342 if (m_level!=1)
1343 {
1344 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h1>",
1345 m_level);
1346 }
1347 goto endheader;
1348 }
1349 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1350 {
1351 if (m_level!=2)
1352 {
1353 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h2>",
1354 m_level);
1355 }
1356 goto endheader;
1357 }
1358 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1359 {
1360 if (m_level!=3)
1361 {
1362 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h3>",
1363 m_level);
1364 }
1365 goto endheader;
1366 }
1367 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1368 {
1369 if (m_level!=4)
1370 {
1371 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h4>",
1372 m_level);
1373 }
1374 goto endheader;
1375 }
1376 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1377 {
1378 if (m_level!=5)
1379 {
1380 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h5>",
1381 m_level);
1382 }
1383 goto endheader;
1384 }
1385 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1386 {
1387 if (m_level!=6)
1388 {
1389 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h6>",
1390 m_level);
1391 }
1392 goto endheader;
1393 }
1394 else if (tagId==HtmlTagType::HTML_A)
1395 {
1396 if (!parser()->context.token->endTag)
1397 {
1398 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1399 }
1400 }
1401 else if (tagId==HtmlTagType::HTML_BR)
1402 {
1404 }
1405 else
1406 {
1407 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <h{:d}> context",
1408 parser()->context.token->endTag?"/":"",parser()->context.token->name,m_level);
1409 }
1410 }
1411 break;
1412 default:
1413 char tmp[20];
1414 qsnprintf(tmp,20,"<h%d> tag",m_level);
1416 }
1417 }
1418 tok = parser()->tokenizer.lex();
1419 }
1420 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1421 {
1422 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1423 " <h{:d}> tag",m_level);
1424 }
1425endheader:
1427 return retval;
1428}
1429//---------------------------------------------------------------------------
1430
1432{
1433 AUTO_TRACE();
1434 auto ns = AutoNodeStack(parser(),thisVariant());
1436 Token tok = parser()->tokenizer.lex();
1437 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1438 {
1439 // check of </summary>
1440 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1441 (Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1442 parser()->context.token->endTag
1443 )
1444 {
1445 break;
1446 }
1447 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1448 {
1449 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1450 }
1451 tok = parser()->tokenizer.lex();
1452 }
1454 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1455 {
1456 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1457 " <summary> tag");
1458 }
1459}
1460
1461//---------------------------------------------------------------------------
1462
1464{
1465 AUTO_TRACE();
1466 Token retval(TokenRetval::TK_NONE);
1467 auto ns = AutoNodeStack(parser(),thisVariant());
1468
1469 // parse one or more paragraphs
1470 bool isFirst=TRUE;
1471 DocPara *par=nullptr;
1472 do
1473 {
1475 par = children().get_last<DocPara>();
1476 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1477 retval=par->parse();
1478 }
1479 while (retval.is(TokenRetval::TK_NEWPARA));
1480 if (par) par->markLast();
1481
1482 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1483 {
1484 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1485 }
1486
1487 if (!summary())
1488 {
1489 HtmlAttribList summaryAttribs;
1491 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1492 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1493 }
1494 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1495 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1496}
1497
1505
1506//---------------------------------------------------------------------------
1507
1509{
1510 AUTO_TRACE();
1511 Token retval(TokenRetval::RetVal_OK);
1512 auto ns = AutoNodeStack(parser(),thisVariant());
1513
1514 Token tok = parser()->tokenizer.lex();
1515 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1516 {
1517 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1518 {
1519 switch (tok.value())
1520 {
1521 case TokenRetval::TK_HTMLTAG:
1522 {
1523 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1524 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1525 {
1526 goto endhref;
1527 }
1528 else if (tagId==HtmlTagType::HTML_BR)
1529 {
1531 }
1532 else
1533 {
1534 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <a href=...> context",
1535 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1536 }
1537 }
1538 break;
1539 default:
1540 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1541 break;
1542 }
1543 }
1544 tok = parser()->tokenizer.lex();
1545 }
1546 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1547 {
1548 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1549 " <a href=...> tag");
1550 }
1551endhref:
1553 return retval;
1554}
1555
1556//---------------------------------------------------------------------------
1557
1559{
1560 AUTO_TRACE();
1561 Token retval(TokenRetval::RetVal_OK);
1562 auto ns = AutoNodeStack(parser(),thisVariant());
1563
1564 // first parse any number of paragraphs
1565 bool isFirst=TRUE;
1566 DocPara *lastPar=nullptr;
1567 do
1568 {
1570 DocPara *par = children().get_last<DocPara>();
1571 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1572 retval=par->parse();
1573 if (!par->isEmpty())
1574 {
1575 if (lastPar) lastPar->markLast(FALSE);
1576 lastPar=par;
1577 }
1578 else
1579 {
1580 children().pop_back();
1581 }
1582 if (retval.is(TokenRetval::TK_LISTITEM))
1583 {
1584 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1585 }
1586 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1587 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1588 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1589 TokenRetval::RetVal_EndInternal));
1590 if (lastPar) lastPar->markLast();
1591
1592 // then parse any number of level-n sections
1593 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1594 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1595 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1596 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1597 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1598 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1599 )
1600 {
1602 level,
1604 retval = children().get_last<DocSection>()->parse();
1605 }
1606
1607 if (retval.is(TokenRetval::RetVal_Internal))
1608 {
1609 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1610 }
1611
1612 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1613 return retval;
1614}
1615
1616//---------------------------------------------------------------------------
1617
1619{
1620 AUTO_TRACE();
1621 Token retval(TokenRetval::RetVal_OK);
1622 auto ns = AutoNodeStack(parser(),thisVariant());
1623 Token tok=parser()->tokenizer.lex();
1624 if (!tok.is(TokenRetval::TK_WHITESPACE))
1625 {
1626 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1627 goto endindexentry;
1628 }
1630 m_entry="";
1631 tok = parser()->tokenizer.lex();
1632 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1633 {
1634 switch (tok.value())
1635 {
1636 case TokenRetval::TK_WHITESPACE:
1637 m_entry+=" ";
1638 break;
1639 case TokenRetval::TK_WORD:
1640 case TokenRetval::TK_LNKWORD:
1642 break;
1643 case TokenRetval::TK_SYMBOL:
1644 {
1645 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1646 switch (s)
1647 {
1648 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1649 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1650 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1651 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1652 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1653 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1654 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1655 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1656 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1657 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1658 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1659 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1660 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1661 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1662 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1663 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1664 default:
1665 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '{}' found as argument of \\addindex",parser()->context.token->name);
1666 break;
1667 }
1668 }
1669 break;
1670 case TokenRetval::TK_COMMAND_AT:
1671 // fall through
1672 case TokenRetval::TK_COMMAND_BS:
1673 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1674 {
1675 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1676 case CommandType::CMD_AT: m_entry+='@'; break;
1677 case CommandType::CMD_LESS: m_entry+='<'; break;
1678 case CommandType::CMD_GREATER: m_entry+='>'; break;
1679 case CommandType::CMD_AMP: m_entry+='&'; break;
1680 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1681 case CommandType::CMD_HASH: m_entry+='#'; break;
1682 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1683 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1684 case CommandType::CMD_NDASH: m_entry+="--"; break;
1685 case CommandType::CMD_MDASH: m_entry+="---"; break;
1686 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1687 case CommandType::CMD_PUNT: m_entry+='.'; break;
1688 case CommandType::CMD_PLUS: m_entry+='+'; break;
1689 case CommandType::CMD_MINUS: m_entry+='-'; break;
1690 case CommandType::CMD_EQUAL: m_entry+='='; break;
1691 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1692 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1693 default:
1694 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command {} found as argument of \\addindex",
1695 parser()->context.token->name);
1696 break;
1697 }
1698 break;
1699 default:
1700 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
1701 tok.to_string());
1702 break;
1703 }
1704 tok = parser()->tokenizer.lex();
1705 }
1707 m_entry = m_entry.stripWhiteSpace();
1708endindexentry:
1709 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1710 return retval;
1711}
1712
1713//---------------------------------------------------------------------------
1714
1717{
1719 for (const auto &opt : attribs)
1720 {
1721 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1722 {
1723 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1724 if (sec)
1725 {
1726 //printf("Found anchor %s\n",qPrint(id));
1727 m_file = sec->fileName();
1728 m_anchor = sec->label();
1730 }
1731 else
1732 {
1733 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '{}'",opt.value);
1734 }
1735 }
1736 else // copy attribute
1737 {
1738 m_attribs.push_back(opt);
1739 }
1740 }
1741}
1742
1744{
1745 AUTO_TRACE();
1746 Token retval = Token::make_TK_NONE();
1747 auto ns = AutoNodeStack(parser(),thisVariant());
1748 Token tok = parser()->tokenizer.lex();
1749 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1750 {
1751 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1752 {
1753 switch (tok.value())
1754 {
1755 case TokenRetval::TK_HTMLTAG:
1756 {
1757 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1758 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1759 {
1760 retval = Token::make_RetVal_OK();
1761 goto endcaption;
1762 }
1763 else
1764 {
1765 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <caption> context",
1766 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1767 }
1768 }
1769 break;
1770 default:
1771 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1772 break;
1773 }
1774 }
1775 tok = parser()->tokenizer.lex();
1776 }
1777 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1778 {
1779 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1780 " <caption> tag");
1781 }
1782endcaption:
1784 return retval;
1785}
1786
1787//---------------------------------------------------------------------------
1788
1790{
1791 AUTO_TRACE();
1792 Token retval = Token::make_RetVal_OK();
1793 auto ns = AutoNodeStack(parser(),thisVariant());
1794
1795 // parse one or more paragraphs
1796 bool isFirst=TRUE;
1797 DocPara *par=nullptr;
1798 do
1799 {
1801 par = children().get_last<DocPara>();
1802 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1803 retval=par->parse();
1804 if (retval.is(TokenRetval::TK_HTMLTAG))
1805 {
1806 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1807 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1808 {
1809 retval = Token::make_TK_NEWPARA(); // ignore the tag
1810 }
1811 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1812 {
1813 retval = Token::make_TK_NEWPARA(); // ignore the tag
1814 }
1815 }
1816 }
1817 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1818 if (par) par->markLast();
1819
1820 return retval;
1821}
1822
1824{
1825 AUTO_TRACE();
1826 Token retval = Token::make_RetVal_OK();
1827 auto ns = AutoNodeStack(parser(),thisVariant());
1828
1829 // parse one or more paragraphs
1830 bool isFirst=TRUE;
1831 DocPara *par=nullptr;
1832 do
1833 {
1835 par = children().get_last<DocPara>();
1836 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1837 retval=par->parse();
1838 if (retval.is(TokenRetval::TK_HTMLTAG))
1839 {
1840 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1841 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1842 {
1843 retval = Token::make_TK_NEWPARA(); // ignore the tag
1844 }
1845 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1846 {
1847 retval = Token::make_TK_NEWPARA(); // ignore the tag
1848 }
1849 }
1850 }
1851 while (retval.is(TokenRetval::TK_NEWPARA));
1852 if (par) par->markLast();
1853
1854 return retval;
1855}
1856
1857uint32_t DocHtmlCell::rowSpan() const
1858{
1859 for (const auto &attr : attribs())
1860 {
1861 if (attr.name.lower()=="rowspan")
1862 {
1863 return attr.value.toUInt();
1864 }
1865 }
1866 return 0;
1867}
1868
1869uint32_t DocHtmlCell::colSpan() const
1870{
1871 for (const auto &attr : attribs())
1872 {
1873 if (attr.name.lower()=="colspan")
1874 {
1875 return std::max(1u,attr.value.toUInt());
1876 }
1877 }
1878 return 1;
1879}
1880
1882{
1883 for (const auto &attr : attribs())
1884 {
1885 QCString attrName = attr.name.lower();
1886 QCString attrValue = attr.value.lower();
1887 if (attrName=="align")
1888 {
1889 if (attrValue=="center")
1890 return Center;
1891 else if (attrValue=="right")
1892 return Right;
1893 else return Left;
1894 }
1895 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1896 {
1897 if (attrValue=="markdowntableheadcenter")
1898 return Center;
1899 else if (attrValue=="markdowntableheadright")
1900 return Right;
1901 else if (attrValue=="markdowntableheadleft")
1902 return Left;
1903 else if (attrValue=="markdowntableheadnone")
1904 return Center;
1905 else if (attrValue=="markdowntablebodycenter")
1906 return Center;
1907 else if (attrValue=="markdowntablebodyright")
1908 return Right;
1909 else if (attrValue=="markdowntablebodyleft")
1910 return Left;
1911 else if (attrValue=="markdowntablebodynone")
1912 return Left;
1913 else return Left;
1914 }
1915 }
1916 return Left;
1917}
1918
1920{
1921 for (const auto &attr : attribs())
1922 {
1923 QCString attrName = attr.name.lower();
1924 QCString attrValue = attr.value.lower();
1925 if (attrName=="valign")
1926 {
1927 if (attrValue=="top")
1928 return Top;
1929 else if (attrValue=="bottom")
1930 return Bottom;
1931 else if (attrValue=="middle")
1932 return Middle;
1933 else return Middle;
1934 }
1935 }
1936 return Middle;
1937}
1938
1939//---------------------------------------------------------------------------
1940
1942{ // a row is a table heading if all cells are marked as such
1943 bool heading=TRUE;
1944 for (const auto &n : children())
1945 {
1946 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1947 if (cell && !cell->isHeading())
1948 {
1949 heading = FALSE;
1950 break;
1951 }
1952 }
1953 return !children().empty() && heading;
1954}
1955
1957{
1958 AUTO_TRACE();
1959 // get next token
1960 Token tok=parser->tokenizer.lex();
1961 // skip whitespace and tbody, thead and tfoot tags
1962 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA,TokenRetval::TK_HTMLTAG,
1963 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS))
1964 {
1965 if (tok.is(TokenRetval::TK_HTMLTAG))
1966 {
1967 AUTO_TRACE_ADD("html_tag={}",parser->context.token->name);
1969 // skip over tbody, thead, tfoot tags
1970 if (tagId==HtmlTagType::HTML_TBODY ||
1971 tagId==HtmlTagType::HTML_THEAD ||
1973 {
1974 tok=parser->tokenizer.lex();
1975 }
1976 else
1977 {
1978 break;
1979 }
1980 }
1981 else if (tok.is(TokenRetval::TK_COMMAND_AT) || tok.is(TokenRetval::TK_COMMAND_BS))
1982 {
1983 QCString cmdName=parser->context.token->name;
1984 AUTO_TRACE_ADD("command={}",cmdName);
1985 auto cmdType = Mappers::cmdMapper->map(cmdName);
1986 if (cmdType==CommandType::CMD_ILINE)
1987 {
1988 parser->tokenizer.pushState();
1989 parser->tokenizer.setStateILine();
1990 tok = parser->tokenizer.lex();
1991 if (!tok.is(TokenRetval::TK_WORD))
1992 {
1993 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
1994 tok.command_to_char(),cmdName);
1995 }
1996 parser->tokenizer.popState();
1997 tok = parser->tokenizer.lex();
1998 }
1999 else
2000 {
2001 break;
2002 }
2003 }
2004 else
2005 {
2006 AUTO_TRACE_ADD("skip whitespace");
2007 tok=parser->tokenizer.lex();
2008 }
2009 }
2010 return tok;
2011}
2012
2013
2014
2015
2017{
2018 AUTO_TRACE();
2019 Token retval = Token::make_RetVal_OK();
2020 auto ns = AutoNodeStack(parser(),thisVariant());
2021
2022 bool isHeading=FALSE;
2023 bool isFirst=TRUE;
2024 DocHtmlCell *cell=nullptr;
2025
2027 // should find a html tag now
2028 if (tok.is(TokenRetval::TK_HTMLTAG))
2029 {
2030 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2031 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
2032 {
2033 }
2034 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
2035 {
2037 }
2038 else // found some other tag
2039 {
2040 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
2041 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2042 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2043 goto endrow;
2044 }
2045 }
2046 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2047 {
2048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2049 " for a html description title");
2050 goto endrow;
2051 }
2052 else // token other than html token
2053 {
2054 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2055 tok.to_string());
2056 goto endrow;
2057 }
2058
2059 // parse one or more cells
2060 do
2061 {
2064 isHeading);
2065 cell = children().get_last<DocHtmlCell>();
2066 cell->markFirst(isFirst);
2067 isFirst=FALSE;
2068 retval=cell->parse();
2069 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
2070 //printf("DocHtmlRow:retval=%s\n",retval.to_string());
2071 if (retval.is(TokenRetval::RetVal_EndTableCell))
2072 {
2073 // get next token
2074 retval = skipSpacesForTable(parser());
2075 //printf("DocHtmlRow:retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2076 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2077 if (tok.is(TokenRetval::TK_HTMLTAG))
2078 {
2079 if ((tagId==HtmlTagType::HTML_TD || tagId==HtmlTagType::HTML_TH) &&
2080 !parser()->context.token->endTag) // found new <td> or <td> tag
2081 {
2082 retval = Token::make_RetVal_TableCell();
2084 }
2085 else if (tagId==HtmlTagType::HTML_TR)
2086 {
2087 if (parser()->context.token->endTag) // found </tr> tag
2088 {
2089 retval = Token::make_RetVal_EndTableRow();
2090 }
2091 else // found <tr> tag
2092 {
2093 retval = Token::make_RetVal_TableRow();
2094 }
2095 }
2096 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag) // found </table>
2097 {
2098 retval = Token::make_RetVal_EndTable();
2099 }
2100 else // found some other tag
2101 {
2102 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but "
2103 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2104 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2105 goto endrow;
2106 }
2107 }
2108 else // token other than html token
2109 {
2110 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but found {} token instead!",
2111 tok.to_string());
2112 goto endrow;
2113 }
2114 }
2115 }
2116 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2117 cell->markLast(TRUE);
2118
2119endrow:
2120 return retval;
2121}
2122
2124{
2125 AUTO_TRACE();
2126 Token retval = Token::make_RetVal_OK();
2127 auto ns = AutoNodeStack(parser(),thisVariant());
2128
2129 bool isFirst=TRUE;
2130 DocHtmlCell *cell=nullptr;
2131
2132 // get next token
2133 Token tok=parser()->tokenizer.lex();
2134 // skip whitespace
2135 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2136 // should find a html tag now
2137 if (tok.is(TokenRetval::TK_HTMLTAG))
2138 {
2139 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2140 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
2141 {
2142 }
2143 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
2144 {
2145 }
2146 else // found some other tag
2147 {
2148 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
2149 "found <{}> instead!",parser()->context.token->name);
2150 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2151 goto endrow;
2152 }
2153 }
2154 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2155 {
2156 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2157 " for a html description title");
2158 goto endrow;
2159 }
2160 else // token other than html token
2161 {
2162 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2163 tok.to_string());
2164 goto endrow;
2165 }
2166
2167 do
2168 {
2170 cell = children().get_last<DocHtmlCell>();
2171 cell->markFirst(isFirst);
2172 isFirst=FALSE;
2173 retval=cell->parseXml();
2174 }
2175 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2176 cell->markLast(TRUE);
2177
2178endrow:
2179 return retval;
2180}
2181
2182//---------------------------------------------------------------------------
2183
2185{
2186 return m_caption!=nullptr;
2187}
2188
2190{
2191 return m_caption.get();
2192}
2193
2195{
2196 size_t hl = 0;
2197 for (auto &rowNode : children())
2198 {
2199 const DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2200 if (row)
2201 {
2202 if (!row->isHeading()) break;
2203 hl++;
2204 }
2205 }
2206 return hl;
2207}
2208
2210{
2211 AUTO_TRACE();
2212 Token retval = Token::make_RetVal_OK();
2213 auto ns = AutoNodeStack(parser(),thisVariant());
2214
2215getrow:
2216 // skip whitespace and tbody, thead and tfoot tags
2218 // should find a html tag now
2219 if (tok.is(TokenRetval::TK_HTMLTAG))
2220 {
2221 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2222 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2223 {
2224 // no caption, just rows
2225 retval = Token::make_RetVal_TableRow();
2226 }
2227 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2228 {
2229 if (m_caption)
2230 {
2231 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2232 }
2233 else
2234 {
2235 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2236 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2237
2238 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2239 {
2240 goto getrow;
2241 }
2242 }
2243 }
2244 else // found wrong token
2245 {
2246 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2247 "found <{}{}> instead!", parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2248 }
2249 }
2250 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2251 {
2252 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2253 " for a <tr> or <caption> tag");
2254 }
2255 else // token other than html token
2256 {
2257 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found {} token instead!",
2258 tok.to_string());
2259 }
2260
2261 // parse one or more rows
2262 while (retval.is(TokenRetval::RetVal_TableRow))
2263 {
2265 retval = children().get_last<DocHtmlRow>()->parse();
2266 //printf("DocHtmlTable::retval=%s\n",retval.to_string());
2267 if (retval.is(TokenRetval::RetVal_EndTableRow))
2268 {
2269 // get next token
2270 retval = skipSpacesForTable(parser());
2271 //printf("DocHtmlTable::retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2272 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2273 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag)
2274 {
2275 retval = Token::make_RetVal_TableRow();
2276 }
2277 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag)
2278 {
2279 retval = Token::make_RetVal_EndTable();
2280 }
2281 else // found some other tag
2282 {
2283 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or </table> tag but "
2284 "found token {} instead!",retval.to_string());
2285 retval=Token::make_RetVal_OK();
2286 break;
2287 }
2288 }
2289 }
2290
2292
2293 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2294}
2295
2297{
2298 AUTO_TRACE();
2299 Token retval = Token::make_RetVal_OK();
2300 auto ns = AutoNodeStack(parser(),thisVariant());
2301
2302 // get next token
2303 Token tok=parser()->tokenizer.lex();
2304 // skip whitespace
2305 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2306 // should find a html tag now
2308 bool isHeader=FALSE;
2309 if (tok.is(TokenRetval::TK_HTMLTAG))
2310 {
2311 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2312 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2313 {
2314 retval = Token::make_RetVal_TableRow();
2315 }
2316 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2317 {
2318 retval = Token::make_RetVal_TableRow();
2319 isHeader=TRUE;
2320 }
2321 }
2322
2323 // parse one or more rows
2324 while (retval.is(TokenRetval::RetVal_TableRow))
2325 {
2328 retval=tr->parseXml(isHeader);
2329 isHeader=FALSE;
2330 }
2331
2333
2334 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2335 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2336}
2337
2338/** Helper class to compute the grid for an HTML style table */
2340{
2341 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2342 uint32_t rowsLeft;
2343 uint32_t column;
2344};
2345
2346/** List of ActiveRowSpan classes. */
2347typedef std::vector<ActiveRowSpan> RowSpanList;
2348
2349/** determines the location of all cells in a grid, resolving row and
2350 column spans. For each the total number of visible cells is computed,
2351 and the total number of visible columns over all rows is stored.
2352 */
2354{
2355 //printf("computeTableGrid()\n");
2356 RowSpanList rowSpans;
2357 uint32_t maxCols=0;
2358 uint32_t rowIdx=1;
2359 for (auto &rowNode : children())
2360 {
2361 uint32_t colIdx=1;
2362 uint32_t cells=0;
2363 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2364 if (row)
2365 {
2366 for (auto &cellNode : row->children())
2367 {
2368 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2369 if (cell)
2370 {
2371 uint32_t rs = cell->rowSpan();
2372 uint32_t cs = cell->colSpan();
2373
2374 for (size_t i=0;i<rowSpans.size();i++)
2375 {
2376 if (rowSpans[i].rowsLeft>0 &&
2377 rowSpans[i].column==colIdx)
2378 {
2379 colIdx=rowSpans[i].column+1;
2380 cells++;
2381 }
2382 }
2383 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2384 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2385 cell->setRowIndex(rowIdx);
2386 cell->setColumnIndex(colIdx);
2387 colIdx+=cs;
2388 cells++;
2389 }
2390 }
2391 for (size_t i=0;i<rowSpans.size();i++)
2392 {
2393 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2394 }
2395 row->setVisibleCells(cells);
2396 row->setRowIndex(rowIdx);
2397 rowIdx++;
2398 }
2399 if (colIdx-1>maxCols) maxCols=colIdx-1;
2400 }
2401 m_numCols = maxCols;
2402}
2403
2404//---------------------------------------------------------------------------
2405
2407{
2408 AUTO_TRACE();
2409 Token retval = Token::make_TK_NONE();
2410 auto ns = AutoNodeStack(parser(),thisVariant());
2411
2412 Token tok = parser()->tokenizer.lex();
2413 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2414 {
2415 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2416 {
2417 switch (tok.value())
2418 {
2419 case TokenRetval::TK_COMMAND_AT:
2420 // fall through
2421 case TokenRetval::TK_COMMAND_BS:
2422 {
2423 QCString cmdName=parser()->context.token->name;
2424 bool isJavaLink=FALSE;
2425 switch (Mappers::cmdMapper->map(cmdName))
2426 {
2428 {
2429 tok=parser()->tokenizer.lex();
2430 if (!tok.is(TokenRetval::TK_WHITESPACE))
2431 {
2432 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
2433 tok.command_to_char(),cmdName);
2434 }
2435 else
2436 {
2438 tok=parser()->tokenizer.lex(); // get the reference id
2439 if (!tok.is(TokenRetval::TK_WORD))
2440 {
2441 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}' command",
2442 tok.to_string(),tok.command_to_char(),cmdName);
2443 }
2444 else
2445 {
2447 children().get_last<DocRef>()->parse();
2448 }
2450 }
2451 }
2452 break;
2454 isJavaLink=TRUE;
2455 // fall through
2457 {
2458 tok=parser()->tokenizer.lex();
2459 if (!tok.is(TokenRetval::TK_WHITESPACE))
2460 {
2461 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
2462 cmdName);
2463 }
2464 else
2465 {
2467 tok=parser()->tokenizer.lex();
2468 if (!tok.is(TokenRetval::TK_WORD))
2469 {
2470 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\{} command",
2471 tok.to_string(),cmdName);
2472 }
2473 else
2474 {
2477 DocLink *lnk = children().get_last<DocLink>();
2478 QCString leftOver = lnk->parse(isJavaLink);
2479 if (!leftOver.isEmpty())
2480 {
2481 children().append<DocWord>(parser(),thisVariant(),leftOver);
2482 }
2483 }
2484 }
2485 }
2486 break;
2488 {
2490 }
2491 break;
2492 default:
2493 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' found as part of a <dt> tag",
2494 tok.command_to_char(),cmdName);
2495 }
2496 }
2497 break;
2498 case TokenRetval::TK_SYMBOL:
2499 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a <dt> tag",
2500 parser()->context.token->name);
2501 break;
2502 case TokenRetval::TK_HTMLTAG:
2503 {
2504 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2505 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2506 {
2507 retval = Token::make_RetVal_DescData();
2508 goto endtitle;
2509 }
2510 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2511 {
2512 // ignore </dt> tag.
2513 }
2514 else if (tagId==HtmlTagType::HTML_DT)
2515 {
2516 // missing <dt> tag.
2517 retval = Token::make_RetVal_DescTitle();
2518 goto endtitle;
2519 }
2520 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2521 {
2522 retval = Token::make_RetVal_EndDesc();
2523 goto endtitle;
2524 }
2525 else if (tagId==HtmlTagType::HTML_A)
2526 {
2527 if (!parser()->context.token->endTag)
2528 {
2529 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2530 }
2531 }
2532 else if (tagId==HtmlTagType::HTML_BR)
2533 {
2535 }
2536 else
2537 {
2538 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <dt> context",
2539 parser()->context.token->endTag?"/":"",parser()->context.token->name);
2540 }
2541 }
2542 break;
2543 default:
2544 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} found as part of a <dt> tag",
2545 tok.to_string());
2546 break;
2547 }
2548 }
2549 tok = parser()->tokenizer.lex();
2550 }
2551 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2552 {
2553 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2554 " <dt> tag");
2555 }
2556endtitle:
2558 return retval;
2559}
2560
2561//---------------------------------------------------------------------------
2562
2564{
2565 AUTO_TRACE();
2567 Token retval = Token::make_TK_NONE();
2568 auto ns = AutoNodeStack(parser(),thisVariant());
2569
2570 bool isFirst=TRUE;
2571 DocPara *par=nullptr;
2572 do
2573 {
2575 par = children().get_last<DocPara>();
2576 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2577 retval=par->parse();
2578 }
2579 while (retval.is(TokenRetval::TK_NEWPARA));
2580 if (par) par->markLast();
2581
2582 return retval;
2583}
2584
2585//---------------------------------------------------------------------------
2586
2588{
2589 AUTO_TRACE();
2590 Token retval = Token::make_RetVal_OK();
2591 auto ns = AutoNodeStack(parser(),thisVariant());
2592
2593 // get next token
2594 Token tok=parser()->tokenizer.lex();
2595 // skip whitespace
2596 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2597 // should find a html tag now
2598 if (tok.is(TokenRetval::TK_HTMLTAG))
2599 {
2600 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2601 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2602 {
2603 // continue
2604 }
2605 else // found some other tag
2606 {
2607 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2608 "found <{}> instead!",parser()->context.token->name);
2609 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2610 goto enddesclist;
2611 }
2612 }
2613 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2614 {
2615 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2616 " for a html description title");
2617 goto enddesclist;
2618 }
2619 else // token other than html token
2620 {
2621 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found {} token instead!",
2622 tok.to_string());
2623 goto enddesclist;
2624 }
2625
2626 do
2627 {
2632 retval=dt->parse();
2633 if (retval.is(TokenRetval::RetVal_DescData))
2634 {
2635 retval=dd->parse();
2636 while (retval.is(TokenRetval::RetVal_DescData))
2637 {
2640 retval=dd->parse();
2641 }
2642 }
2643 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2644 {
2645 // error
2646 break;
2647 }
2648 } while (retval.is(TokenRetval::RetVal_DescTitle));
2649
2650 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2651 {
2652 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2653 }
2654
2655enddesclist:
2656
2657 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2658}
2659
2660//---------------------------------------------------------------------------
2661
2663{
2664 AUTO_TRACE();
2665 Token retval = Token::make_TK_NONE();
2666 auto ns = AutoNodeStack(parser(),thisVariant());
2667
2668 // parse one or more paragraphs
2669 bool isFirst=TRUE;
2670 DocPara *par=nullptr;
2671 do
2672 {
2674 par = children().get_last<DocPara>();
2675 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2676 retval=par->parse();
2677 }
2678 while (retval.is(TokenRetval::TK_NEWPARA));
2679 if (par) par->markLast();
2680
2681 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2682 return retval;
2683}
2684
2686{
2687 AUTO_TRACE();
2688 Token retval = Token::make_TK_NONE();
2689 auto ns = AutoNodeStack(parser(),thisVariant());
2690
2691 // parse one or more paragraphs
2692 bool isFirst=TRUE;
2693 DocPara *par=nullptr;
2694 do
2695 {
2697 par = children().get_last<DocPara>();
2698 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2699 retval=par->parse();
2700 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2701
2702 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2703 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2704 if (retval.is(TokenRetval::RetVal_ListItem))
2705 {
2706 break;
2707 }
2708 }
2709 while (!retval.is(TokenRetval::RetVal_CloseXml));
2710
2711 if (par) par->markLast();
2712
2713 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2714 return retval;
2715}
2716
2717//---------------------------------------------------------------------------
2718
2720{
2721 AUTO_TRACE();
2722 Token retval = Token::make_RetVal_OK();
2723 int num=1;
2724 auto ns = AutoNodeStack(parser(),thisVariant());
2725
2726 // get next token
2727 Token tok=parser()->tokenizer.lex();
2728 // skip whitespace and paragraph breaks
2729 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2730 // should find a html tag now
2731 if (tok.is(TokenRetval::TK_HTMLTAG))
2732 {
2733 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2734 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2735 {
2736 // ok, we can go on.
2737 }
2738 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2740 ) && parser()->context.token->endTag
2741 ) // found empty list
2742 {
2743 // add dummy item to obtain valid HTML
2745 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2746 retval = Token::make_RetVal_EndList();
2747 goto endlist;
2748 }
2749 else // found some other tag
2750 {
2751 // add dummy item to obtain valid HTML
2753 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2754 "found <{}{}> instead!",parser()->context.token->endTag?"/":"",parser()->context.token->name);
2755 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2756 goto endlist;
2757 }
2758 }
2759 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2760 {
2761 // add dummy item to obtain valid HTML
2763 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2764 " for a html list item");
2765 goto endlist;
2766 }
2767 else // token other than html token
2768 {
2769 // add dummy item to obtain valid HTML
2771 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found {} token instead!",
2772 tok.to_string());
2773 goto endlist;
2774 }
2775
2776 do
2777 {
2780 retval=li->parse();
2781 } while (retval.is(TokenRetval::RetVal_ListItem));
2782
2783 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2784 {
2785 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <{:c}l> block",
2786 m_type==Unordered ? 'u' : 'o');
2787 }
2788
2789endlist:
2790 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2791 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2792}
2793
2795{
2796 AUTO_TRACE();
2797 Token retval = Token::make_RetVal_OK();
2798 int num=1;
2799 auto ns = AutoNodeStack(parser(),thisVariant());
2800
2801 // get next token
2802 Token tok=parser()->tokenizer.lex();
2803 // skip whitespace and paragraph breaks
2804 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2805 // should find a html tag now
2806 if (tok.is(TokenRetval::TK_HTMLTAG))
2807 {
2808 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2809 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2810 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2811 {
2812 // ok, we can go on.
2813 }
2814 else // found some other tag
2815 {
2816 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2817 "found <{}> instead!",parser()->context.token->name);
2818 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2819 goto endlist;
2820 }
2821 }
2822 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2823 {
2824 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2825 " for a html list item");
2826 goto endlist;
2827 }
2828 else // token other than html token
2829 {
2830 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found {} token instead!",
2831 tok.to_string());
2832 goto endlist;
2833 }
2834
2835 do
2836 {
2839 retval=li->parseXml();
2840 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2841 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2842 } while (retval.is(TokenRetval::RetVal_ListItem));
2843
2844 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2845 {
2846 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"{}\"> block",
2847 m_type==Unordered ? "bullet" : "number");
2848 }
2849
2850endlist:
2851 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2852 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2853 Token::make_RetVal_OK() : retval;
2854}
2855
2856//--------------------------------------------------------------------------
2857
2859{
2860 AUTO_TRACE();
2861 Token retval = Token::make_TK_NONE();
2862 auto ns = AutoNodeStack(parser(),thisVariant());
2863
2864 // parse one or more paragraphs
2865 bool isFirst=TRUE;
2866 DocPara *par=nullptr;
2867 do
2868 {
2870 par = children().get_last<DocPara>();
2871 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2872 retval=par->parse();
2873 }
2874 while (retval.is(TokenRetval::TK_NEWPARA));
2875 if (par) par->markLast();
2876
2877 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2878 {
2879 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2880 }
2881
2882 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2883 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2884}
2885
2886//---------------------------------------------------------------------------
2887
2889{
2890 AUTO_TRACE();
2891 Token retval = Token::make_TK_NONE();
2892 auto ns = AutoNodeStack(parser(),thisVariant());
2893
2894 // parse one or more paragraphs
2895 bool isFirst=TRUE;
2896 DocPara *par=nullptr;
2897 do
2898 {
2900 par = children().get_last<DocPara>();
2901 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2902 retval=par->parse();
2903 }
2904 while (retval.is(TokenRetval::TK_NEWPARA));
2905 if (par) par->markLast();
2906
2907 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2908 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2909}
2910
2911//---------------------------------------------------------------------------
2912
2917
2918
2920{
2921 auto ns = AutoNodeStack(parser(),thisVariant());
2923 DocPara *par = &std::get<DocPara>(*m_paragraph);
2924 Token rv=par->parse();
2925 par->markFirst();
2926 par->markLast();
2927 return rv;
2928}
2929
2930//--------------------------------------------------------------------------
2931
2933{
2934 auto ns = AutoNodeStack(parser(),thisVariant());
2935 Token rv = Token::make_TK_NONE();
2936 do
2937 {
2940 rv=li->parse();
2941 } while (rv.is(TokenRetval::RetVal_ListItem));
2942 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2943}
2944
2945//--------------------------------------------------------------------------
2946
2951
2953{
2954 AUTO_TRACE();
2955 Token retval = Token::make_RetVal_OK();
2956 auto ns = AutoNodeStack(parser(),thisVariant());
2957
2958 // first parse any number of paragraphs
2959 bool isFirst=TRUE;
2960 DocPara *lastPar=nullptr;
2961 do
2962 {
2964 DocPara *par = children().get_last<DocPara>();
2965 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2966 retval=par->parse();
2967 if (!par->isEmpty())
2968 {
2969 if (lastPar) lastPar->markLast(FALSE);
2970 lastPar=par;
2971 }
2972 else
2973 {
2974 children().pop_back();
2975 }
2976 // next paragraph should be more indented than the - marker to belong
2977 // to this item
2978 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2979 if (lastPar) lastPar->markLast();
2980
2981 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2982 return retval;
2983}
2984
2985//--------------------------------------------------------------------------
2986
2993
2995{
2996 AUTO_TRACE();
2997 Token retval = Token::make_RetVal_OK();
2998 int num=1;
2999 auto ns = AutoNodeStack(parser(),thisVariant());
3001 // first item or sub list => create new list
3002 do
3003 {
3004 switch (parser()->context.token->id)
3005 {
3006 case -1:
3007 break;
3008 case DocAutoList::Unchecked: // unchecked
3009 case DocAutoList::Checked_x: // checked with x
3010 case DocAutoList::Checked_X: // checked with X
3011 num = parser()->context.token->id;
3012 break;
3013 default: // explicitly numbered list
3014 num=parser()->context.token->id; // override num with real number given
3015 break;
3016 }
3017
3019 retval = children().get_last<DocAutoListItem>()->parse();
3020 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
3021 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
3022 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
3023 // qPrint(parser()->context.token->name));
3024 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
3025 }
3026 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
3027 m_indent==parser()->context.token->indent && // at same indent level
3028 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
3029 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
3030 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
3031 );
3032
3034
3035 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3036 return retval;
3037}
3038
3039//--------------------------------------------------------------------------
3040
3042{
3043 AUTO_TRACE();
3044 auto ns = AutoNodeStack(parser(),thisVariant());
3046 Token tok = parser()->tokenizer.lex();
3047 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
3048 {
3049 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
3050 {
3051 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
3052 }
3053 tok = parser()->tokenizer.lex();
3054 }
3057}
3058
3060{
3062 parser()->pushContext(); // this will create a new parser->context.token
3064 parser()->popContext(); // this will restore the old parser->context.token
3068}
3069
3070//--------------------------------------------------------------------------
3071
3076
3078{
3079 return m_title && std::get<DocTitle>(*m_title).hasTitle();
3080}
3081
3082Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
3083{
3084 AUTO_TRACE();
3085 auto ns = AutoNodeStack(parser(),thisVariant());
3086
3087 // handle case for user defined title
3088 if (userTitle)
3089 {
3091 std::get_if<DocTitle>(m_title.get())->parse();
3092 }
3093
3094 // add new paragraph as child
3095 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3096 {
3097 std::get<DocPara>(children().back()).markLast(FALSE);
3098 }
3099 bool markFirst = children().empty();
3100 if (needsSeparator)
3101 {
3103 }
3105 DocPara *par = children().get_last<DocPara>();
3106 if (markFirst)
3107 {
3108 par->markFirst();
3109 }
3110 par->markLast();
3111
3112 // parse the contents of the paragraph
3113 Token retval = par->parse();
3114
3115 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3116 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
3117}
3118
3120{
3121 AUTO_TRACE();
3122 auto ns = AutoNodeStack(parser(),thisVariant());
3123
3125 DocTitle *title = &std::get<DocTitle>(*m_title);
3126 title->parseFromString(thisVariant(),parser()->context.token->name);
3127
3128 QCString text = parser()->context.token->text;
3129 parser()->pushContext(); // this will create a new parser->context.token
3131 parser()->popContext(); // this will restore the old parser->context.token
3132
3133 return Token::make_RetVal_OK();
3134}
3135
3137{
3138 AUTO_TRACE();
3139 auto ns = AutoNodeStack(parser(),thisVariant());
3140
3141 Token retval = Token::make_RetVal_OK();
3142 for (;;)
3143 {
3144 // add new paragraph as child
3145 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3146 {
3147 std::get<DocPara>(children().back()).markLast(false);
3148 }
3149 bool markFirst = children().empty();
3151 DocPara *par = children().get_last<DocPara>();
3152 if (markFirst)
3153 {
3154 par->markFirst();
3155 }
3156 par->markLast();
3157
3158 // parse the contents of the paragraph
3159 retval = par->parse();
3160 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3161 if (retval.is(TokenRetval::RetVal_CloseXml))
3162 {
3163 retval = Token::make_RetVal_OK();
3164 break;
3165 }
3166 }
3167
3168 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3169 return retval;
3170}
3171
3173{
3174 DocPara *p=nullptr;
3175 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
3176 {
3178 p = children().get_last<DocPara>();
3179 }
3180 else
3181 {
3182 // Comma-separate <seealso> links.
3183 p->injectToken(Token::make_TK_WORD(),",");
3184 p->injectToken(Token::make_TK_WHITESPACE()," ");
3185 }
3186
3188 p->injectToken(Token::make_TK_LNKWORD(),word);
3190}
3191
3193{
3194 switch (m_type)
3195 {
3196 case Unknown: break;
3197 case See: return "see";
3198 case Return: return "return";
3199 case Author: // fall through
3200 case Authors: return "author";
3201 case Version: return "version";
3202 case Since: return "since";
3203 case Date: return "date";
3204 case Note: return "note";
3205 case Warning: return "warning";
3206 case Pre: return "pre";
3207 case Post: return "post";
3208 case Copyright: return "copyright";
3209 case Invar: return "invariant";
3210 case Remark: return "remark";
3211 case Attention: return "attention";
3212 case Important: return "important";
3213 case User: return "user";
3214 case Rcs: return "rcs";
3215 }
3216 return "unknown";
3217}
3218
3219//--------------------------------------------------------------------------
3220
3222{
3223 AUTO_TRACE();
3224 Token retval = Token::make_RetVal_OK();
3225 auto ns = AutoNodeStack(parser(),thisVariant());
3226 DocPara *par=nullptr;
3227 QCString saveCmdName = cmdName;
3228
3229 Token tok=parser()->tokenizer.lex();
3230 if (!tok.is(TokenRetval::TK_WHITESPACE))
3231 {
3232 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3233 saveCmdName);
3234 retval = Token::make_RetVal_EndParBlock();
3235 goto endparamlist;
3236 }
3238 tok=parser()->tokenizer.lex();
3239 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3240 {
3242 {
3243 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3244 if (typeSeparator!=-1)
3245 {
3246 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3247 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3250 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3251 {
3252 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3253 }
3254 }
3255 else
3256 {
3259 }
3260 }
3261 else if (m_type==DocParamSect::RetVal)
3262 {
3265 }
3266 //m_params.append(parser()->context.token->name);
3268 tok=parser()->tokenizer.lex();
3269 }
3271 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3272 {
3273 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3274 "argument of command {}",saveCmdName);
3275 retval = Token::make_RetVal_EndParBlock();
3276 goto endparamlist;
3277 }
3278 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3279 {
3280 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3281 {
3282 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3283 "argument of command {}",tok.to_string(),saveCmdName);
3284 }
3285 retval = Token::make_RetVal_EndParBlock();
3286 goto endparamlist;
3287 }
3288
3290 par = m_paragraphs.get_last<DocPara>();
3291 retval = par->parse();
3292 par->markFirst();
3293 par->markLast();
3294
3295endparamlist:
3296 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3297 return retval;
3298}
3299
3301{
3302 AUTO_TRACE();
3303 Token retval = Token::make_RetVal_OK();
3304 auto ns = AutoNodeStack(parser(),thisVariant());
3305
3306 parser()->context.token->name = paramName;
3308 {
3311 }
3312 else if (m_type==DocParamSect::RetVal)
3313 {
3316 }
3317
3319
3320 do
3321 {
3323 DocPara *par = m_paragraphs.get_last<DocPara>();
3324 retval = par->parse();
3325 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3326 // after </para> and before </param>
3327 {
3328 m_paragraphs.pop_back();
3329 break;
3330 }
3331 else // append the paragraph to the list
3332 {
3333 if (!m_paragraphs.empty())
3334 {
3335 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3336 }
3337 bool markFirst = m_paragraphs.empty();
3338 par = &std::get<DocPara>(m_paragraphs.back());
3339 if (markFirst)
3340 {
3341 par->markFirst();
3342 }
3343 par->markLast();
3344 }
3345
3346 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3347
3348 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3349 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3350 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3351 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3352
3353 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3354 {
3355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3356 }
3357 else
3358 {
3359 retval = Token::make_RetVal_OK();
3360 }
3361
3362 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3363 return retval;
3364}
3365
3366//--------------------------------------------------------------------------
3367
3368Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3369{
3370 AUTO_TRACE();
3371 Token retval = Token::make_RetVal_OK();
3372 auto ns = AutoNodeStack(parser(),thisVariant());
3373
3374 if (d!=Unspecified)
3375 {
3377 }
3378
3379 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3380 {
3381 DocParamList &lastPl = std::get<DocParamList>(children().back());
3382 lastPl.markLast(false);
3383 }
3384 bool markFirst = children().empty();
3387 if (markFirst)
3388 {
3389 pl->markFirst();
3390 }
3391 pl->markLast();
3392 if (xmlContext)
3393 {
3394 retval = pl->parseXml(cmdName);
3395 }
3396 else
3397 {
3398 retval = pl->parse(cmdName);
3399 }
3400 if (retval.is(TokenRetval::RetVal_EndParBlock))
3401 {
3402 retval = Token::make_RetVal_OK();
3403 }
3404
3405 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3406 return retval;
3407}
3408
3409//--------------------------------------------------------------------------
3410
3416
3418{
3419 AUTO_TRACE();
3420 DocSimpleSect *ss=nullptr;
3421 bool needsSeparator = FALSE;
3422 if (!children().empty() && // has previous element
3423 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3424 ss->type()==t && // of same type
3425 t!=DocSimpleSect::User) // but not user defined
3426 {
3427 // append to previous section
3428 needsSeparator = TRUE;
3429 }
3430 else // start new section
3431 {
3434 }
3435 Token rv = Token::make_RetVal_OK();
3436 if (xmlContext)
3437 {
3438 return ss->parseXml();
3439 }
3440 else
3441 {
3442 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3443 }
3444 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3445}
3446
3449 bool xmlContext=FALSE,
3450 int direction=DocParamSect::Unspecified)
3451{
3452 AUTO_TRACE();
3453 DocParamSect *ps = nullptr;
3454 if (!children().empty() && // previous element
3455 (ps=children().get_last<DocParamSect>()) && // was a param sect
3456 ps->type()==t) // of same type
3457 { // append to previous section ps
3458 }
3459 else // start new section
3460 {
3462 ps = children().get_last<DocParamSect>();
3463 }
3464 Token rv=ps->parse(cmdName,xmlContext,
3465 static_cast<DocParamSect::Direction>(direction));
3466 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3467 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3468}
3469
3470void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3471{
3472 AUTO_TRACE();
3473 QCString saveCmdName = cmdName;
3474 // get the argument of the cite command.
3475 Token tok=parser()->tokenizer.lex();
3476
3477 CiteInfoOption option;
3478 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3479 {
3481 parser()->tokenizer.lex();
3482 StringVector optList=split(parser()->context.token->name.str(),",");
3483 for (auto const &opt : optList)
3484 {
3485 if (opt == "number")
3486 {
3487 if (!option.isUnknown())
3488 {
3489 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3490 }
3491 else
3492 {
3493 option = CiteInfoOption::makeNumber();
3494 }
3495 }
3496 else if (opt == "year")
3497 {
3498 if (!option.isUnknown())
3499 {
3500 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3501 }
3502 else
3503 {
3504 option = CiteInfoOption::makeYear();
3505 }
3506 }
3507 else if (opt == "shortauthor")
3508 {
3509 if (!option.isUnknown())
3510 {
3511 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3512 }
3513 else
3514 {
3516 }
3517 }
3518 else if (opt == "nopar")
3519 {
3520 option.setNoPar();
3521 }
3522 else if (opt == "nocite")
3523 {
3524 option.setNoCite();
3525 }
3526 else
3527 {
3528 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unknown option specified with \\{}, discarding '{}'", saveCmdName, opt);
3529 }
3530 }
3531
3532 if (option.isUnknown()) option.changeToNumber();
3533
3535 tok=parser()->tokenizer.lex();
3536 if (!tok.is(TokenRetval::TK_WHITESPACE))
3537 {
3538 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3539 saveCmdName);
3540 return;
3541 }
3542 }
3543 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3544 {
3545 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3546 cmdChar,saveCmdName);
3547 return;
3548 }
3549 else
3550 {
3551 option = CiteInfoOption::makeNumber();
3552 }
3553
3555 tok=parser()->tokenizer.lex();
3556 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3557 {
3558 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"THE ONE unexpected end of comment block while parsing the "
3559 "argument of command '{:c}{}'",cmdChar,saveCmdName);
3560 return;
3561 }
3562 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3563 {
3564 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3565 tok.to_string(),cmdChar,saveCmdName);
3566 return;
3567 }
3571
3573}
3574
3575void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3576{
3577 AUTO_TRACE();
3578 // get the argument of the emoji command.
3579 Token tok=parser()->tokenizer.lex();
3580 if (!tok.is(TokenRetval::TK_WHITESPACE))
3581 {
3582 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3583 cmdChar,cmdName);
3584 return;
3585 }
3587 tok=parser()->tokenizer.lex();
3588 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3589 {
3590 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3591 "argument of command '{:c}{}'",cmdChar,cmdName);
3593 return;
3594 }
3595 else if (!tok.is(TokenRetval::TK_WORD))
3596 {
3597 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3598 tok.to_string(),cmdChar,cmdName);
3600 return;
3601 }
3604}
3605
3606void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3607{
3608 // get the argument of the cite command.
3609 Token tok=parser()->tokenizer.lex();
3610 if (!tok.is(TokenRetval::TK_WHITESPACE))
3611 {
3612 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3613 cmdChar,cmdName);
3614 return;
3615 }
3617 tok=parser()->tokenizer.lex();
3618 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3619 {
3620 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3621 "argument of command '{:c}{}'",cmdChar,cmdName);
3622 return;
3623 }
3624 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3625 {
3626 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3627 tok.to_string(),cmdChar,cmdName);
3628 return;
3629 }
3630 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3631 if (opt)
3632 {
3633 QCString optionValue;
3634 switch (opt->kind())
3635 {
3637 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3638 break;
3640 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3641 break;
3643 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3644 break;
3646 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3647 break;
3649 {
3650 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3651 optionValue="";
3652 if (!lst->empty())
3653 {
3654 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3655 static const reg::Ex marker(R"(@(\d+))");
3656 reg::Iterator it(lstFormat,marker);
3658 size_t index=0;
3659 // now replace all markers with the real text
3660 for ( ; it!=end ; ++it)
3661 {
3662 const auto &match = *it;
3663 size_t newIndex = match.position();
3664 size_t matchLen = match.length();
3665 optionValue += lstFormat.substr(index,newIndex-index);
3666 unsigned long entryIndex = std::stoul(match[1].str());
3667 if (entryIndex<(unsigned long)lst->size())
3668 {
3669 optionValue += lst->at(entryIndex);
3670 }
3671 index=newIndex+matchLen;
3672 }
3673 optionValue+=lstFormat.substr(index);
3674 }
3675 }
3676 break;
3678 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3679 cmdChar,cmdName,parser()->context.token->name);
3680 break;
3682 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3683 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3684 cmdChar,cmdName,parser()->context.token->name);
3685 break;
3687 // nothing to show here
3688 break;
3689 }
3690 if (!optionValue.isEmpty())
3691 {
3692 children().append<DocWord>(parser(),thisVariant(),optionValue);
3693 }
3694 }
3695 else
3696 {
3697 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3698 cmdChar,cmdName,parser()->context.token->name);
3700 }
3702}
3703
3705{
3706 AUTO_TRACE();
3707 Token retval=parser()->tokenizer.lex();
3708 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3710 retval=parser()->tokenizer.lex();
3711 if (retval.is(TokenRetval::RetVal_OK))
3712 {
3716 if (!ref->parse())
3717 {
3718 children().pop_back();
3719 }
3720 }
3722 return retval;
3723}
3724
3725void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3726{
3727 AUTO_TRACE();
3728 QCString fmt;
3729 QCString date;
3730 Token tok=parser()->tokenizer.lex();
3731 if (!tok.is(TokenRetval::TK_WHITESPACE))
3732 {
3733 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3734 cmdChar,cmdName);
3735 return;
3736 }
3738 tok = parser()->tokenizer.lex();
3739 if (!tok.is(TokenRetval::TK_WORD))
3740 {
3741 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3742 cmdChar,cmdName);
3744 return;
3745 }
3746 fmt = parser()->context.token->name;
3747
3749 tok = parser()->tokenizer.lex();
3750
3751 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3752 QCString specDate = specDateRaw.stripWhiteSpace();
3753 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3754 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3755 {
3756 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3757 cmdChar,cmdName);
3759 return;
3760 }
3761
3762 std::tm dat{};
3763 int specFormat=0;
3764 QCString err = dateTimeFromString(specDate,dat,specFormat);
3765 if (!err.isEmpty())
3766 {
3767 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3768 cmdChar,cmdName,err);
3770 return;
3771 }
3772
3773 int usedFormat=0;
3774 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3775
3776 // warn the user if the format contains markers that are not explicitly filled in
3777 for (int i=0;i<SF_NumBits;i++)
3778 {
3779 int bitMask = 1<<i;
3780 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3781 {
3782 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.",
3783 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3784 }
3785 }
3786
3787 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3788 if (specDateOnlyWS) // specDate is only whitespace
3789 {
3791 }
3793}
3794
3795void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3796{
3797 AUTO_TRACE();
3799 Token tok = parser()->tokenizer.lex();
3800 if (!tok.is(TokenRetval::TK_WORD))
3801 {
3802 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
3803 cmdChar,cmdName);
3804 return;
3805 }
3807}
3808
3809void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3810{
3811 AUTO_TRACE();
3812 Token tok=parser()->tokenizer.lex();
3813 if (!tok.is(TokenRetval::TK_WHITESPACE))
3814 {
3815 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3816 cmdChar,cmdName);
3817 return;
3818 }
3820 tok=parser()->tokenizer.lex();
3822 if (!tok.is(TokenRetval::TK_WORD))
3823 {
3824 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3825 tok.to_string(),cmdChar,cmdName);
3826 return;
3827 }
3830}
3831
3832
3834{
3835 AUTO_TRACE("cmdName={}",cmdName);
3836 QCString saveCmdName = cmdName;
3837 Token tok=parser()->tokenizer.lex();
3838 if (!tok.is(TokenRetval::TK_WHITESPACE))
3839 {
3840 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3841 saveCmdName);
3842 return;
3843 }
3845 tok=parser()->tokenizer.lex();
3847 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3848 {
3849 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3850 "argument of command {}", saveCmdName);
3851 return;
3852 }
3853 else if (!tok.is(TokenRetval::TK_WORD))
3854 {
3855 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3856 tok.to_string(),saveCmdName);
3857 return;
3858 }
3859 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3860 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3861 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3862 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3863 //TODO get from context the stripCodeComments()
3864 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3868 stripCodeComments,
3871 );
3873 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3874 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3875 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3876 bool isFirst = !n1 || // no last node
3877 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3878 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3879 op->markFirst(isFirst);
3880 op->markLast(true);
3881 if (n1_docIncOp)
3882 {
3883 n1_docIncOp->markLast(false);
3884 }
3885 else if (n1_docWs && n2_docIncOp)
3886 {
3887 n2_docIncOp->markLast(false);
3888 }
3889 op->parse();
3890}
3891
3892template<class T>
3893void DocPara::handleFile(const QCString &cmdName)
3894{
3895 AUTO_TRACE("cmdName={}",cmdName);
3896 QCString saveCmdName = cmdName;
3897 Token tok=parser()->tokenizer.lex();
3898 if (!tok.is(TokenRetval::TK_WHITESPACE))
3899 {
3900 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3901 saveCmdName);
3902 return;
3903 }
3905 tok=parser()->tokenizer.lex();
3907 if (!tok.is(TokenRetval::TK_WORD))
3908 {
3909 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3910 tok.to_string(),saveCmdName);
3911 return;
3912 }
3913 QCString name = parser()->context.token->name;
3914 children().append<T>(parser(),thisVariant(),name,
3918 auto df = children().get_last<T>();
3919 if (!df->parse())
3920 {
3921 children().pop_back();
3922 }
3923}
3924
3931
3932void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3933{
3934 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3935 QCString saveCmdName = cmdName;
3936 Token tok=parser()->tokenizer.lex();
3937 if (!tok.is(TokenRetval::TK_WHITESPACE))
3938 {
3939 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3940 saveCmdName);
3941 return;
3942 }
3944 tok=parser()->tokenizer.lex();
3945 if (!tok.is(TokenRetval::TK_WORD))
3946 {
3947 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3948 tok.to_string(),saveCmdName);
3949 return;
3950 }
3951 if (saveCmdName == "javalink")
3952 {
3954 parser()->context.nodeStack.size(),
3955 DocStyleChange::Code,cmdName,TRUE);
3956 }
3959 DocLink *lnk = children().get_last<DocLink>();
3960 if (saveCmdName == "javalink")
3961 {
3963 parser()->context.nodeStack.size(),
3964 DocStyleChange::Code,cmdName,FALSE);
3965 }
3966 QCString leftOver = lnk->parse(isJavaLink);
3967 if (!leftOver.isEmpty())
3968 {
3969 children().append<DocWord>(parser(),thisVariant(),leftOver);
3970 }
3971}
3972
3973void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3974{
3975 AUTO_TRACE("cmdName={}",cmdName);
3976 QCString saveCmdName = cmdName;
3977 Token tok=parser()->tokenizer.lex();
3978 if (!tok.is(TokenRetval::TK_WHITESPACE))
3979 {
3980 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3981 cmdChar,qPrint(saveCmdName));
3982 return;
3983 }
3985 tok=parser()->tokenizer.lex(); // get the reference id
3986 if (!tok.is(TokenRetval::TK_WORD))
3987 {
3988 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3989 tok.to_string(),cmdChar,saveCmdName);
3990 goto endref;
3991 }
3995 children().get_last<DocRef>()->parse();
3996endref:
3998}
3999
4001{
4002 AUTO_TRACE("cmdName={}",cmdName);
4003 QCString saveCmdName = cmdName;
4004 Token tok=parser()->tokenizer.lex();
4005 bool isBlock = false;
4006 bool trimLeft = false;
4007 bool localScope = false;
4008 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
4009 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
4010 {
4012 parser()->tokenizer.lex();
4014 StringVector optList=split(parser()->context.token->name.str(),",");
4015 auto contains = [&optList](const char *kw)
4016 {
4017 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
4018 };
4019 localScope = contains("local");
4020 if (contains("nostrip"))
4021 {
4022 stripCodeComments = false;
4023 }
4024 else if (contains("strip"))
4025 {
4026 stripCodeComments = true;
4027 }
4028 if (t==DocInclude::Snippet && contains("trimleft"))
4029 {
4030 trimLeft = true;
4031 }
4032
4033 if (contains("lineno"))
4034 {
4038 }
4039 tok=parser()->tokenizer.lex();
4040 if (!tok.is(TokenRetval::TK_WHITESPACE))
4041 {
4042 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4043 saveCmdName);
4044 return;
4045 }
4046 }
4047 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
4048 {
4050 parser()->tokenizer.lex();
4051 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
4053 parser()->tokenizer.lex();
4054 }
4055 else if (!tok.is(TokenRetval::TK_WHITESPACE))
4056 {
4057 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4058 saveCmdName);
4059 return;
4060 }
4062 tok=parser()->tokenizer.lex();
4064 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4065 {
4066 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4067 "argument of command {}",saveCmdName);
4068 return;
4069 }
4070 else if (!tok.is(TokenRetval::TK_WORD))
4071 {
4072 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
4073 tok.to_string(),saveCmdName);
4074 return;
4075 }
4076 QCString fileName = parser()->context.token->name;
4077 QCString blockId;
4079 {
4080 if (fileName == "this") fileName=parser()->context.fileName;
4082 tok=parser()->tokenizer.lex();
4084 if (!tok.is(TokenRetval::TK_WORD))
4085 {
4086 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
4087 tok.to_string(),saveCmdName);
4088 return;
4089 }
4090 blockId = "["+parser()->context.token->name+"]";
4091 }
4092
4094 thisVariant(),
4095 fileName,
4096 localScope ? parser()->context.context : "",
4097 t,
4098 stripCodeComments,
4101 blockId,isBlock,trimLeft);
4103}
4104
4105void DocPara::handleSection(char cmdChar,const QCString &cmdName)
4106{
4107 AUTO_TRACE("cmdName={}",cmdName);
4108 QCString saveCmdName = cmdName;
4109 // get the argument of the section command.
4110 Token tok=parser()->tokenizer.lex();
4111 if (!tok.is(TokenRetval::TK_WHITESPACE))
4112 {
4113 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
4114 cmdChar,saveCmdName);
4115 return;
4116 }
4117 tok=parser()->tokenizer.lex();
4118 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4119 {
4120 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4121 "argument of command '{:c}{}'", cmdChar,saveCmdName);
4122 return;
4123 }
4124 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
4125 {
4126 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
4127 tok.to_string(),cmdChar,saveCmdName);
4128 return;
4129 }
4132 parser()->tokenizer.lex();
4134}
4135
4136Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
4137{
4138 AUTO_TRACE();
4139 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
4140 Token retval = children().get_last<DocHtmlHeader>()->parse();
4141 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
4142}
4143
4144// For XML tags whose content is stored in attributes rather than
4145// contained within the element, we need a way to inject the attribute
4146// text into the current paragraph.
4147bool DocPara::injectToken(Token tok,const QCString &tokText)
4148{
4149 AUTO_TRACE();
4150 parser()->context.token->name = tokText;
4151 return parser()->defaultHandleToken(thisVariant(),tok,children());
4152}
4153
4155{
4156 AUTO_TRACE();
4157 Token retval = parser()->tokenizer.lex();
4158 QCString lang = parser()->context.token->name;
4159 if (!lang.isEmpty() && lang.at(0)!='.')
4160 {
4161 lang="."+lang;
4162 }
4163 if (parser()->context.xmlComment)
4164 {
4165 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
4166 }
4167 // search for the first non-whitespace line, index is stored in li
4168 size_t i=0,li=0,l=parser()->context.token->verb.length();
4169 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
4170 {
4171 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
4172 i++;
4173 }
4176 stripIndentation(parser()->context.token->verb.mid(li)),
4180 FALSE,lang);
4181 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4182 {
4183 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
4184 }
4186 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4187 return retval;
4188}
4189
4191{
4192 if (parser()->context.memberDef) // inheriting docs from a member
4193 {
4194 const MemberDef *reMd = parser()->context.memberDef->reimplements();
4195 if (reMd) // member from which was inherited.
4196 {
4197 const MemberDef *thisMd = parser()->context.memberDef;
4198 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
4199 parser()->pushContext();
4200 parser()->context.scope=reMd->getOuterScope();
4201 if (parser()->context.scope!=Doxygen::globalScope)
4202 {
4204 }
4205 parser()->context.memberDef=reMd;
4206 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
4207 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
4208 parser()->context.copyStack.push_back(reMd);
4211 parser()->context.copyStack.pop_back();
4212 auto hasParamCommand = parser()->context.hasParamCommand;
4213 auto hasReturnCommand = parser()->context.hasReturnCommand;
4214 auto retvalsFound = parser()->context.retvalsFound;
4215 auto paramsFound = parser()->context.paramsFound;
4216 parser()->popContext();
4217 parser()->context.hasParamCommand = hasParamCommand;
4218 parser()->context.hasReturnCommand = hasReturnCommand;
4219 parser()->context.retvalsFound = retvalsFound;
4220 parser()->context.paramsFound = paramsFound;
4221 parser()->context.memberDef = thisMd;
4222 }
4223 }
4224}
4225
4226
4227Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
4228{
4229 AUTO_TRACE("cmdName={}",cmdName);
4230 Token retval = Token::make_RetVal_OK();
4231 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
4232 switch (cmdId)
4233 {
4235 {
4236 std::string str{cmdChar};
4237 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
4238 if (isAliasCmd(cmdName.view()))
4239 {
4240 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
4241 }
4242 else
4243 {
4244 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
4245 }
4246 }
4247 break;
4250 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4252 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4253 break;
4256 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4258 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4259 break;
4262 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4264 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4265 break;
4268 break;
4271 break;
4274 break;
4277 break;
4280 break;
4283 break;
4286 break;
4289 break;
4292 break;
4295 break;
4299 break;
4304 break;
4307 break;
4310 break;
4313 break;
4316 break;
4319 break;
4322 break;
4325 break;
4330 break;
4334 break;
4337 break;
4340 break;
4343 break;
4346 break;
4349 break;
4352 break;
4355 break;
4358 break;
4361 break;
4364 break;
4367 break;
4370 break;
4373 break;
4376 break;
4379 break;
4381 {
4383 retval = children().get_last<DocSimpleList>()->parse();
4384 }
4385 break;
4387 {
4388 handleSection(cmdChar,cmdName);
4389 retval = Token::make_RetVal_Section();
4390 }
4391 break;
4393 {
4394 handleSection(cmdChar,cmdName);
4395 retval = Token::make_RetVal_Subsection();
4396 }
4397 break;
4399 {
4400 handleSection(cmdChar,cmdName);
4401 retval = Token::make_RetVal_Subsubsection();
4402 }
4403 break;
4405 {
4406 handleSection(cmdChar,cmdName);
4407 retval = Token::make_RetVal_Paragraph();
4408 }
4409 break;
4411 {
4412 handleSection(cmdChar,cmdName);
4413 retval = Token::make_RetVal_SubParagraph();
4414 }
4415 break;
4417 {
4418 handleSection(cmdChar,cmdName);
4419 retval = Token::make_RetVal_SubSubParagraph();
4420 }
4421 break;
4423 {
4425 retval = handleStartCode();
4426 }
4427 break;
4429 {
4431 retval = handleStartCode();
4432 }
4433 break;
4435 {
4437 retval = parser()->tokenizer.lex();
4439 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4440 {
4441 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4442 }
4444 }
4445 break;
4447 {
4449 retval = parser()->tokenizer.lex();
4451 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4452 {
4453 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4454 }
4456 }
4457 break;
4459 {
4461 retval = parser()->tokenizer.lex();
4463 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4464 {
4465 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4466 }
4468 }
4469 break;
4471 {
4473 retval = parser()->tokenizer.lex();
4475 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4476 {
4477 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4478 }
4480 }
4481 break;
4483 {
4485 retval = parser()->tokenizer.lex();
4487 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4488 {
4489 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4490 }
4492 }
4493 break;
4495 {
4497 retval = parser()->tokenizer.lex();
4499 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4500 {
4501 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4502 }
4504 }
4505 break;
4507 {
4510 parser()->tokenizer.lex();
4511
4512 QCString fullMatch = parser()->context.token->verb;
4513 int idx = fullMatch.find('{');
4514 int idxEnd = fullMatch.find("}",idx+1);
4515 StringVector optList;
4516 if (idx != -1) // options present
4517 {
4518 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4519 optList = split(optStr.str(),",");
4520 for (const auto &opt : optList)
4521 {
4522 if (opt.empty()) continue;
4523 QCString locOpt(opt);
4524 locOpt = locOpt.stripWhiteSpace().lower();
4525 if (locOpt == "code")
4526 {
4528 }
4529 else if (!locOpt.isEmpty())
4530 {
4531 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4532 }
4533 }
4534 }
4535
4537 retval = parser()->tokenizer.lex();
4539 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4540 {
4541 if (t == DocVerbatim::JavaDocCode)
4542 {
4543 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4544 }
4545 else
4546 {
4547 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4548 }
4549 }
4551 }
4552 break;
4555 {
4556 if (cmdId == CommandType::CMD_VERBATIM)
4557 {
4559 }
4560 else
4561 {
4563 }
4564 retval = parser()->tokenizer.lex();
4566 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4567 {
4568 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4569 }
4571 }
4572 break;
4574 {
4583 QCString width,height;
4584 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4586 retval = parser()->tokenizer.lex();
4587 dv->setText(parser()->context.token->verb);
4588 dv->setWidth(width);
4589 dv->setHeight(height);
4590 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4591 if (!Config_getBool(HAVE_DOT))
4592 {
4593 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4594 children().pop_back();
4595 }
4596 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4597 {
4598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4599 }
4601 }
4602 break;
4604 {
4613 QCString width,height;
4614 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4616 retval = parser()->tokenizer.lex();
4617 dv->setText(parser()->context.token->verb);
4618 dv->setWidth(width);
4619 dv->setHeight(height);
4620 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4621 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4622 {
4623 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4624 }
4626 }
4627 break;
4629 {
4630 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4632 parser()->tokenizer.lex();
4633 QCString fullMatch = parser()->context.token->sectionId;
4634 QCString sectionId = "";
4635 int idx = fullMatch.find('{');
4636 int idxEnd = fullMatch.find("}",idx+1);
4637 StringVector optList;
4638 QCString engine;
4639 if (idx != -1) // options present
4640 {
4641 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4642 optList = split(optStr.str(),",");
4643 for (const auto &opt : optList)
4644 {
4645 if (opt.empty()) continue;
4646 bool found = false;
4647 QCString locOpt(opt);
4648 locOpt = locOpt.stripWhiteSpace().lower();
4649 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4650 {
4651 if (!engine.isEmpty())
4652 {
4653 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4654 }
4655 engine = locOpt;
4656 found = true;
4657 }
4658 if (!found)
4659 {
4660 if (sectionId.isEmpty())
4661 {
4662 sectionId = opt;
4663 }
4664 else
4665 {
4666 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4667 }
4668 }
4669 }
4670 }
4671 else
4672 {
4673 sectionId = parser()->context.token->sectionId;
4674 }
4675 if (engine.isEmpty()) engine = "uml";
4676
4677 if (sectionId.isEmpty())
4678 {
4680 retval = parser()->tokenizer.lex();
4681 assert(retval.is(TokenRetval::RetVal_OK));
4682
4683 sectionId = parser()->context.token->sectionId;
4684 sectionId = sectionId.stripWhiteSpace();
4685 }
4686
4687 QCString plantFile(sectionId);
4692 FALSE,plantFile);
4694 dv->setEngine(engine);
4696 QCString width,height;
4697 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4699 retval = parser()->tokenizer.lex();
4700 int line = 0;
4701 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4702 if (engine == "ditaa")
4703 {
4704 dv->setUseBitmap(true);
4705 }
4706 else if (engine == "uml")
4707 {
4708 int i = trimmedVerb.find('\n');
4709 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4710 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4711 }
4712 dv->setText(trimmedVerb);
4713 dv->setWidth(width);
4714 dv->setHeight(height);
4715 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4716 if (jarPath.isEmpty())
4717 {
4718 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4719 children().pop_back();
4720 }
4721 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4722 {
4723 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4724 }
4726 }
4727 break;
4729 retval = Token::make_RetVal_EndParBlock();
4730 break;
4746 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4747 break;
4749 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4750 break;
4752 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4753 break;
4755 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4756 break;
4759 break;
4761 retval = handleXRefItem();
4762 break;
4764 {
4766 }
4767 break;
4770 {
4772 }
4773 break;
4775 {
4777 }
4778 break;
4780 {
4784 retval = children().get_last<DocIndexEntry>()->parse();
4785 }
4786 break;
4788 retval = Token::make_RetVal_Internal();
4789 break;
4791 retval = Token::make_RetVal_EndInternal();
4792 break;
4794 {
4796 retval = children().get_last<DocParBlock>()->parse();
4797 }
4798 break;
4799 case CommandType::CMD_COPYDOC: // fall through
4800 case CommandType::CMD_COPYBRIEF: // fall through
4802 //retval = Token::make_RetVal_CopyDoc();
4803 // these commands should already be resolved by processCopyDoc()
4804 break;
4807 break;
4810 break;
4813 break;
4816 break;
4819 break;
4822 break;
4825 break;
4828 break;
4831 break;
4834 break;
4837 break;
4840 break;
4843 break;
4846 break;
4849 break;
4852 break;
4855 break;
4857 if (!Config_getBool(HAVE_DOT))
4858 {
4859 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4860 "ignoring \\dotfile command because HAVE_DOT is not set");
4861 }
4862 else
4863 {
4864 handleFile<DocDotFile>(cmdName);
4865 }
4866 break;
4869 break;
4871 handleFile<DocMscFile>(cmdName);
4872 break;
4874 handleFile<DocDiaFile>(cmdName);
4875 break;
4878 break;
4880 handleLink(cmdName,FALSE);
4881 break;
4883 handleLink(cmdName,TRUE);
4884 break;
4886 handleCite(cmdChar,cmdName);
4887 break;
4889 handleEmoji(cmdChar,cmdName);
4890 break;
4892 handleDoxyConfig(cmdChar,cmdName);
4893 break;
4894 case CommandType::CMD_REF: // fall through
4896 handleRef(cmdChar,cmdName);
4897 break;
4899 {
4902 }
4903 break;
4905 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4906 break;
4908 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4909 break;
4911 {
4913 }
4914 break;
4915 //case CommandType::CMD_LANGSWITCH:
4916 // retval = handleLanguageSwitch();
4917 // break;
4919 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4920 {
4923 }
4924 break;
4927 break;
4929 handleShowDate(cmdChar,cmdName);
4930 break;
4932 handleILine(cmdChar,cmdName);
4933 break;
4935 handleIFile(cmdChar,cmdName);
4936 break;
4938 {
4940 (void)parser()->tokenizer.lex();
4942 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4944 }
4945 break;
4946 default:
4947 // we should not get here!
4948 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4949 break;
4950 }
4951 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4952 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4953 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4954 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4955 TokenRetval::RetVal_EndInternal)
4956 );
4957 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4958 return retval;
4959}
4960
4961static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4962 const char *attrName,
4963 QCString *result)
4964{
4965
4966 for (const auto &opt : tagHtmlAttribs)
4967 {
4968 if (opt.name==attrName)
4969 {
4970 *result = opt.value;
4971 return TRUE;
4972 }
4973 }
4974 return FALSE;
4975}
4976
4977Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4978{
4979 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4980 Token retval = Token::make_RetVal_OK();
4981 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4982 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4985 {
4986 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4987 tagName);
4988 }
4989 switch (tagId)
4990 {
4992 if (!parser()->context.token->emptyTag)
4993 {
4995 tagHtmlAttribs,DocHtmlList::Unordered);
4996 retval=children().get_last<DocHtmlList>()->parse();
4997 }
4998 break;
5000 if (!parser()->context.token->emptyTag)
5001 {
5003 tagHtmlAttribs,DocHtmlList::Ordered);
5004 retval=children().get_last<DocHtmlList>()->parse();
5005 }
5006 break;
5008 if (parser()->context.token->emptyTag) break;
5010 {
5011 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
5012 }
5013 else
5014 {
5015 retval = Token::make_RetVal_ListItem();
5016 }
5017 break;
5019 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
5020 break;
5022 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
5023 break;
5025 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
5026 break;
5028 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
5029 break;
5031 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
5032 break;
5034 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
5035 break;
5037 if (parser()->context.token->emptyTag) break;
5038 if (parser()->context.xmlComment)
5039 // for C# source or inside a <summary> or <remark> section we
5040 // treat <code> as an XML tag (so similar to @code)
5041 {
5043 retval = handleStartCode();
5044 }
5045 else // normal HTML markup
5046 {
5047 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5048 }
5049 break;
5051 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
5052 break;
5054 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Typewriter,tagName,&parser()->context.token->attribs);
5055 break;
5057 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
5058 break;
5060 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
5061 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
5062 break;
5064 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
5065 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
5066 break;
5068 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
5069 break;
5071 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
5072 break;
5074 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
5075 break;
5077 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
5078 break;
5080 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
5081 break;
5083 if (parser()->context.token->emptyTag) break;
5084 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
5087 break;
5089 retval = Token::make_TK_NEWPARA();
5090 break;
5092 if (!parser()->context.token->emptyTag)
5093 {
5094 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
5095 retval=children().get_last<DocHtmlDescList>()->parse();
5096 }
5097 break;
5099 if (insideDL(thisVariant()))
5100 {
5101 retval = Token::make_RetVal_DescTitle();
5102 }
5103 else
5104 {
5105 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
5106 }
5107 break;
5109 if (insideDL(thisVariant()))
5110 {
5111 retval = Token::make_RetVal_DescData();
5112 }
5113 else
5114 {
5115 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
5116 }
5117 break;
5119 if (!parser()->context.token->emptyTag)
5120 {
5121 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
5122 retval=children().get_last<DocHtmlTable>()->parse();
5123 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5124 }
5125 break;
5127 retval = Token::make_RetVal_TableRow();
5128 break;
5130 retval = Token::make_RetVal_TableCell();
5131 break;
5133 retval = Token::make_RetVal_TableHCell();
5134 break;
5138 // for time being ignore </t....> tag
5139 break;
5141 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
5142 break;
5144 {
5145 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
5146 }
5147 break;
5149 {
5150 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
5151 }
5152 break;
5154 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
5155 break;
5157 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
5158 break;
5160 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
5161 break;
5163 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
5164 break;
5166 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
5167 break;
5169 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
5170 break;
5172 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
5173 break;
5175 {
5176 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
5177 }
5178 break;
5180 if (!parser()->context.token->emptyTag)
5181 {
5182 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
5183 retval=children().get_last<DocHtmlDetails>()->parse();
5184 }
5185 break;
5187 if (!parser()->context.token->emptyTag)
5188 {
5189 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
5190 retval = children().get_last<DocHtmlBlockQuote>()->parse();
5191 }
5192 break;
5193
5196 {
5197 if (!parser()->context.token->emptyTag)
5198 {
5200 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
5201 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
5202 if (d)
5203 {
5204 if (!d->summary()) // details section does not have a summary yet
5205 {
5206 d->parseSummary(n,parser()->context.token->attribs);
5207 }
5208 else
5209 {
5210 retval = Token::make_TK_NEWPARA();
5211 }
5212 }
5213 }
5214 }
5215 break;
5219 // fall through
5222 if (!children().empty())
5223 {
5224 retval = Token::make_TK_NEWPARA();
5225 }
5226 break;
5228 if (insideTable(thisVariant()))
5229 {
5230 retval = Token::make_RetVal_TableCell();
5231 }
5232 break;
5233 case HtmlTagType::XML_C:
5234 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5235 break;
5238 {
5240 QCString paramName;
5241 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5242 {
5243 if (paramName.isEmpty())
5244 {
5245 if (Config_getBool(WARN_NO_PARAMDOC))
5246 {
5247 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5248 }
5249 }
5250 else
5251 {
5252 retval = handleParamSection(paramName,
5254 TRUE);
5255 }
5256 }
5257 else
5258 {
5259 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5260 }
5261 }
5262 break;
5265 {
5266 QCString paramName;
5267 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5268 {
5269 //printf("paramName=%s\n",qPrint(paramName));
5271 children().append<DocWord>(parser(),thisVariant(),paramName);
5273 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5274 }
5275 else
5276 {
5277 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5278 }
5279 }
5280 break;
5282 {
5284 QCString exceptName;
5285 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5286 {
5287 unescapeCRef(exceptName);
5288 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5289 }
5290 else
5291 {
5292 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5293 }
5294 }
5295 break;
5298 if (insideTable(thisVariant()))
5299 {
5300 retval = Token::make_RetVal_TableRow();
5301 }
5302 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5303 {
5304 retval = Token::make_RetVal_ListItem();
5305 }
5306 else
5307 {
5308 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5309 }
5310 break;
5315 break;
5317 if (insideTable(thisVariant()))
5318 {
5319 retval = Token::make_RetVal_TableCell();
5320 }
5321 break;
5323 // I'm not sure if <see> is the same as <seealso> or if it
5324 // should you link a member without producing a section. The
5325 // C# specification is extremely vague about this (but what else
5326 // can we expect from Microsoft...)
5327 {
5328 QCString cref;
5329 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5330 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5331 {
5332 unescapeCRef(cref);
5333 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5334 {
5335 bool inSeeBlock = parser()->context.inSeeBlock;
5336 parser()->context.token->name = cref;
5339 parser()->context.inSeeBlock = inSeeBlock;
5340 }
5341 else // <see cref="...">...</see> style
5342 {
5343 //DocRef *ref = new DocRef(this,cref);
5344 //children().append(ref);
5345 //ref->parse();
5348 DocLink *lnk = children().get_last<DocLink>();
5349 QCString leftOver = lnk->parse(FALSE,TRUE);
5350 if (!leftOver.isEmpty())
5351 {
5352 children().append<DocWord>(parser(),thisVariant(),leftOver);
5353 }
5354 }
5355 }
5356 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5357 {
5358 bool inSeeBlock = parser()->context.inSeeBlock;
5359 parser()->context.token->name = cref;
5364 parser()->context.inSeeBlock = inSeeBlock;
5365 }
5366 else
5367 {
5368 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5369 }
5370 }
5371 break;
5373 {
5375 QCString cref;
5376 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5377 {
5378 unescapeCRef(cref);
5379 // Look for an existing "see" section
5380 DocNodeVariant *vss=nullptr;
5381 for (auto &n : children())
5382 {
5383 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5384 if (candidate && candidate->type()==DocSimpleSect::See)
5385 {
5386 vss = &n;
5387 }
5388 }
5389
5390 if (!vss) // start new section
5391 {
5393 vss = &children().back();
5394 }
5395
5396 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5397 retval = Token::make_RetVal_OK();
5398 }
5399 else
5400 {
5401 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5402 }
5403 }
5404 break;
5406 {
5407 QCString type;
5408 findAttribute(tagHtmlAttribs,"type",&type);
5410 HtmlAttribList emptyList;
5411 if (type=="number")
5412 {
5413 listType=DocHtmlList::Ordered;
5414 }
5415 if (type=="table")
5416 {
5417 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5418 retval=children().get_last<DocHtmlTable>()->parseXml();
5419 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5420 }
5421 else
5422 {
5423 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5424 retval=children().get_last<DocHtmlList>()->parseXml();
5425 }
5426 }
5427 break;
5430 // These tags are defined in .Net but are currently unsupported
5432 break;
5434 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5435 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5436 break;
5439 break;
5440 default:
5441 // we should not get here!
5442 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5443 ASSERT(0);
5444 break;
5445 }
5446 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5447 return retval;
5448}
5449
5451{
5452 AUTO_TRACE("tagName={}",tagName);
5453 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5454 Token retval = Token::make_RetVal_OK();
5455 switch (tagId)
5456 {
5458 if (!insideUL(thisVariant()))
5459 {
5460 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5461 }
5462 else
5463 {
5464 retval = Token::make_RetVal_EndList();
5465 }
5466 break;
5468 if (!insideOL(thisVariant()))
5469 {
5470 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5471 }
5472 else
5473 {
5474 retval = Token::make_RetVal_EndList();
5475 }
5476 break;
5478 if (!insideLI(thisVariant()))
5479 {
5480 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5481 }
5482 else
5483 {
5484 // ignore </li> tags
5485 }
5486 break;
5488 if (!insideDetails(thisVariant()))
5489 {
5490 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5491 }
5492 else
5493 {
5494 retval = Token::make_RetVal_EndHtmlDetails();
5495 }
5496 break;
5499 {
5500 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5501 }
5502 else
5503 {
5504 retval = Token::make_RetVal_EndBlockQuote();
5505 }
5506 break;
5509 break;
5512 break;
5515 break;
5518 break;
5521 break;
5524 break;
5527 break;
5530 break;
5533 break;
5536 break;
5539 break;
5542 break;
5545 break;
5548 break;
5551 break;
5554 break;
5557 break;
5562 break;
5564 retval = Token::make_TK_NEWPARA();
5565 break;
5567 retval = Token::make_RetVal_EndDesc();
5568 break;
5570 // ignore </dt> tag
5571 break;
5573 // ignore </dd> tag
5574 break;
5576 retval = Token::make_RetVal_EndTable();
5577 break;
5579 retval = Token::make_RetVal_EndTableRow();
5580 break;
5582 retval = Token::make_RetVal_EndTableCell();
5583 break;
5585 retval = Token::make_RetVal_EndTableCell();
5586 break;
5590 // for time being ignore </t....> tag
5591 break;
5593 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5594 break;
5596 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5597 break;
5599 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5600 break;
5602 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5603 break;
5605 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5606 break;
5608 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5609 break;
5611 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5612 break;
5614 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5615 break;
5617 break;
5619 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5620 break;
5622 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5623 // ignore </a> tag (can be part of <a name=...></a>
5624 break;
5625
5627 break;
5629 retval = Token::make_TK_NEWPARA();
5630 break;
5643 retval = Token::make_RetVal_CloseXml();
5644 break;
5645 case HtmlTagType::XML_C:
5647 break;
5655 // These tags are defined in .Net but are currently unsupported
5656 break;
5658 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5659 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5660 break;
5661 default:
5662 // we should not get here!
5663 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5664 ASSERT(0);
5665 break;
5666 }
5667 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5668 return retval;
5669}
5670
5672{
5673 // expected hierarchy:
5674 // 1. DocAutoListItem <- n
5675 // 2. DocAutoList <- parent(n)
5676 // 3. DocPara <- parent(parent(n))
5677
5678 // step 1
5679 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5680 {
5681 return false;
5682 }
5683
5684 // step 2
5685 n = parent(n);
5686 int indent = 0;
5687 const auto docAutoList = std::get_if<DocAutoList>(n);
5688 if (docAutoList) // capture indent
5689 {
5690 indent = docAutoList->indent();
5691 }
5692 else
5693 {
5694 return false;
5695 }
5696
5697 // step 3
5698 n = parent(n);
5699 const auto docPara = std::get_if<DocPara>(n);
5700 if (docPara)
5701 {
5702 QCString tagNameLower = QCString(parser->context.token->name).lower();
5703 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5704 {
5705 return std::get<DocStyleChange>(*stack.top());
5706 };
5707
5708 if (parser->context.styleStack.empty() || // no style change
5709 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5710 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5711 )
5712 {
5713 // insert an artificial 'end of autolist' marker and parse again
5714 QCString indentStr;
5715 indentStr.fill(' ',indent);
5716 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5717 return true;
5718 }
5719 }
5720 return false;
5721}
5722
5724{
5725 AUTO_TRACE();
5726 auto ns = AutoNodeStack(parser(),thisVariant());
5727 // handle style commands "inherited" from the previous paragraph
5729 Token tok=parser()->tokenizer.lex();
5730 Token retval = Token::make_TK_NONE();
5731 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5732 {
5733reparsetoken:
5734 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5735 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5736 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5737 )
5738 {
5739 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5740 }
5741 switch(tok.value())
5742 {
5743 case TokenRetval::TK_WORD:
5745 break;
5746 case TokenRetval::TK_LNKWORD:
5748 break;
5749 case TokenRetval::TK_URL:
5751 break;
5752 case TokenRetval::TK_WHITESPACE:
5753 {
5754 // prevent leading whitespace and collapse multiple whitespace areas
5755 if (insidePRE(thisVariant()) || // all whitespace is relevant
5756 (
5757 // remove leading whitespace
5758 !children().empty() &&
5759 // and whitespace after certain constructs
5763 )
5764 )
5765 {
5767 }
5768 }
5769 break;
5770 case TokenRetval::TK_LISTITEM:
5771 {
5772 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5773 const DocNodeVariant *n=parent();
5774 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5775 const DocAutoList *al = std::get_if<DocAutoList>(n);
5776 if (al) // we found an auto list up in the hierarchy
5777 {
5778 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5779 if (al->indent()>=parser()->context.token->indent)
5780 // new item at the same or lower indent level
5781 {
5782 retval = Token::make_TK_LISTITEM();
5783 goto endparagraph;
5784 }
5785 }
5786
5787 // determine list depth
5788 int depth = 0;
5789 n=parent();
5790 while (n)
5791 {
5792 al = std::get_if<DocAutoList>(n);
5793 if (al && al->isEnumList()) depth++;
5794 n=::parent(n);
5795 }
5796
5797 // first item or sub list => create new list
5798 do
5799 {
5802 parser()->context.token->isEnumList,depth,
5804 al = children().get_last<DocAutoList>();
5805 retval = children().get_last<DocAutoList>()->parse();
5806 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5807 al->indent()==parser()->context.token->indent // at same indent level
5808 );
5809
5810 // check the return value
5811 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5812 {
5813 // Reparse the token that ended the section at this level,
5814 // so a new simple section will be started at this level.
5815 // This is the same as unputting the last read token and continuing.
5817 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5818 {
5821 tok = Token::make_TK_RCSTAG();
5822 }
5823 else // other section
5824 {
5825 tok = Token::make_TK_COMMAND_BS();
5826 }
5827 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5828 goto reparsetoken;
5829 }
5830 else if (retval.is(TokenRetval::TK_ENDLIST))
5831 {
5832 if (al->indent()>parser()->context.token->indent) // end list
5833 {
5834 goto endparagraph;
5835 }
5836 else // continue with current paragraph
5837 {
5838 }
5839 }
5840 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5841 {
5842 goto endparagraph;
5843 }
5844 }
5845 break;
5846 case TokenRetval::TK_ENDLIST:
5847 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5848 if (std::get_if<DocAutoListItem>(parent()))
5849 {
5850 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5851 if (al && al->indent()>=parser()->context.token->indent)
5852 {
5853 // end of list marker ends this paragraph
5854 retval = Token::make_TK_ENDLIST();
5855 goto endparagraph;
5856 }
5857 else
5858 {
5859 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5860 "has invalid indent level");
5861 }
5862 }
5863 else
5864 {
5865 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5866 "list items");
5867 }
5868 break;
5869 case TokenRetval::TK_COMMAND_AT:
5870 // fall through
5871 case TokenRetval::TK_COMMAND_BS:
5872 {
5873 // see if we have to start a simple section
5874 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5875 const DocNodeVariant *n=parent();
5876 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5877 !std::holds_alternative<DocParamSect>(*n))
5878 {
5879 n=::parent(n);
5880 }
5882 {
5883 if (n) // already in a simple section
5884 {
5885 // simple section cannot start in this paragraph, need
5886 // to unwind the stack and remember the command.
5888 retval = Token::make_RetVal_SimpleSec();
5889 goto endparagraph;
5890 }
5891 }
5892 // see if we are in a simple list
5893 n=parent();
5894 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5895 if (n)
5896 {
5897 if (cmd==CommandType::CMD_LI)
5898 {
5899 retval = Token::make_RetVal_ListItem();
5900 goto endparagraph;
5901 }
5902 }
5903
5904 // handle the command
5905 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5906 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5907
5908 // check the return value
5909 if (retval.is(TokenRetval::RetVal_SimpleSec))
5910 {
5911 // Reparse the token that ended the section at this level,
5912 // so a new simple section will be started at this level.
5913 // This is the same as unputting the last read token and continuing.
5915 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5916 {
5919 tok = Token::make_TK_RCSTAG();
5920 }
5921 else // other section
5922 {
5923 tok = Token::make_TK_COMMAND_BS();
5924 }
5925 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5926 goto reparsetoken;
5927 }
5928 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5929 {
5930 // the command ended with a new command, reparse this token
5931 tok = retval;
5932 goto reparsetoken;
5933 }
5934 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5935 // or some auto list marker
5936 {
5937 goto endparagraph;
5938 }
5939 }
5940 break;
5941 case TokenRetval::TK_HTMLTAG:
5942 {
5943 if (!parser()->context.token->endTag) // found a start tag
5944 {
5945 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5946 }
5947 else // found an end tag
5948 {
5950 {
5951 break; // new code has been pushed back to the scanner, need to reparse
5952 }
5953 retval = handleHtmlEndTag(parser()->context.token->name);
5954 }
5955 if (!retval.is(TokenRetval::RetVal_OK))
5956 {
5957 goto endparagraph;
5958 }
5959 }
5960 break;
5961 case TokenRetval::TK_SYMBOL:
5962 {
5963 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5965 {
5967 }
5968 else
5969 {
5971 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5972 parser()->context.token->name);
5973 }
5974 break;
5975 }
5976 case TokenRetval::TK_NEWPARA:
5977 retval = Token::make_TK_NEWPARA();
5978 goto endparagraph;
5979 case TokenRetval::TK_RCSTAG:
5980 {
5981 const DocNodeVariant *n=parent();
5982 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5983 !std::holds_alternative<DocParamSect>(*n))
5984 {
5985 n=::parent(n);
5986 }
5987 if (n) // already in a simple section
5988 {
5989 // simple section cannot start in this paragraph, need
5990 // to unwind the stack and remember the command.
5993 retval = Token::make_RetVal_SimpleSec();
5994 goto endparagraph;
5995 }
5996
5997 // see if we are in a simple list
5999 children().get_last<DocSimpleSect>()->parseRcs();
6000 }
6001 break;
6002 default:
6003 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6004 "Found unexpected token (id={})",tok.to_string());
6005 break;
6006 }
6007 tok=parser()->tokenizer.lex();
6008 }
6009 retval=Token::make_TK_NONE();
6010endparagraph:
6012 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
6013 if (!parser()->context.token->endTag && par &&
6014 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
6015 {
6016 par->setAttribs(parser()->context.token->attribs);
6017 }
6018 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
6019 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
6020 );
6021
6022 AUTO_TRACE_EXIT("retval={}",retval.to_string());
6023 return retval;
6024}
6025
6026//--------------------------------------------------------------------------
6027
6029{
6030 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
6031 Token retval = Token::make_RetVal_OK();
6032 auto ns = AutoNodeStack(parser(),thisVariant());
6033
6034 if (!m_id.isEmpty())
6035 {
6037 if (sec)
6038 {
6039 m_file = sec->fileName();
6040 m_anchor = sec->label();
6041 QCString titleStr = sec->title();
6042 if (titleStr.isEmpty()) titleStr = sec->label();
6044 DocTitle *title = &std::get<DocTitle>(*m_title);
6045 title->parseFromString(thisVariant(),titleStr);
6046 }
6047 }
6048
6049 // first parse any number of paragraphs
6050 bool isFirst=TRUE;
6051 DocPara *lastPar=nullptr;
6052 do
6053 {
6055 DocPara *par = children().get_last<DocPara>();
6056 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6057 retval=par->parse();
6058 if (!par->isEmpty())
6059 {
6060 if (lastPar) lastPar->markLast(FALSE);
6061 lastPar = par;
6062 }
6063 else
6064 {
6065 children().pop_back();
6066 }
6067 if (retval.is(TokenRetval::TK_LISTITEM))
6068 {
6069 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6070 }
6071 if (retval.is(TokenRetval::RetVal_Internal))
6072 {
6074 retval = children().get_last<DocInternal>()->parse(m_level+1);
6075 if (retval.is(TokenRetval::RetVal_EndInternal))
6076 {
6077 retval = Token::make_RetVal_OK();
6078 }
6079 }
6080 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6081 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
6082 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
6083 );
6084
6085 if (lastPar) lastPar->markLast();
6086
6087 while (true)
6088 {
6089 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
6090 {
6091 // then parse any number of nested sections
6092 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
6093 {
6095 2,
6097 retval = children().get_last<DocSection>()->parse();
6098 }
6099 break;
6100 }
6101 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
6102 {
6103 if ((m_level <= 1) &&
6104 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6105 {
6106 warn_doc_error(parser()->context.fileName,
6107 parser()->tokenizer.getLineNr(),
6108 "Unexpected subsubsection command found inside {}!",
6110 }
6111 // then parse any number of nested sections
6112 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
6113 {
6115 3,
6117 retval = children().get_last<DocSection>()->parse();
6118 }
6119 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
6120 }
6121 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
6122 {
6123 if ((m_level <= 2) &&
6124 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6125 {
6126 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6127 "Unexpected paragraph command found inside {}!",
6129 }
6130 // then parse any number of nested sections
6131 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
6132 {
6134 4,
6136 retval = children().get_last<DocSection>()->parse();
6137 }
6138 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
6139 }
6140 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
6141 {
6142 if ((m_level <= 3) &&
6143 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6144 {
6145 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6146 "Unexpected subparagraph command found inside {}!",
6148 }
6149 // then parse any number of nested sections
6150 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
6151 {
6153 5,
6155 retval = children().get_last<DocSection>()->parse();
6156 }
6157 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
6158 }
6159 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
6160 {
6161 if ((m_level <= 4) &&
6162 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6163 {
6164 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6165 "Unexpected subsubparagraph command found inside {}!",
6167 }
6168 // then parse any number of nested sections
6169 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
6170 {
6172 6,
6174 retval = children().get_last<DocSection>()->parse();
6175 }
6176 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
6177 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
6178 }
6179 else
6180 {
6181 break;
6182 }
6183 }
6184
6185 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
6186 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6187 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
6188 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
6189 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
6190 );
6191
6192 AUTO_TRACE_EXIT("retval={}", retval.to_string());
6193 return retval;
6194}
6195
6196//--------------------------------------------------------------------------
6197
6199{
6200 AUTO_TRACE();
6201 auto ns = AutoNodeStack(parser(),thisVariant());
6203
6204 Token tok = parser()->tokenizer.lex();
6205 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
6206 {
6207 switch(tok.value())
6208 {
6209 case TokenRetval::TK_WORD:
6211 break;
6212 case TokenRetval::TK_WHITESPACE:
6214 break;
6215 case TokenRetval::TK_SYMBOL:
6216 {
6217 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
6219 {
6221 }
6222 else
6223 {
6224 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
6225 parser()->context.token->name);
6226 }
6227 }
6228 break;
6229 case TokenRetval::TK_COMMAND_AT:
6230 // fall through
6231 case TokenRetval::TK_COMMAND_BS:
6232 switch (Mappers::cmdMapper->map(parser()->context.token->name))
6233 {
6236 break;
6239 break;
6242 break;
6245 break;
6248 break;
6251 break;
6254 break;
6257 break;
6260 break;
6264 break;
6269 break;
6272 break;
6275 break;
6278 break;
6281 break;
6284 break;
6287 break;
6290 break;
6291 default:
6292 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6293 parser()->context.token->name);
6294 break;
6295 }
6296 break;
6297 default:
6298 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6299 tok.to_string());
6300 break;
6301 }
6302 tok = parser()->tokenizer.lex();
6303 }
6304
6306
6307}
6308
6309
6310//--------------------------------------------------------------------------
6311
6313{
6314 AUTO_TRACE();
6315 auto ns = AutoNodeStack(parser(),thisVariant());
6317 Token retval = Token::make_TK_NONE();
6318
6319 // first parse any number of paragraphs
6320 bool isFirst=TRUE;
6321 DocPara *lastPar = nullptr;
6322 do
6323 {
6324 {
6326 DocPara *par = children().get_last<DocPara>();
6327 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6328 retval=par->parse();
6329 if (par->isEmpty() && par->attribs().empty())
6330 {
6331 children().pop_back();
6332 }
6333 else
6334 {
6335 lastPar = par;
6336 }
6337 }
6338 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6339 if (retval == t)
6340 {
6341 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6342 {
6343 warn_doc_error(parser()->context.fileName,
6344 parser()->tokenizer.getLineNr(),
6345 "found {} command (id: '{}') outside of {} context!",
6346 sectionType,parser()->context.token->sectionId,parentSectionType);
6347 }
6348 while (retval==t)
6349 {
6350 if (!parser()->context.token->sectionId.isEmpty())
6351 {
6352 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6353 if (sec)
6354 {
6356 level,
6358 retval = children().get_last<DocSection>()->parse();
6359 }
6360 else
6361 {
6362 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6363 sectionType,parser()->context.token->sectionId,sectionType);
6364 retval = Token::make_TK_NONE();
6365 }
6366 }
6367 else
6368 {
6369 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6370 retval = Token::make_TK_NONE();
6371 }
6372 }
6373 }
6374 };
6375 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6376 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6377 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6378 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6379 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6380
6381 if (retval.is(TokenRetval::TK_LISTITEM))
6382 {
6383 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6384 }
6385 if (retval.is(TokenRetval::RetVal_Internal))
6386 {
6388 retval = children().get_last<DocInternal>()->parse(1);
6389 }
6390 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6391 if (lastPar) lastPar->markLast();
6392
6393 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6394 // then parse any number of level1 sections
6395 while (retval.is(TokenRetval::RetVal_Section))
6396 {
6397 if (!parser()->context.token->sectionId.isEmpty())
6398 {
6399 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6400 if (sec)
6401 {
6403 1,
6405 retval = children().get_last<DocSection>()->parse();
6406 }
6407 else
6408 {
6409 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6410 retval = Token::make_TK_NONE();
6411 }
6412 }
6413 else
6414 {
6415 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6416 retval = Token::make_TK_NONE();
6417 }
6418 }
6419
6421}
bool isAliasCmd(std::string_view aliasCmd)
Definition aliases.cpp:518
static AnchorGenerator & instance()
Returns the singleton instance.
Definition anchor.cpp:38
Citation manager class.
Definition cite.h:85
QCString anchorPrefix() const
Definition cite.cpp:126
const CiteInfo * find(const QCString &label) const
Return the citation info for a given label.
Definition cite.cpp:101
static CitationManager & instance()
Definition cite.cpp:85
QCString fileName() const
Definition cite.cpp:121
constexpr void setNoCite() noexcept
Definition cite.h:35
static constexpr CiteInfoOption makeNumber()
Definition cite.h:29
constexpr void changeToNumber() noexcept
Definition cite.h:33
constexpr void setNoPar() noexcept
Definition cite.h:34
constexpr bool isUnknown() const noexcept
Definition cite.h:37
static constexpr CiteInfoOption makeYear()
Definition cite.h:31
static constexpr CiteInfoOption makeShortAuthor()
Definition cite.h:30
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:2994
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:2987
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:2947
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:959
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:923
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:1195
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1188
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:1117
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1110
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:1508
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:1715
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:1919
void setColumnIndex(uint32_t idx)
Definition docnode.h:1217
bool isFirst() const
Definition docnode.h:1201
Token parseXml()
Definition docnode.cpp:1823
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:1857
void markFirst(bool v=TRUE)
Definition docnode.h:1203
Alignment alignment() const
Definition docnode.cpp:1881
bool isHeading() const
Definition docnode.h:1200
const HtmlAttribList & attribs() const
Definition docnode.h:1205
Token parse()
Definition docnode.cpp:1789
uint32_t colSpan() const
Definition docnode.cpp:1869
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:1498
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:1324
Node representing a Html list.
Definition docnode.h:1000
Type m_type
Definition docnode.h:1011
Token parseXml()
Definition docnode.cpp:2794
Token parse()
Definition docnode.cpp:2719
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:2123
void setVisibleCells(uint32_t n)
Definition docnode.h:1256
bool isHeading() const
Definition docnode.cpp:1941
void setRowIndex(uint32_t idx)
Definition docnode.h:1261
Token parse()
Definition docnode.cpp:2016
Node Html summary.
Definition docnode.h:844
Node representing a HTML table.
Definition docnode.h:1269
Token parseXml()
Definition docnode.cpp:2296
size_t numberHeaderRows() const
Definition docnode.cpp:2194
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1284
Token parse()
Definition docnode.cpp:2209
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2353
size_t m_numCols
Definition docnode.h:1286
const DocNodeVariant * caption() const
Definition docnode.cpp:2189
bool hasCaption() const
Definition docnode.cpp:2184
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:1301
std::unique_ptr< Private > p
Definition docnode.h:675
void parse()
Definition docnode.cpp:1316
bool isSVG() const
Definition docnode.cpp:1307
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:1618
Node representing an internal section of documentation.
Definition docnode.h:969
Token parse(int)
Definition docnode.cpp:1558
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:1148
bool parse()
Definition docnode.cpp:1155
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:2888
Node representing a paragraph in the documentation tree.
Definition docnode.h:1080
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3417
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3932
void handleInheritDoc()
Definition docnode.cpp:4190
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3470
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3411
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:4000
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4227
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3606
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4105
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3893
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3809
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3447
void markLast(bool v=TRUE)
Definition docnode.h:1086
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4977
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3575
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3833
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:3973
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3795
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1115
bool m_isFirst
Definition docnode.h:1118
Token parse()
Definition docnode.cpp:5723
void handleVhdlFlow()
Definition docnode.cpp:3925
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:4136
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3725
bool m_isLast
Definition docnode.h:1119
Token handleXRefItem()
Definition docnode.cpp:3704
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5450
Token handleStartCode()
Definition docnode.cpp:4154
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:4147
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:3300
void markLast(bool b=TRUE)
Definition docnode.h:1135
Token parse(const QCString &cmdName)
Definition docnode.cpp:3221
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:3368
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:1227
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:877
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:6312
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:6028
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:2932
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:2913
Node representing a simple section.
Definition docnode.h:1017
QCString typeString() const
Definition docnode.cpp:3192
Type type() const
Definition docnode.h:1026
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:3082
Token parseRcs()
Definition docnode.cpp:3119
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:3072
const DocNodeVariant * title() const
Definition docnode.h:1033
Token parseXml()
Definition docnode.cpp:3136
void appendLinkWord(const QCString &word)
Definition docnode.cpp:3172
bool hasTitle() const
Definition docnode.cpp:3077
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:6198
Node representing a simple section title.
Definition docnode.h:608
void parse()
Definition docnode.cpp:3041
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:3059
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:1271
void parse()
Definition docnode.cpp:1275
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:109
static FileNameLinkedMap * dotFileNameLinkedMap
Definition doxygen.h:106
static NamespaceDefMutable * globalScope
Definition doxygen.h:120
static FileNameLinkedMap * mscFileNameLinkedMap
Definition doxygen.h:107
static FileNameLinkedMap * diaFileNameLinkedMap
Definition doxygen.h:108
static QCString htmlFileExtension
Definition doxygen.h:121
static PageLinkedMap * pageLinkedMap
Definition doxygen.h:99
static DirLinkedMap * dirLinkedMap
Definition doxygen.h:128
static SearchIndexIntf searchIndex
Definition doxygen.h:123
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:230
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:174
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:133
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:845
static Token skipSpacesForTable(DocParser *parser)
Definition docnode.cpp:1956
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4961
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2347
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:117
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5671
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:1956
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:571
#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:2342
uint32_t column
Definition docnode.cpp:2343
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2341
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:836
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:2642
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5147
QCString stripIndentation(const QCString &s, bool skipFirstLine)
Definition util.cpp:5901
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:2966
QCString stripScope(const QCString &name)
Definition util.cpp:3721
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, SrcLangExt lang, const QCString &prefix)
Definition util.cpp:2668
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3446
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:6568
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:4966
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:2838
A bunch of utility functions.