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