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