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();
3266 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3267 {
3269 {
3270 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3271 if (typeSeparator!=-1)
3272 {
3273 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3274 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3277 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3278 {
3279 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3280 }
3281 }
3282 else
3283 {
3286 }
3287 }
3288 else if (m_type==DocParamSect::RetVal)
3289 {
3292 }
3293 parser()->context.inSeeBlock=true;
3295 parser()->context.inSeeBlock=false;
3296 tok=parser()->tokenizer.lex();
3297 }
3299 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3300 {
3301 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3302 "argument of command {}",saveCmdName);
3303 retval = Token::make_RetVal_EndParBlock();
3304 goto endparamlist;
3305 }
3306 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3307 {
3308 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3309 {
3310 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3311 "argument of command {}",tok.to_string(),saveCmdName);
3312 }
3313 retval = Token::make_RetVal_EndParBlock();
3314 goto endparamlist;
3315 }
3316
3318 par = m_paragraphs.get_last<DocPara>();
3319 retval = par->parse();
3320 par->markFirst();
3321 par->markLast();
3322
3323endparamlist:
3324 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3325 return retval;
3326}
3327
3329{
3330 AUTO_TRACE();
3331 Token retval = Token::make_RetVal_OK();
3332 auto ns = AutoNodeStack(parser(),thisVariant());
3333
3334 parser()->context.token->name = paramName;
3336 {
3339 }
3340 else if (m_type==DocParamSect::RetVal)
3341 {
3344 }
3345
3347
3348 do
3349 {
3351 DocPara *par = m_paragraphs.get_last<DocPara>();
3352 retval = par->parse();
3353 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3354 // after </para> and before </param>
3355 {
3356 m_paragraphs.pop_back();
3357 break;
3358 }
3359 else // append the paragraph to the list
3360 {
3361 if (!m_paragraphs.empty())
3362 {
3363 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3364 }
3365 bool markFirst = m_paragraphs.empty();
3366 par = &std::get<DocPara>(m_paragraphs.back());
3367 if (markFirst)
3368 {
3369 par->markFirst();
3370 }
3371 par->markLast();
3372 }
3373
3374 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3375
3376 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3377 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3378 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3379 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3380
3381 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3382 {
3383 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3384 }
3385 else
3386 {
3387 retval = Token::make_RetVal_OK();
3388 }
3389
3390 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3391 return retval;
3392}
3393
3394//--------------------------------------------------------------------------
3395
3396Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3397{
3398 AUTO_TRACE();
3399 Token retval = Token::make_RetVal_OK();
3400 auto ns = AutoNodeStack(parser(),thisVariant());
3401
3402 if (d!=Unspecified)
3403 {
3405 }
3406
3407 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3408 {
3409 DocParamList &lastPl = std::get<DocParamList>(children().back());
3410 lastPl.markLast(false);
3411 }
3412 bool markFirst = children().empty();
3415 if (markFirst)
3416 {
3417 pl->markFirst();
3418 }
3419 pl->markLast();
3420 if (xmlContext)
3421 {
3422 retval = pl->parseXml(cmdName);
3423 }
3424 else
3425 {
3426 retval = pl->parse(cmdName);
3427 }
3428 if (retval.is(TokenRetval::RetVal_EndParBlock))
3429 {
3430 retval = Token::make_RetVal_OK();
3431 }
3432
3433 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3434 return retval;
3435}
3436
3437//--------------------------------------------------------------------------
3438
3444
3446{
3447 AUTO_TRACE();
3448 DocSimpleSect *ss=nullptr;
3449 bool needsSeparator = FALSE;
3450 if (!children().empty() && // has previous element
3451 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3452 ss->type()==t && // of same type
3453 t!=DocSimpleSect::User) // but not user defined
3454 {
3455 // append to previous section
3456 needsSeparator = TRUE;
3457 }
3458 else // start new section
3459 {
3462 }
3463 Token rv = Token::make_RetVal_OK();
3464 if (xmlContext)
3465 {
3466 return ss->parseXml();
3467 }
3468 else
3469 {
3470 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3471 }
3472 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3473}
3474
3477 bool xmlContext=FALSE,
3478 int direction=DocParamSect::Unspecified)
3479{
3480 AUTO_TRACE();
3481 DocParamSect *ps = nullptr;
3482 if (!children().empty() && // previous element
3483 (ps=children().get_last<DocParamSect>()) && // was a param sect
3484 ps->type()==t) // of same type
3485 { // append to previous section ps
3486 }
3487 else // start new section
3488 {
3490 ps = children().get_last<DocParamSect>();
3491 }
3492 Token rv=ps->parse(cmdName,xmlContext,
3493 static_cast<DocParamSect::Direction>(direction));
3494 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3495 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3496}
3497
3498void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3499{
3500 AUTO_TRACE();
3501 QCString saveCmdName = cmdName;
3502 // get the argument of the cite command.
3503 Token tok=parser()->tokenizer.lex();
3504
3505 CiteInfoOption option;
3506 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3507 {
3509 parser()->tokenizer.lex();
3510 StringVector optList=split(parser()->context.token->name.str(),",");
3511 for (auto const &opt : optList)
3512 {
3513 if (opt == "number")
3514 {
3515 if (!option.isUnknown())
3516 {
3517 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3518 }
3519 else
3520 {
3521 option = CiteInfoOption::makeNumber();
3522 }
3523 }
3524 else if (opt == "year")
3525 {
3526 if (!option.isUnknown())
3527 {
3528 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3529 }
3530 else
3531 {
3532 option = CiteInfoOption::makeYear();
3533 }
3534 }
3535 else if (opt == "shortauthor")
3536 {
3537 if (!option.isUnknown())
3538 {
3539 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3540 }
3541 else
3542 {
3544 }
3545 }
3546 else if (opt == "nopar")
3547 {
3548 option.setNoPar();
3549 }
3550 else if (opt == "nocite")
3551 {
3552 option.setNoCite();
3553 }
3554 else
3555 {
3556 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unknown option specified with \\{}, discarding '{}'", saveCmdName, opt);
3557 }
3558 }
3559
3560 if (option.isUnknown()) option.changeToNumber();
3561
3563 tok=parser()->tokenizer.lex();
3564 if (!tok.is(TokenRetval::TK_WHITESPACE))
3565 {
3566 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3567 saveCmdName);
3568 return;
3569 }
3570 }
3571 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3572 {
3573 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3574 cmdChar,saveCmdName);
3575 return;
3576 }
3577 else
3578 {
3579 option = CiteInfoOption::makeNumber();
3580 }
3581
3583 tok=parser()->tokenizer.lex();
3584 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3585 {
3586 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"THE ONE unexpected end of comment block while parsing the "
3587 "argument of command '{:c}{}'",cmdChar,saveCmdName);
3588 return;
3589 }
3590 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3591 {
3592 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3593 tok.to_string(),cmdChar,saveCmdName);
3594 return;
3595 }
3599
3601}
3602
3603void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3604{
3605 AUTO_TRACE();
3606 // get the argument of the emoji command.
3607 Token tok=parser()->tokenizer.lex();
3608 if (!tok.is(TokenRetval::TK_WHITESPACE))
3609 {
3610 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3611 cmdChar,cmdName);
3612 return;
3613 }
3615 tok=parser()->tokenizer.lex();
3616 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3617 {
3618 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3619 "argument of command '{:c}{}'",cmdChar,cmdName);
3621 return;
3622 }
3623 else if (!tok.is(TokenRetval::TK_WORD))
3624 {
3625 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3626 tok.to_string(),cmdChar,cmdName);
3628 return;
3629 }
3632}
3633
3634void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3635{
3636 // get the argument of the cite command.
3637 Token tok=parser()->tokenizer.lex();
3638 if (!tok.is(TokenRetval::TK_WHITESPACE))
3639 {
3640 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3641 cmdChar,cmdName);
3642 return;
3643 }
3645 tok=parser()->tokenizer.lex();
3646 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3647 {
3648 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3649 "argument of command '{:c}{}'",cmdChar,cmdName);
3650 return;
3651 }
3652 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3653 {
3654 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3655 tok.to_string(),cmdChar,cmdName);
3656 return;
3657 }
3658 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3659 if (opt)
3660 {
3661 QCString optionValue;
3662 switch (opt->kind())
3663 {
3665 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3666 break;
3668 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3669 break;
3671 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3672 break;
3674 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3675 break;
3677 {
3678 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3679 optionValue="";
3680 if (!lst->empty())
3681 {
3682 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3683 static const reg::Ex marker(R"(@(\d+))");
3684 reg::Iterator it(lstFormat,marker);
3686 size_t index=0;
3687 // now replace all markers with the real text
3688 for ( ; it!=end ; ++it)
3689 {
3690 const auto &match = *it;
3691 size_t newIndex = match.position();
3692 size_t matchLen = match.length();
3693 optionValue += lstFormat.substr(index,newIndex-index);
3694 unsigned long entryIndex = std::stoul(match[1].str());
3695 if (entryIndex<(unsigned long)lst->size())
3696 {
3697 optionValue += lst->at(entryIndex);
3698 }
3699 index=newIndex+matchLen;
3700 }
3701 optionValue+=lstFormat.substr(index);
3702 }
3703 }
3704 break;
3706 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3707 cmdChar,cmdName,parser()->context.token->name);
3708 break;
3710 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3711 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3712 cmdChar,cmdName,parser()->context.token->name);
3713 break;
3715 // nothing to show here
3716 break;
3717 }
3718 if (!optionValue.isEmpty())
3719 {
3720 children().append<DocWord>(parser(),thisVariant(),optionValue);
3721 }
3722 }
3723 else
3724 {
3725 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3726 cmdChar,cmdName,parser()->context.token->name);
3728 }
3730}
3731
3733{
3734 AUTO_TRACE();
3735 Token retval=parser()->tokenizer.lex();
3736 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3738 retval=parser()->tokenizer.lex();
3739 if (retval.is(TokenRetval::RetVal_OK))
3740 {
3744 if (!ref->parse())
3745 {
3746 children().pop_back();
3747 }
3748 }
3750 return retval;
3751}
3752
3753
3754void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3755{
3756 AUTO_TRACE();
3757 QCString fmt;
3758 QCString date;
3759 Token tok=parser()->tokenizer.lex();
3760 if (!tok.is(TokenRetval::TK_WHITESPACE))
3761 {
3762 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3763 cmdChar,cmdName);
3764 return;
3765 }
3767 tok = parser()->tokenizer.lex();
3768 if (!tok.is(TokenRetval::TK_WORD))
3769 {
3770 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3771 cmdChar,cmdName);
3773 return;
3774 }
3775 fmt = parser()->context.token->name;
3776
3778 tok = parser()->tokenizer.lex();
3779
3780 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3781 QCString specDate = specDateRaw.stripWhiteSpace();
3782 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3783 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3784 {
3785 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3786 cmdChar,cmdName);
3788 return;
3789 }
3790
3791 std::tm dat{};
3792 int specFormat=0;
3793 QCString err = dateTimeFromString(specDate,dat,specFormat);
3794 if (!err.isEmpty())
3795 {
3796 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3797 cmdChar,cmdName,err);
3799 return;
3800 }
3801
3802 int usedFormat=0;
3803 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3804
3805 // warn the user if the format contains markers that are not explicitly filled in
3806 for (int i=0;i<SF_NumBits;i++)
3807 {
3808 int bitMask = 1<<i;
3809 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3810 {
3811 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.",
3812 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3813 }
3814 }
3815
3816 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3817 if (specDateOnlyWS) // specDate is only whitespace
3818 {
3820 }
3822}
3823
3825{
3826 AUTO_TRACE("cmdName={}",cmdName);
3827 QCString saveCmdName = cmdName;
3828 Token tok=parser()->tokenizer.lex();
3829 if (!tok.is(TokenRetval::TK_WHITESPACE))
3830 {
3831 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3832 saveCmdName);
3833 return;
3834 }
3836 tok=parser()->tokenizer.lex();
3838 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3839 {
3840 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3841 "argument of command {}", saveCmdName);
3842 return;
3843 }
3844 else if (!tok.is(TokenRetval::TK_WORD))
3845 {
3846 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3847 tok.to_string(),saveCmdName);
3848 return;
3849 }
3850 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3851 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3852 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3853 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3854 //TODO get from context the stripCodeComments()
3855 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3859 stripCodeComments,
3862 );
3864 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3865 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3866 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3867 bool isFirst = !n1 || // no last node
3868 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3869 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3870 op->markFirst(isFirst);
3871 op->markLast(true);
3872 if (n1_docIncOp)
3873 {
3874 n1_docIncOp->markLast(false);
3875 }
3876 else if (n1_docWs && n2_docIncOp)
3877 {
3878 n2_docIncOp->markLast(false);
3879 }
3880 op->parse();
3881}
3882
3883template<class T>
3884void DocPara::handleFile(const QCString &cmdName)
3885{
3886 AUTO_TRACE("cmdName={}",cmdName);
3887 QCString saveCmdName = cmdName;
3888 Token tok=parser()->tokenizer.lex();
3889 if (!tok.is(TokenRetval::TK_WHITESPACE))
3890 {
3891 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3892 saveCmdName);
3893 return;
3894 }
3896 tok=parser()->tokenizer.lex();
3898 if (!tok.is(TokenRetval::TK_WORD))
3899 {
3900 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3901 tok.to_string(),saveCmdName);
3902 return;
3903 }
3904 QCString name = parser()->context.token->name;
3905 children().append<T>(parser(),thisVariant(),name,
3909 auto df = children().get_last<T>();
3910 if (!df->parse())
3911 {
3912 children().pop_back();
3913 }
3914}
3915
3922
3923void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3924{
3925 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3926 QCString saveCmdName = cmdName;
3927 Token tok=parser()->tokenizer.lex();
3928 if (!tok.is(TokenRetval::TK_WHITESPACE))
3929 {
3930 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3931 saveCmdName);
3932 return;
3933 }
3935 tok=parser()->tokenizer.lex();
3936 if (!tok.is(TokenRetval::TK_WORD))
3937 {
3938 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3939 tok.to_string(),saveCmdName);
3940 return;
3941 }
3942 if (saveCmdName == "javalink")
3943 {
3945 parser()->context.nodeStack.size(),
3946 DocStyleChange::Code,cmdName,TRUE);
3947 }
3950 DocLink *lnk = children().get_last<DocLink>();
3951 if (saveCmdName == "javalink")
3952 {
3954 parser()->context.nodeStack.size(),
3955 DocStyleChange::Code,cmdName,FALSE);
3956 }
3957 QCString leftOver = lnk->parse(isJavaLink);
3958 if (!leftOver.isEmpty())
3959 {
3960 children().append<DocWord>(parser(),thisVariant(),leftOver);
3961 }
3962}
3963
3965{
3966 AUTO_TRACE("cmdName={}",cmdName);
3967 QCString saveCmdName = cmdName;
3968 Token tok=parser()->tokenizer.lex();
3969 bool isBlock = false;
3970 bool trimLeft = false;
3971 bool localScope = false;
3972 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3973 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3974 {
3976 parser()->tokenizer.lex();
3978 StringVector optList=split(parser()->context.token->name.str(),",");
3979 auto contains = [&optList](const char *kw)
3980 {
3981 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
3982 };
3983 localScope = contains("local");
3984 if (contains("nostrip"))
3985 {
3986 stripCodeComments = false;
3987 }
3988 else if (contains("strip"))
3989 {
3990 stripCodeComments = true;
3991 }
3992 if (t==DocInclude::Snippet && contains("trimleft"))
3993 {
3994 trimLeft = true;
3995 }
3996
3997 if (contains("lineno"))
3998 {
4002 }
4003 tok=parser()->tokenizer.lex();
4004 if (!tok.is(TokenRetval::TK_WHITESPACE))
4005 {
4006 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4007 saveCmdName);
4008 return;
4009 }
4010 }
4011 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
4012 {
4014 parser()->tokenizer.lex();
4015 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
4017 parser()->tokenizer.lex();
4018 }
4019 else if (!tok.is(TokenRetval::TK_WHITESPACE))
4020 {
4021 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
4022 saveCmdName);
4023 return;
4024 }
4026 tok=parser()->tokenizer.lex();
4028 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4029 {
4030 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4031 "argument of command {}",saveCmdName);
4032 return;
4033 }
4034 else if (!tok.is(TokenRetval::TK_WORD))
4035 {
4036 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
4037 tok.to_string(),saveCmdName);
4038 return;
4039 }
4040 QCString fileName = parser()->context.token->name;
4041 QCString blockId;
4043 {
4044 if (fileName == "this") fileName=parser()->context.fileName;
4046 tok=parser()->tokenizer.lex();
4048 if (!tok.is(TokenRetval::TK_WORD))
4049 {
4050 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
4051 tok.to_string(),saveCmdName);
4052 return;
4053 }
4054 blockId = "["+parser()->context.token->name+"]";
4055 }
4056
4058 thisVariant(),
4059 fileName,
4060 localScope ? parser()->context.context : "",
4061 t,
4062 stripCodeComments,
4065 blockId,isBlock,trimLeft);
4067}
4068
4069void DocPara::handleSection(char cmdChar,const QCString &cmdName)
4070{
4071 AUTO_TRACE("cmdName={}",cmdName);
4072 QCString saveCmdName = cmdName;
4073 // get the argument of the section command.
4074 Token tok=parser()->tokenizer.lex();
4075 if (!tok.is(TokenRetval::TK_WHITESPACE))
4076 {
4077 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
4078 cmdChar,saveCmdName);
4079 return;
4080 }
4081 tok=parser()->tokenizer.lex();
4082 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4083 {
4084 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4085 "argument of command '{:c}{}'", cmdChar,saveCmdName);
4086 return;
4087 }
4088 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
4089 {
4090 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
4091 tok.to_string(),cmdChar,saveCmdName);
4092 return;
4093 }
4096 parser()->tokenizer.lex();
4098}
4099
4100Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
4101{
4102 AUTO_TRACE();
4103 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
4104 Token retval = children().get_last<DocHtmlHeader>()->parse();
4105 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
4106}
4107
4108// For XML tags whose content is stored in attributes rather than
4109// contained within the element, we need a way to inject the attribute
4110// text into the current paragraph.
4111bool DocPara::injectToken(Token tok,const QCString &tokText)
4112{
4113 AUTO_TRACE();
4114 parser()->context.token->name = tokText;
4115 return parser()->defaultHandleToken(thisVariant(),tok,children());
4116}
4117
4119{
4120 AUTO_TRACE();
4121 Token retval = parser()->tokenizer.lex();
4122 QCString lang = parser()->context.token->name;
4123 if (!lang.isEmpty() && lang.at(0)!='.')
4124 {
4125 lang="."+lang;
4126 }
4127 if (parser()->context.xmlComment)
4128 {
4129 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
4130 }
4131 // search for the first non-whitespace line, index is stored in li
4132 size_t i=0,li=0,l=parser()->context.token->verb.length();
4133 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
4134 {
4135 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
4136 i++;
4137 }
4140 stripIndentation(parser()->context.token->verb.mid(li)),
4144 FALSE,lang);
4145 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4146 {
4147 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
4148 }
4150 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4151 return retval;
4152}
4153
4155{
4156 if (parser()->context.memberDef) // inheriting docs from a member
4157 {
4158 const MemberDef *reMd = parser()->context.memberDef->reimplements();
4159 if (reMd) // member from which was inherited.
4160 {
4161 const MemberDef *thisMd = parser()->context.memberDef;
4162 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
4163 parser()->pushContext();
4164 parser()->context.scope=reMd->getOuterScope();
4165 if (parser()->context.scope!=Doxygen::globalScope)
4166 {
4168 }
4169 parser()->context.memberDef=reMd;
4170 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
4171 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
4172 parser()->context.copyStack.push_back(reMd);
4175 parser()->context.copyStack.pop_back();
4176 auto hasParamCommand = parser()->context.hasParamCommand;
4177 auto hasReturnCommand = parser()->context.hasReturnCommand;
4178 auto retvalsFound = parser()->context.retvalsFound;
4179 auto paramsFound = parser()->context.paramsFound;
4180 parser()->popContext();
4181 parser()->context.hasParamCommand = hasParamCommand;
4182 parser()->context.hasReturnCommand = hasReturnCommand;
4183 parser()->context.retvalsFound = retvalsFound;
4184 parser()->context.paramsFound = paramsFound;
4185 parser()->context.memberDef = thisMd;
4186 }
4187 }
4188}
4189
4190
4191Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
4192{
4193 AUTO_TRACE("cmdName={}",cmdName);
4194 Token retval = Token::make_RetVal_OK();
4195 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
4196 switch (cmdId)
4197 {
4199 {
4200 std::string str{cmdChar};
4201 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
4202 if (isAliasCmd(cmdName.view()))
4203 {
4204 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
4205 }
4206 else
4207 {
4208 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
4209 }
4210 }
4211 break;
4214 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4216 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4217 break;
4220 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4222 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4223 break;
4226 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4228 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4229 break;
4232 break;
4235 break;
4238 break;
4241 break;
4244 break;
4247 break;
4250 break;
4253 break;
4256 break;
4259 break;
4263 break;
4268 break;
4271 break;
4274 break;
4277 break;
4280 break;
4283 break;
4286 break;
4289 break;
4294 break;
4298 break;
4301 break;
4304 break;
4307 break;
4310 break;
4313 break;
4316 break;
4319 break;
4322 break;
4325 break;
4328 break;
4331 break;
4334 break;
4337 break;
4340 break;
4343 break;
4345 {
4347 retval = children().get_last<DocSimpleList>()->parse();
4348 }
4349 break;
4351 {
4352 handleSection(cmdChar,cmdName);
4353 retval = Token::make_RetVal_Section();
4354 }
4355 break;
4357 {
4358 handleSection(cmdChar,cmdName);
4359 retval = Token::make_RetVal_Subsection();
4360 }
4361 break;
4363 {
4364 handleSection(cmdChar,cmdName);
4365 retval = Token::make_RetVal_Subsubsection();
4366 }
4367 break;
4369 {
4370 handleSection(cmdChar,cmdName);
4371 retval = Token::make_RetVal_Paragraph();
4372 }
4373 break;
4375 {
4376 handleSection(cmdChar,cmdName);
4377 retval = Token::make_RetVal_SubParagraph();
4378 }
4379 break;
4381 {
4382 handleSection(cmdChar,cmdName);
4383 retval = Token::make_RetVal_SubSubParagraph();
4384 }
4385 break;
4387 {
4389 retval = handleStartCode();
4390 }
4391 break;
4393 {
4395 retval = handleStartCode();
4396 }
4397 break;
4399 {
4401 retval = parser()->tokenizer.lex();
4403 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4404 {
4405 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4406 }
4408 }
4409 break;
4411 {
4413 retval = parser()->tokenizer.lex();
4415 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4416 {
4417 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4418 }
4420 }
4421 break;
4423 {
4425 retval = parser()->tokenizer.lex();
4427 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4428 {
4429 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4430 }
4432 }
4433 break;
4435 {
4437 retval = parser()->tokenizer.lex();
4439 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4440 {
4441 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4442 }
4444 }
4445 break;
4447 {
4449 retval = parser()->tokenizer.lex();
4451 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4452 {
4453 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4454 }
4456 }
4457 break;
4459 {
4461 retval = parser()->tokenizer.lex();
4463 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4464 {
4465 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4466 }
4468 }
4469 break;
4471 {
4474 parser()->tokenizer.lex();
4475
4476 QCString fullMatch = parser()->context.token->verb;
4477 int idx = fullMatch.find('{');
4478 int idxEnd = fullMatch.find("}",idx+1);
4479 StringVector optList;
4480 if (idx != -1) // options present
4481 {
4482 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4483 optList = split(optStr.str(),",");
4484 for (const auto &opt : optList)
4485 {
4486 if (opt.empty()) continue;
4487 QCString locOpt(opt);
4488 locOpt = locOpt.stripWhiteSpace().lower();
4489 if (locOpt == "code")
4490 {
4492 }
4493 else if (!locOpt.isEmpty())
4494 {
4495 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4496 }
4497 }
4498 }
4499
4501 retval = parser()->tokenizer.lex();
4503 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4504 {
4505 if (t == DocVerbatim::JavaDocCode)
4506 {
4507 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4508 }
4509 else
4510 {
4511 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4512 }
4513 }
4515 }
4516 break;
4519 {
4520 if (cmdId == CommandType::CMD_VERBATIM)
4521 {
4523 }
4524 else
4525 {
4527 }
4528 retval = parser()->tokenizer.lex();
4530 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4531 {
4532 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4533 }
4535 }
4536 break;
4538 {
4547 QCString width,height;
4548 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4550 retval = parser()->tokenizer.lex();
4551 dv->setText(parser()->context.token->verb);
4552 dv->setWidth(width);
4553 dv->setHeight(height);
4554 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4555 if (!Config_getBool(HAVE_DOT))
4556 {
4557 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4558 children().pop_back();
4559 }
4560 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4561 {
4562 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4563 }
4565 }
4566 break;
4568 {
4577 QCString width,height;
4578 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4580 retval = parser()->tokenizer.lex();
4581 dv->setText(parser()->context.token->verb);
4582 dv->setWidth(width);
4583 dv->setHeight(height);
4584 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4585 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4586 {
4587 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4588 }
4590 }
4591 break;
4593 {
4594 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4596 parser()->tokenizer.lex();
4597 QCString fullMatch = parser()->context.token->sectionId;
4598 QCString sectionId = "";
4599 int idx = fullMatch.find('{');
4600 int idxEnd = fullMatch.find("}",idx+1);
4601 StringVector optList;
4602 QCString engine;
4603 if (idx != -1) // options present
4604 {
4605 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4606 optList = split(optStr.str(),",");
4607 for (const auto &opt : optList)
4608 {
4609 if (opt.empty()) continue;
4610 bool found = false;
4611 QCString locOpt(opt);
4612 locOpt = locOpt.stripWhiteSpace().lower();
4613 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4614 {
4615 if (!engine.isEmpty())
4616 {
4617 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4618 }
4619 engine = locOpt;
4620 found = true;
4621 }
4622 if (!found)
4623 {
4624 if (sectionId.isEmpty())
4625 {
4626 sectionId = opt;
4627 }
4628 else
4629 {
4630 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4631 }
4632 }
4633 }
4634 }
4635 else
4636 {
4637 sectionId = parser()->context.token->sectionId;
4638 }
4639 if (engine.isEmpty()) engine = "uml";
4640
4641 if (sectionId.isEmpty())
4642 {
4644 retval = parser()->tokenizer.lex();
4645 assert(retval.is(TokenRetval::RetVal_OK));
4646
4647 sectionId = parser()->context.token->sectionId;
4648 sectionId = sectionId.stripWhiteSpace();
4649 }
4650
4651 QCString plantFile(sectionId);
4656 FALSE,plantFile);
4658 dv->setEngine(engine);
4660 QCString width,height;
4661 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4663 retval = parser()->tokenizer.lex();
4664 int line = 0;
4665 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4666 if (engine == "ditaa")
4667 {
4668 dv->setUseBitmap(true);
4669 }
4670 else if (engine == "uml")
4671 {
4672 int i = trimmedVerb.find('\n');
4673 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4674 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4675 }
4676 dv->setText(trimmedVerb);
4677 dv->setWidth(width);
4678 dv->setHeight(height);
4679 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4680 if (jarPath.isEmpty())
4681 {
4682 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4683 children().pop_back();
4684 }
4685 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4686 {
4687 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4688 }
4690 }
4691 break;
4693 retval = Token::make_RetVal_EndParBlock();
4694 break;
4710 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4711 break;
4713 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4714 break;
4716 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4717 break;
4719 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4720 break;
4723 break;
4725 retval = handleXRefItem();
4726 break;
4728 {
4730 }
4731 break;
4734 {
4736 }
4737 break;
4739 {
4741 }
4742 break;
4744 {
4748 retval = children().get_last<DocIndexEntry>()->parse();
4749 }
4750 break;
4752 retval = Token::make_RetVal_Internal();
4753 break;
4755 retval = Token::make_RetVal_EndInternal();
4756 break;
4758 {
4760 retval = children().get_last<DocParBlock>()->parse();
4761 }
4762 break;
4763 case CommandType::CMD_COPYDOC: // fall through
4764 case CommandType::CMD_COPYBRIEF: // fall through
4766 //retval = Token::make_RetVal_CopyDoc();
4767 // these commands should already be resolved by processCopyDoc()
4768 break;
4771 break;
4774 break;
4777 break;
4780 break;
4783 break;
4786 break;
4789 break;
4792 break;
4795 break;
4798 break;
4801 break;
4804 break;
4807 break;
4810 break;
4813 break;
4816 break;
4819 break;
4821 if (!Config_getBool(HAVE_DOT))
4822 {
4823 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4824 "ignoring \\dotfile command because HAVE_DOT is not set");
4825 }
4826 else
4827 {
4828 handleFile<DocDotFile>(cmdName);
4829 }
4830 break;
4833 break;
4835 handleFile<DocMscFile>(cmdName);
4836 break;
4838 handleFile<DocDiaFile>(cmdName);
4839 break;
4842 break;
4844 handleLink(cmdName,FALSE);
4845 break;
4847 handleLink(cmdName,TRUE);
4848 break;
4850 handleCite(cmdChar,cmdName);
4851 break;
4853 handleEmoji(cmdChar,cmdName);
4854 break;
4856 handleDoxyConfig(cmdChar,cmdName);
4857 break;
4859 // fall through
4861 parser()->handleRef(thisVariant(),children(),cmdChar,cmdName);
4862 break;
4864 {
4867 }
4868 break;
4870 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4871 break;
4873 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4874 break;
4876 {
4878 }
4879 break;
4880 //case CommandType::CMD_LANGSWITCH:
4881 // retval = handleLanguageSwitch();
4882 // break;
4884 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4885 {
4888 }
4889 break;
4892 break;
4894 handleShowDate(cmdChar,cmdName);
4895 break;
4897 parser()->handleILine(cmdChar,cmdName);
4898 break;
4900 parser()->handleIFile(cmdChar,cmdName);
4901 break;
4903 {
4905 (void)parser()->tokenizer.lex();
4907 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4909 }
4910 break;
4911 default:
4912 // we should not get here!
4913 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4914 break;
4915 }
4916 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4917 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4918 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4919 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4920 TokenRetval::RetVal_EndInternal)
4921 );
4922 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4923 return retval;
4924}
4925
4926static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4927 const char *attrName,
4928 QCString *result)
4929{
4930
4931 for (const auto &opt : tagHtmlAttribs)
4932 {
4933 if (opt.name==attrName)
4934 {
4935 *result = opt.value;
4936 return TRUE;
4937 }
4938 }
4939 return FALSE;
4940}
4941
4942Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4943{
4944 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4945 Token retval = Token::make_RetVal_OK();
4946 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4947 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4950 {
4951 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4952 tagName);
4953 }
4954 switch (tagId)
4955 {
4957 if (!parser()->context.token->emptyTag)
4958 {
4960 tagHtmlAttribs,DocHtmlList::Unordered);
4961 retval=children().get_last<DocHtmlList>()->parse();
4962 }
4963 break;
4965 if (!parser()->context.token->emptyTag)
4966 {
4968 tagHtmlAttribs,DocHtmlList::Ordered);
4969 retval=children().get_last<DocHtmlList>()->parse();
4970 }
4971 break;
4973 if (parser()->context.token->emptyTag) break;
4975 {
4976 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4977 }
4978 else
4979 {
4980 retval = Token::make_RetVal_ListItem();
4981 }
4982 break;
4984 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
4985 break;
4987 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
4988 break;
4990 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
4991 break;
4993 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
4994 break;
4996 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
4997 break;
4999 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
5000 break;
5002 if (parser()->context.token->emptyTag) break;
5003 if (parser()->context.xmlComment)
5004 // for C# source or inside a <summary> or <remark> section we
5005 // treat <code> as an XML tag (so similar to @code)
5006 {
5008 retval = handleStartCode();
5009 }
5010 else // normal HTML markup
5011 {
5012 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5013 }
5014 break;
5016 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
5017 break;
5019 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Typewriter,tagName,&parser()->context.token->attribs);
5020 break;
5022 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
5023 break;
5025 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
5026 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
5027 break;
5029 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
5030 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
5031 break;
5033 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
5034 break;
5036 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
5037 break;
5039 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
5040 break;
5042 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
5043 break;
5045 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
5046 break;
5048 if (parser()->context.token->emptyTag) break;
5049 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
5052 break;
5054 retval = Token::make_TK_NEWPARA();
5055 break;
5057 if (!parser()->context.token->emptyTag)
5058 {
5059 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
5060 retval=children().get_last<DocHtmlDescList>()->parse();
5061 }
5062 break;
5064 if (insideDL(thisVariant()))
5065 {
5066 retval = Token::make_RetVal_DescTitle();
5067 }
5068 else
5069 {
5070 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
5071 }
5072 break;
5074 if (insideDL(thisVariant()))
5075 {
5076 retval = Token::make_RetVal_DescData();
5077 }
5078 else
5079 {
5080 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
5081 }
5082 break;
5084 if (!parser()->context.token->emptyTag)
5085 {
5086 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
5087 retval=children().get_last<DocHtmlTable>()->parse();
5088 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5089 }
5090 break;
5092 retval = Token::make_RetVal_TableRow();
5093 break;
5095 retval = Token::make_RetVal_TableCell();
5096 break;
5098 retval = Token::make_RetVal_TableHCell();
5099 break;
5103 // for time being ignore </t....> tag
5104 break;
5106 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
5107 break;
5109 {
5110 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
5111 }
5112 break;
5114 {
5115 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
5116 }
5117 break;
5119 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
5120 break;
5122 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
5123 break;
5125 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
5126 break;
5128 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
5129 break;
5131 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
5132 break;
5134 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
5135 break;
5137 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
5138 break;
5140 {
5141 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
5142 }
5143 break;
5145 if (!parser()->context.token->emptyTag)
5146 {
5147 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
5148 retval=children().get_last<DocHtmlDetails>()->parse();
5149 }
5150 break;
5152 if (!parser()->context.token->emptyTag)
5153 {
5154 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
5155 retval = children().get_last<DocHtmlBlockQuote>()->parse();
5156 }
5157 break;
5158
5161 {
5162 if (!parser()->context.token->emptyTag)
5163 {
5165 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
5166 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
5167 if (d)
5168 {
5169 if (!d->summary()) // details section does not have a summary yet
5170 {
5171 d->parseSummary(n,parser()->context.token->attribs);
5172 }
5173 else
5174 {
5175 retval = Token::make_TK_NEWPARA();
5176 }
5177 }
5178 }
5179 }
5180 break;
5184 // fall through
5187 if (!children().empty())
5188 {
5189 retval = Token::make_TK_NEWPARA();
5190 }
5191 break;
5193 if (insideTable(thisVariant()))
5194 {
5195 retval = Token::make_RetVal_TableCell();
5196 }
5197 break;
5198 case HtmlTagType::XML_C:
5199 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5200 break;
5203 {
5205 QCString paramName;
5206 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5207 {
5208 if (paramName.isEmpty())
5209 {
5210 if (Config_getBool(WARN_NO_PARAMDOC))
5211 {
5212 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5213 }
5214 }
5215 else
5216 {
5217 retval = handleParamSection(paramName,
5219 TRUE);
5220 }
5221 }
5222 else
5223 {
5224 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5225 }
5226 }
5227 break;
5230 {
5231 QCString paramName;
5232 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5233 {
5234 //printf("paramName=%s\n",qPrint(paramName));
5236 children().append<DocWord>(parser(),thisVariant(),paramName);
5238 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5239 }
5240 else
5241 {
5242 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5243 }
5244 }
5245 break;
5247 {
5249 QCString exceptName;
5250 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5251 {
5252 unescapeCRef(exceptName);
5253 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5254 }
5255 else
5256 {
5257 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5258 }
5259 }
5260 break;
5263 if (insideTable(thisVariant()))
5264 {
5265 retval = Token::make_RetVal_TableRow();
5266 }
5267 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5268 {
5269 retval = Token::make_RetVal_ListItem();
5270 }
5271 else
5272 {
5273 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5274 }
5275 break;
5280 break;
5282 if (insideTable(thisVariant()))
5283 {
5284 retval = Token::make_RetVal_TableCell();
5285 }
5286 break;
5288 // I'm not sure if <see> is the same as <seealso> or if it
5289 // should you link a member without producing a section. The
5290 // C# specification is extremely vague about this (but what else
5291 // can we expect from Microsoft...)
5292 {
5293 QCString cref;
5294 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5295 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5296 {
5297 unescapeCRef(cref);
5298 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5299 {
5300 bool inSeeBlock = parser()->context.inSeeBlock;
5301 parser()->context.token->name = cref;
5304 parser()->context.inSeeBlock = inSeeBlock;
5305 }
5306 else // <see cref="...">...</see> style
5307 {
5310 DocLink *lnk = children().get_last<DocLink>();
5311 QCString leftOver = lnk->parse(FALSE,TRUE);
5312 if (!leftOver.isEmpty())
5313 {
5314 children().append<DocWord>(parser(),thisVariant(),leftOver);
5315 }
5316 }
5317 }
5318 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5319 {
5320 bool inSeeBlock = parser()->context.inSeeBlock;
5321 parser()->context.token->name = cref;
5326 parser()->context.inSeeBlock = inSeeBlock;
5327 }
5328 else
5329 {
5330 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5331 }
5332 }
5333 break;
5335 {
5337 QCString cref;
5338 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5339 {
5340 unescapeCRef(cref);
5341 // Look for an existing "see" section
5342 DocNodeVariant *vss=nullptr;
5343 for (auto &n : children())
5344 {
5345 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5346 if (candidate && candidate->type()==DocSimpleSect::See)
5347 {
5348 vss = &n;
5349 }
5350 }
5351
5352 if (!vss) // start new section
5353 {
5355 vss = &children().back();
5356 }
5357
5358 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5359 retval = Token::make_RetVal_OK();
5360 }
5361 else
5362 {
5363 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5364 }
5365 }
5366 break;
5368 {
5369 QCString type;
5370 findAttribute(tagHtmlAttribs,"type",&type);
5372 HtmlAttribList emptyList;
5373 if (type=="number")
5374 {
5375 listType=DocHtmlList::Ordered;
5376 }
5377 if (type=="table")
5378 {
5379 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5380 retval=children().get_last<DocHtmlTable>()->parseXml();
5381 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5382 }
5383 else
5384 {
5385 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5386 retval=children().get_last<DocHtmlList>()->parseXml();
5387 }
5388 }
5389 break;
5392 // These tags are defined in .Net but are currently unsupported
5394 break;
5396 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5397 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5398 break;
5401 break;
5402 default:
5403 // we should not get here!
5404 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5405 ASSERT(0);
5406 break;
5407 }
5408 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5409 return retval;
5410}
5411
5413{
5414 AUTO_TRACE("tagName={}",tagName);
5415 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5416 Token retval = Token::make_RetVal_OK();
5417 switch (tagId)
5418 {
5420 if (!insideUL(thisVariant()))
5421 {
5422 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5423 }
5424 else
5425 {
5426 retval = Token::make_RetVal_EndList();
5427 }
5428 break;
5430 if (!insideOL(thisVariant()))
5431 {
5432 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5433 }
5434 else
5435 {
5436 retval = Token::make_RetVal_EndList();
5437 }
5438 break;
5440 if (!insideLI(thisVariant()))
5441 {
5442 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5443 }
5444 else
5445 {
5446 // ignore </li> tags
5447 }
5448 break;
5450 if (!insideDetails(thisVariant()))
5451 {
5452 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5453 }
5454 else
5455 {
5456 retval = Token::make_RetVal_EndHtmlDetails();
5457 }
5458 break;
5461 {
5462 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5463 }
5464 else
5465 {
5466 retval = Token::make_RetVal_EndBlockQuote();
5467 }
5468 break;
5471 break;
5474 break;
5477 break;
5480 break;
5483 break;
5486 break;
5489 break;
5492 break;
5495 break;
5498 break;
5501 break;
5504 break;
5507 break;
5510 break;
5513 break;
5516 break;
5519 break;
5524 break;
5526 retval = Token::make_TK_NEWPARA();
5527 break;
5529 retval = Token::make_RetVal_EndDesc();
5530 break;
5532 // ignore </dt> tag
5533 break;
5535 // ignore </dd> tag
5536 break;
5538 retval = Token::make_RetVal_EndTable();
5539 break;
5541 retval = Token::make_RetVal_EndTableRow();
5542 break;
5544 retval = Token::make_RetVal_EndTableCell();
5545 break;
5547 retval = Token::make_RetVal_EndTableCell();
5548 break;
5552 // for time being ignore </t....> tag
5553 break;
5555 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5556 break;
5558 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5559 break;
5561 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5562 break;
5564 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5565 break;
5567 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5568 break;
5570 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5571 break;
5573 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5574 break;
5576 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5577 break;
5579 break;
5581 // warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5582 break;
5584 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5585 // ignore </a> tag (can be part of <a name=...></a>
5586 break;
5587
5589 break;
5591 retval = Token::make_TK_NEWPARA();
5592 break;
5605 retval = Token::make_RetVal_CloseXml();
5606 break;
5607 case HtmlTagType::XML_C:
5609 break;
5617 // These tags are defined in .Net but are currently unsupported
5618 break;
5620 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5621 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5622 break;
5623 default:
5624 // we should not get here!
5625 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5626 ASSERT(0);
5627 break;
5628 }
5629 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5630 return retval;
5631}
5632
5634{
5635 // expected hierarchy:
5636 // 1. DocAutoListItem <- n
5637 // 2. DocAutoList <- parent(n)
5638 // 3. DocPara <- parent(parent(n))
5639
5640 // step 1
5641 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5642 {
5643 return false;
5644 }
5645
5646 // step 2
5647 n = parent(n);
5648 int indent = 0;
5649 const auto docAutoList = std::get_if<DocAutoList>(n);
5650 if (docAutoList) // capture indent
5651 {
5652 indent = docAutoList->indent();
5653 }
5654 else
5655 {
5656 return false;
5657 }
5658
5659 // step 3
5660 n = parent(n);
5661 const auto docPara = std::get_if<DocPara>(n);
5662 if (docPara)
5663 {
5664 QCString tagNameLower = QCString(parser->context.token->name).lower();
5665 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5666 {
5667 return std::get<DocStyleChange>(*stack.top());
5668 };
5669
5670 if (parser->context.styleStack.empty() || // no style change
5671 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5672 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5673 )
5674 {
5675 // insert an artificial 'end of autolist' marker and parse again
5676 QCString indentStr;
5677 indentStr.fill(' ',indent);
5678 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5679 return true;
5680 }
5681 }
5682 return false;
5683}
5684
5686{
5687 AUTO_TRACE();
5688 auto ns = AutoNodeStack(parser(),thisVariant());
5689 // handle style commands "inherited" from the previous paragraph
5691 Token tok=parser()->tokenizer.lex();
5692 Token retval = Token::make_TK_NONE();
5693 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5694 {
5695reparsetoken:
5696 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5697 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5698 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5699 )
5700 {
5701 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5702 }
5703 switch(tok.value())
5704 {
5705 case TokenRetval::TK_WORD:
5707 break;
5708 case TokenRetval::TK_LNKWORD:
5710 break;
5711 case TokenRetval::TK_URL:
5713 break;
5714 case TokenRetval::TK_WHITESPACE:
5715 {
5716 // prevent leading whitespace and collapse multiple whitespace areas
5717 if (insidePRE(thisVariant()) || // all whitespace is relevant
5718 (
5719 // remove leading whitespace
5720 !children().empty() &&
5721 // and whitespace after certain constructs
5725 )
5726 )
5727 {
5729 }
5730 }
5731 break;
5732 case TokenRetval::TK_LISTITEM:
5733 {
5734 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5735 const DocNodeVariant *n=parent();
5736 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5737 const DocAutoList *al = std::get_if<DocAutoList>(n);
5738 if (al) // we found an auto list up in the hierarchy
5739 {
5740 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5741 if (al->indent()>=parser()->context.token->indent)
5742 // new item at the same or lower indent level
5743 {
5744 retval = Token::make_TK_LISTITEM();
5745 goto endparagraph;
5746 }
5747 }
5748
5749 // determine list depth
5750 int depth = 0;
5751 n=parent();
5752 while (n)
5753 {
5754 al = std::get_if<DocAutoList>(n);
5755 if (al && al->isEnumList()) depth++;
5756 n=::parent(n);
5757 }
5758
5759 // first item or sub list => create new list
5760 do
5761 {
5764 parser()->context.token->isEnumList,depth,
5766 al = children().get_last<DocAutoList>();
5767 retval = children().get_last<DocAutoList>()->parse();
5768 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5769 al->indent()==parser()->context.token->indent // at same indent level
5770 );
5771
5772 // check the return value
5773 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5774 {
5775 // Reparse the token that ended the section at this level,
5776 // so a new simple section will be started at this level.
5777 // This is the same as unputting the last read token and continuing.
5779 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5780 {
5783 tok = Token::make_TK_RCSTAG();
5784 }
5785 else // other section
5786 {
5787 tok = Token::make_TK_COMMAND_BS();
5788 }
5789 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5790 goto reparsetoken;
5791 }
5792 else if (retval.is(TokenRetval::TK_ENDLIST))
5793 {
5794 if (al->indent()>parser()->context.token->indent) // end list
5795 {
5796 goto endparagraph;
5797 }
5798 else // continue with current paragraph
5799 {
5800 }
5801 }
5802 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5803 {
5804 goto endparagraph;
5805 }
5806 }
5807 break;
5808 case TokenRetval::TK_ENDLIST:
5809 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5810 if (std::get_if<DocAutoListItem>(parent()))
5811 {
5812 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5813 if (al && al->indent()>=parser()->context.token->indent)
5814 {
5815 // end of list marker ends this paragraph
5816 retval = Token::make_TK_ENDLIST();
5817 goto endparagraph;
5818 }
5819 else
5820 {
5821 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5822 "has invalid indent level");
5823 }
5824 }
5825 else
5826 {
5827 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5828 "list items");
5829 }
5830 break;
5831 case TokenRetval::TK_COMMAND_AT:
5832 // fall through
5833 case TokenRetval::TK_COMMAND_BS:
5834 {
5835 // see if we have to start a simple section
5836 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5837 const DocNodeVariant *n=parent();
5838 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5839 !std::holds_alternative<DocParamSect>(*n))
5840 {
5841 n=::parent(n);
5842 }
5844 {
5845 if (n) // already in a simple section
5846 {
5847 // simple section cannot start in this paragraph, need
5848 // to unwind the stack and remember the command.
5850 retval = Token::make_RetVal_SimpleSec();
5851 goto endparagraph;
5852 }
5853 }
5854 // see if we are in a simple list
5855 n=parent();
5856 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5857 if (n)
5858 {
5859 if (cmd==CommandType::CMD_LI)
5860 {
5861 retval = Token::make_RetVal_ListItem();
5862 goto endparagraph;
5863 }
5864 }
5865
5866 // handle the command
5867 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5868 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5869
5870 // check the return value
5871 if (retval.is(TokenRetval::RetVal_SimpleSec))
5872 {
5873 // Reparse the token that ended the section at this level,
5874 // so a new simple section will be started at this level.
5875 // This is the same as unputting the last read token and continuing.
5877 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5878 {
5881 tok = Token::make_TK_RCSTAG();
5882 }
5883 else // other section
5884 {
5885 tok = Token::make_TK_COMMAND_BS();
5886 }
5887 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5888 goto reparsetoken;
5889 }
5890 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5891 {
5892 // the command ended with a new command, reparse this token
5893 tok = retval;
5894 goto reparsetoken;
5895 }
5896 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5897 // or some auto list marker
5898 {
5899 goto endparagraph;
5900 }
5901 }
5902 break;
5903 case TokenRetval::TK_HTMLTAG:
5904 {
5905 if (!parser()->context.token->endTag) // found a start tag
5906 {
5907 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5908 }
5909 else // found an end tag
5910 {
5912 {
5913 break; // new code has been pushed back to the scanner, need to reparse
5914 }
5915 retval = handleHtmlEndTag(parser()->context.token->name);
5916 }
5917 if (!retval.is(TokenRetval::RetVal_OK))
5918 {
5919 goto endparagraph;
5920 }
5921 }
5922 break;
5923 case TokenRetval::TK_SYMBOL:
5924 {
5925 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5927 {
5929 }
5930 else
5931 {
5933 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5934 parser()->context.token->name);
5935 }
5936 break;
5937 }
5938 case TokenRetval::TK_NEWPARA:
5939 retval = Token::make_TK_NEWPARA();
5940 goto endparagraph;
5941 case TokenRetval::TK_RCSTAG:
5942 {
5943 const DocNodeVariant *n=parent();
5944 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5945 !std::holds_alternative<DocParamSect>(*n))
5946 {
5947 n=::parent(n);
5948 }
5949 if (n) // already in a simple section
5950 {
5951 // simple section cannot start in this paragraph, need
5952 // to unwind the stack and remember the command.
5955 retval = Token::make_RetVal_SimpleSec();
5956 goto endparagraph;
5957 }
5958
5959 // see if we are in a simple list
5961 children().get_last<DocSimpleSect>()->parseRcs();
5962 }
5963 break;
5964 default:
5965 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5966 "Found unexpected token (id={})",tok.to_string());
5967 break;
5968 }
5969 tok=parser()->tokenizer.lex();
5970 }
5971 retval=Token::make_TK_NONE();
5972endparagraph:
5974 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5975 if (!parser()->context.token->endTag && par &&
5976 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5977 {
5978 par->setAttribs(parser()->context.token->attribs);
5979 }
5980 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
5981 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
5982 );
5983
5984 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5985 return retval;
5986}
5987
5988//--------------------------------------------------------------------------
5989
5991{
5992 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
5993 Token retval = Token::make_RetVal_OK();
5994 auto ns = AutoNodeStack(parser(),thisVariant());
5995
5996 if (!m_id.isEmpty())
5997 {
5999 if (sec)
6000 {
6001 m_file = sec->fileName();
6002 m_anchor = sec->label();
6003 QCString titleStr = sec->title();
6004 if (titleStr.isEmpty()) titleStr = sec->label();
6006 DocTitle *title = &std::get<DocTitle>(*m_title);
6007 title->parseFromString(thisVariant(),titleStr);
6008 }
6009 }
6010
6011 // first parse any number of paragraphs
6012 bool isFirst=TRUE;
6013 DocPara *lastPar=nullptr;
6014 do
6015 {
6017 DocPara *par = children().get_last<DocPara>();
6018 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6019 retval=par->parse();
6020 if (!par->isEmpty())
6021 {
6022 if (lastPar) lastPar->markLast(FALSE);
6023 lastPar = par;
6024 }
6025 else
6026 {
6027 children().pop_back();
6028 }
6029 if (retval.is(TokenRetval::TK_LISTITEM))
6030 {
6031 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6032 }
6033 if (retval.is(TokenRetval::RetVal_Internal))
6034 {
6036 retval = children().get_last<DocInternal>()->parse(m_level+1);
6037 if (retval.is(TokenRetval::RetVal_EndInternal))
6038 {
6039 retval = Token::make_RetVal_OK();
6040 }
6041 }
6042 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6043 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
6044 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
6045 );
6046
6047 if (lastPar) lastPar->markLast();
6048
6049 while (true)
6050 {
6051 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
6052 {
6053 // then parse any number of nested sections
6054 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
6055 {
6057 2,
6059 retval = children().get_last<DocSection>()->parse();
6060 }
6061 break;
6062 }
6063 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
6064 {
6065 if ((m_level <= 1) &&
6066 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6067 {
6068 warn_doc_error(parser()->context.fileName,
6069 parser()->tokenizer.getLineNr(),
6070 "Unexpected subsubsection command found inside {}!",
6072 }
6073 // then parse any number of nested sections
6074 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
6075 {
6077 3,
6079 retval = children().get_last<DocSection>()->parse();
6080 }
6081 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
6082 }
6083 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
6084 {
6085 if ((m_level <= 2) &&
6086 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6087 {
6088 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6089 "Unexpected paragraph command found inside {}!",
6091 }
6092 // then parse any number of nested sections
6093 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
6094 {
6096 4,
6098 retval = children().get_last<DocSection>()->parse();
6099 }
6100 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
6101 }
6102 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
6103 {
6104 if ((m_level <= 3) &&
6105 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6106 {
6107 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6108 "Unexpected subparagraph command found inside {}!",
6110 }
6111 // then parse any number of nested sections
6112 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
6113 {
6115 5,
6117 retval = children().get_last<DocSection>()->parse();
6118 }
6119 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
6120 }
6121 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
6122 {
6123 if ((m_level <= 4) &&
6124 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6125 {
6126 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6127 "Unexpected subsubparagraph command found inside {}!",
6129 }
6130 // then parse any number of nested sections
6131 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
6132 {
6134 6,
6136 retval = children().get_last<DocSection>()->parse();
6137 }
6138 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
6139 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
6140 }
6141 else
6142 {
6143 break;
6144 }
6145 }
6146
6147 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
6148 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6149 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
6150 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
6151 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
6152 );
6153
6154 AUTO_TRACE_EXIT("retval={}", retval.to_string());
6155 return retval;
6156}
6157
6158//--------------------------------------------------------------------------
6159
6161{
6162 AUTO_TRACE();
6163 auto ns = AutoNodeStack(parser(),thisVariant());
6165
6166 Token tok = parser()->tokenizer.lex();
6167 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
6168 {
6169 switch(tok.value())
6170 {
6171 case TokenRetval::TK_WORD:
6173 break;
6174 case TokenRetval::TK_WHITESPACE:
6176 break;
6177 case TokenRetval::TK_SYMBOL:
6178 {
6179 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
6181 {
6183 }
6184 else
6185 {
6186 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
6187 parser()->context.token->name);
6188 }
6189 }
6190 break;
6191 case TokenRetval::TK_COMMAND_AT:
6192 // fall through
6193 case TokenRetval::TK_COMMAND_BS:
6194 switch (Mappers::cmdMapper->map(parser()->context.token->name))
6195 {
6198 break;
6201 break;
6204 break;
6207 break;
6210 break;
6213 break;
6216 break;
6219 break;
6222 break;
6226 break;
6231 break;
6234 break;
6237 break;
6240 break;
6243 break;
6246 break;
6249 break;
6252 break;
6253 default:
6254 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6255 parser()->context.token->name);
6256 break;
6257 }
6258 break;
6259 default:
6260 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6261 tok.to_string());
6262 break;
6263 }
6264 tok = parser()->tokenizer.lex();
6265 }
6266
6268
6269}
6270
6271
6272//--------------------------------------------------------------------------
6273
6275{
6276 AUTO_TRACE();
6277 auto ns = AutoNodeStack(parser(),thisVariant());
6279 Token retval = Token::make_TK_NONE();
6280
6281 // first parse any number of paragraphs
6282 bool isFirst=TRUE;
6283 DocPara *lastPar = nullptr;
6284 do
6285 {
6286 {
6288 DocPara *par = children().get_last<DocPara>();
6289 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6290 retval=par->parse();
6291 if (par->isEmpty() && par->attribs().empty())
6292 {
6293 children().pop_back();
6294 }
6295 else
6296 {
6297 lastPar = par;
6298 }
6299 }
6300 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6301 if (retval == t)
6302 {
6303 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6304 {
6305 warn_doc_error(parser()->context.fileName,
6306 parser()->tokenizer.getLineNr(),
6307 "found {} command (id: '{}') outside of {} context!",
6308 sectionType,parser()->context.token->sectionId,parentSectionType);
6309 }
6310 while (retval==t)
6311 {
6312 if (!parser()->context.token->sectionId.isEmpty())
6313 {
6314 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6315 if (sec)
6316 {
6318 level,
6320 retval = children().get_last<DocSection>()->parse();
6321 }
6322 else
6323 {
6324 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6325 sectionType,parser()->context.token->sectionId,sectionType);
6326 retval = Token::make_TK_NONE();
6327 }
6328 }
6329 else
6330 {
6331 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6332 retval = Token::make_TK_NONE();
6333 }
6334 }
6335 }
6336 };
6337 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6338 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6339 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6340 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6341 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6342
6343 if (retval.is(TokenRetval::TK_LISTITEM))
6344 {
6345 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6346 }
6347 if (retval.is(TokenRetval::RetVal_Internal))
6348 {
6350 retval = children().get_last<DocInternal>()->parse(1);
6351 }
6352 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6353 if (lastPar) lastPar->markLast();
6354
6355 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6356 // then parse any number of level1 sections
6357 while (retval.is(TokenRetval::RetVal_Section))
6358 {
6359 if (!parser()->context.token->sectionId.isEmpty())
6360 {
6361 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6362 if (sec)
6363 {
6365 1,
6367 retval = children().get_last<DocSection>()->parse();
6368 }
6369 else
6370 {
6371 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6372 retval = Token::make_TK_NONE();
6373 }
6374 }
6375 else
6376 {
6377 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6378 retval = Token::make_TK_NONE();
6379 }
6380 }
6381
6383}
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:3445
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3923
void handleInheritDoc()
Definition docnode.cpp:4154
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3498
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3439
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3964
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4191
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3634
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4069
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3884
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3475
void markLast(bool v=TRUE)
Definition docnode.h:1086
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4942
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3603
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3824
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:5685
void handleVhdlFlow()
Definition docnode.cpp:3916
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:4100
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3754
bool m_isLast
Definition docnode.h:1116
Token handleXRefItem()
Definition docnode.cpp:3732
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5412
Token handleStartCode()
Definition docnode.cpp:4118
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:4111
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:3328
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:3396
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:6274
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:5990
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:6160
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:126
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:704
static FormulaManager & instance()
Definition formula.cpp:53
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:4926
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:5633
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:1966
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:91
DocStyleChangeStack styleStack
Definition docparser_p.h:68
size_t includeFileLength
Definition docparser_p.h:89
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:81
const Definition * scope
Definition docparser_p.h:61
QCString includeFileText
Definition docparser_p.h:87
TokenInfo * token
Definition docparser_p.h:94
QCString includeFileName
Definition docparser_p.h:86
size_t includeFileOffset
Definition docparser_p.h:88
const MemberDef * memberDef
Definition docparser_p.h:79
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:2698
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5214
QCString stripIndentation(const QCString &s, bool skipFirstLine)
Definition util.cpp:5972
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3022
QCString stripScope(const QCString &name)
Definition util.cpp:3783
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, SrcLangExt lang, const QCString &prefix)
Definition util.cpp:2724
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3508
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:6641
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5033
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:2894
A bunch of utility functions.