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 (resolveLink(context,target,true,&compound,anchor,lang,parser->context.prefix))
761 {
762 bool isFile = compound ?
763 (compound->definitionType()==Definition::TypeFile ||
765 FALSE;
766 m_text = linkToText(lang,target,isFile);
768 if (compound && compound->isLinkable()) // ref to compound
769 {
770 if (anchor.isEmpty() && /* compound link */
771 compound->definitionType()==Definition::TypeGroup && /* is group */
772 !toGroupDef(compound)->groupTitle().isEmpty() /* with title */
773 )
774 {
775 m_text=(toGroupDef(compound))->groupTitle(); // use group's title as link
776 }
777 else if (compound->definitionType()==Definition::TypeMember &&
778 toMemberDef(compound)->isObjCMethod())
779 {
780 // Objective C Method
781 const MemberDef *member = toMemberDef(compound);
782 bool localLink = parser->context.memberDef ? member->getClassDef()==parser->context.memberDef->getClassDef() : FALSE;
783 m_text = member->objCMethodName(localLink,parser->context.inSeeBlock);
784 }
785 else if (Config_getBool(HIDE_SCOPE_NAMES))
786 {
788 }
789
790 m_file = compound->getOutputFileBase();
791 m_ref = compound->getReference();
792 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
793 // compound->definitionType());
794 AUTO_TRACE_EXIT("compound");
795 return;
796 }
797 else if (compound && compound->definitionType()==Definition::TypeFile &&
798 toFileDef(compound)->generateSourceFile()
799 ) // undocumented file that has source code we can link to
800 {
801 m_file = compound->getSourceFileBase();
802 m_ref = compound->getReference();
803 AUTO_TRACE_EXIT("source");
804 return;
805 }
806 else
807 {
808 AUTO_TRACE_EXIT("compound '{}' not linkable",compound?compound->name():"none");
809 }
810 }
811 m_text = target;
812 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\ref command",
813 target);
814}
815
817{
818 for (auto &&elem : elements)
819 {
820 emplace_back(std::move(elem));
821 }
822 elements.clear();
823}
824
825static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
826{
827 DocNodeList newChildren;
828 for (auto &dn : children)
829 {
830 DocPara *para = std::get_if<DocPara>(&dn);
831 if (para)
832 {
833 //// move the children of the paragraph to the end of the newChildren list
834 newChildren.move_append(para->children());
835 }
836 }
837
838 // replace the children list by the newChildren list
839 children.clear();
840 children.move_append(newChildren);
841 // reparent the children
842 for (auto &cn : children)
843 {
844 setParent(&cn,root);
845 // we also need to set the parent for each child of cn, as cn's address may have changed.
846 auto opt_children = call_method_children(&cn);
847 if (opt_children)
848 {
849 for (auto &ccn : *opt_children)
850 {
851 setParent(&ccn,&cn);
852 }
853 }
854 }
855}
856
858{
859 AUTO_TRACE();
860 auto ns = AutoNodeStack(parser(),thisVariant());
861
862 Token tok = parser()->tokenizer.lex();
863 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
864 {
865 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
866 {
867 switch (tok.value())
868 {
869 case TokenRetval::TK_HTMLTAG:
870 break;
871 default:
873 break;
874 }
875 }
876 tok=parser()->tokenizer.lex();
877 }
878
879 if (children().empty() && !m_text.isEmpty())
880 {
881 QCString text = m_text;
882 if (parser()->context.insideHtmlLink)
883 {
884 // we already in a link/title only output anchor
885 text = m_anchor;
886 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
887 "Potential recursion while resolving \\ref command!");
888 }
890 parser()->pushContext();
892 parser()->popContext();
896 }
897
899}
900
901//---------------------------------------------------------------------------
902
904{
905 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
906 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
907 ASSERT(!target.isEmpty());
908 m_relPath = parser->context.relPath;
910 const CiteInfo *cite = ct.find(target);
911 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
912 m_option = opt;
914 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
915 {
916 m_ref = "";
917 m_anchor = ct.anchorPrefix()+cite->label();
919 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
920 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
921 return;
922 }
923 if (numBibFiles==0)
924 {
925 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
926 }
927 else if (cite==nullptr)
928 {
929 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '{}' for \\cite command",
930 target);
931 }
932 else
933 {
934 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '{}' does not have an associated number",
935 target);
936 }
937}
938
940{
941 QCString txt;
942 auto opt = m_option;
944 const CiteInfo *citeInfo = ct.find(m_target);
945
946 if (!opt.noPar()) txt += "[";
947
948 if (citeInfo)
949 {
950 if (opt.isNumber()) txt += citeInfo->text();
951 else if (opt.isShortAuthor()) txt += citeInfo->shortAuthor();
952 else if (opt.isYear()) txt += citeInfo->year();
953 }
954
955 if (!opt.noPar()) txt += "]";
956 return txt;
957}
958
959
960//---------------------------------------------------------------------------
961
963{
964 const Definition *compound = nullptr;
966 m_refText = target;
967 m_relPath = parser->context.relPath;
968 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
969 {
970 m_refText = m_refText.right(m_refText.length()-1);
971 }
972 if (resolveLink(parser->context.context,stripKnownExtensions(target),
973 parser->context.inSeeBlock,&compound,anchor,
974 parser->context.lang,parser->context.prefix))
975 {
976 m_anchor = anchor;
977 if (compound && compound->isLinkable())
978 {
979 m_file = compound->getOutputFileBase();
980 m_ref = compound->getReference();
981 }
982 else if (compound && compound->definitionType()==Definition::TypeFile &&
983 (toFileDef(compound))->generateSourceFile()
984 ) // undocumented file that has source code we can link to
985 {
986 m_file = compound->getSourceFileBase();
987 m_ref = compound->getReference();
988 }
989 return;
990 }
991
992 // bogus link target
993 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '{}' for \\link command",
994 target);
995}
996
997
998QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
999{
1000 AUTO_TRACE();
1001 QCString result;
1002 auto ns = AutoNodeStack(parser(),thisVariant());
1003
1004 Token tok = parser()->tokenizer.lex();
1005 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1006 {
1007 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
1008 {
1009 switch (tok.value())
1010 {
1011 case TokenRetval::TK_COMMAND_AT:
1012 // fall through
1013 case TokenRetval::TK_COMMAND_BS:
1014 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1015 {
1017 if (isJavaLink)
1018 {
1019 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{{@link...' ended with '{:c}{}' command",
1020 tok.command_to_char(),parser()->context.token->name);
1021 }
1022 goto endlink;
1023 default:
1024 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' as part of a \\link",
1025 tok.command_to_char(),parser()->context.token->name);
1026 break;
1027 }
1028 break;
1029 case TokenRetval::TK_SYMBOL:
1030 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a \\link",
1031 parser()->context.token->name);
1032 break;
1033 case TokenRetval::TK_HTMLTAG:
1034 if (parser()->context.token->name!="see" || !isXmlLink)
1035 {
1036 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command {} found as part of a \\link",
1037 parser()->context.token->name);
1038 }
1039 goto endlink;
1040 case TokenRetval::TK_LNKWORD:
1041 case TokenRetval::TK_WORD:
1042 if (isJavaLink) // special case to detect closing }
1043 {
1045 int p = 0;
1046 if (w=="}")
1047 {
1048 goto endlink;
1049 }
1050 else if ((p=w.find('}'))!=-1)
1051 {
1052 int l = static_cast<int>(w.length());
1054 if (p<l-1) // something left after the } (for instance a .)
1055 {
1056 result=w.right(l-p-1);
1057 }
1058 goto endlink;
1059 }
1060 }
1062 break;
1063 default:
1064 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",tok.to_string());
1065 break;
1066 }
1067 }
1068 tok = parser()->tokenizer.lex();
1069 }
1070 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1071 {
1072 warn_doc_error(parser()->context.fileName,
1073 parser()->tokenizer.getLineNr(),
1074 "Unexpected end of comment while inside link command");
1075 }
1076endlink:
1077
1078 if (children().empty()) // no link text
1079 {
1081 }
1082
1084 return result;
1085}
1086
1087
1088//---------------------------------------------------------------------------
1089
1096
1098{
1099 bool ok = false;
1101
1102 bool ambig = false;
1104 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1105 {
1106 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1107 }
1108 if (fd)
1109 {
1110 p->file = fd->absFilePath();
1111 ok = true;
1112 if (ambig)
1113 {
1114 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '{}' is ambiguous.\n"
1115 "Possible candidates:\n{}",p->name,
1117 );
1118 }
1119 }
1120 else
1121 {
1122 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '{}' is not found "
1123 "in any of the paths specified via DOTFILE_DIRS!",p->name);
1124 }
1125 return ok;
1126}
1127
1134
1136{
1137 bool ok = false;
1139
1140 bool ambig = false;
1142 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1143 {
1144 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1145 }
1146 if (fd)
1147 {
1148 p->file = fd->absFilePath();
1149 ok = true;
1150 if (ambig)
1151 {
1152 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '{}' is ambiguous.\n"
1153 "Possible candidates:\n{}",qPrint(p->name),
1155 );
1156 }
1157 }
1158 else
1159 {
1160 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '{}' is not found "
1161 "in any of the paths specified via MSCFILE_DIRS!",p->name);
1162 }
1163 return ok;
1164}
1165
1166//---------------------------------------------------------------------------
1167
1174
1176{
1177 bool ok = false;
1179
1180 bool ambig = false;
1182 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1183 {
1184 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
1185 }
1186 if (fd)
1187 {
1188 p->file = fd->absFilePath();
1189 ok = true;
1190 if (ambig)
1191 {
1192 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file name '{}' is ambiguous.\n"
1193 "Possible candidates:\n{}",p->name,
1195 );
1196 }
1197 }
1198 else
1199 {
1200 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file '{}' is not found "
1201 "in any of the paths specified via DIAFILE_DIRS!",p->name);
1202 }
1203 return ok;
1204}
1205//---------------------------------------------------------------------------
1206
1213
1215{
1216 bool ok = false;
1218
1219 bool ambig = false;
1221 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1222 {
1223 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1224 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1225 {
1226 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1227 }
1228 }
1229 if (fd)
1230 {
1231 p->file = fd->absFilePath();
1232 ok = true;
1233 if (ambig)
1234 {
1235 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '{}' is ambiguous.\n"
1236 "Possible candidates:\n{}",p->name,
1238 );
1239 }
1240 }
1241 else
1242 {
1243 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '{}' is not found "
1244 "in any of the paths specified via PLANTUMLFILE_DIRS!",p->name);
1245 }
1246 return ok;
1247}
1248
1249//---------------------------------------------------------------------------
1250
1254
1256{
1257 AUTO_TRACE();
1258 auto ns = AutoNodeStack(parser(),thisVariant());
1259
1261 Token tok = parser()->tokenizer.lex();
1262 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1263 {
1264 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1265 {
1266 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1267 }
1268 tok = parser()->tokenizer.lex();
1269 }
1270 parser()->tokenizer.lex();
1271
1274
1275 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1276}
1277
1278
1279//---------------------------------------------------------------------------
1280
1282 Type t,const QCString &url, bool inlineImage) :
1283 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1284{
1285}
1286
1288{
1289 QCString locName = p->url.isEmpty() ? p->name : p->url;
1290 int len = static_cast<int>(locName.length());
1291 int fnd = locName.find('?'); // ignore part from ? until end
1292 if (fnd==-1) fnd=len;
1293 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1294}
1295
1300
1301
1302//---------------------------------------------------------------------------
1303
1305{
1306 AUTO_TRACE();
1307 Token retval(TokenRetval::RetVal_OK);
1308 auto ns = AutoNodeStack(parser(),thisVariant());
1309
1310 Token tok = parser()->tokenizer.lex();
1311 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1312 {
1313 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1314 {
1315 switch (tok.value())
1316 {
1317 case TokenRetval::TK_HTMLTAG:
1318 {
1319 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1320 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1321 {
1322 if (m_level!=1)
1323 {
1324 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h1>",
1325 m_level);
1326 }
1327 goto endheader;
1328 }
1329 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1330 {
1331 if (m_level!=2)
1332 {
1333 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h2>",
1334 m_level);
1335 }
1336 goto endheader;
1337 }
1338 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1339 {
1340 if (m_level!=3)
1341 {
1342 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h3>",
1343 m_level);
1344 }
1345 goto endheader;
1346 }
1347 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1348 {
1349 if (m_level!=4)
1350 {
1351 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h4>",
1352 m_level);
1353 }
1354 goto endheader;
1355 }
1356 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1357 {
1358 if (m_level!=5)
1359 {
1360 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h5>",
1361 m_level);
1362 }
1363 goto endheader;
1364 }
1365 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1366 {
1367 if (m_level!=6)
1368 {
1369 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h{:d}> ended with </h6>",
1370 m_level);
1371 }
1372 goto endheader;
1373 }
1374 else if (tagId==HtmlTagType::HTML_A)
1375 {
1376 if (!parser()->context.token->endTag)
1377 {
1378 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1379 }
1380 }
1381 else if (tagId==HtmlTagType::HTML_BR)
1382 {
1384 }
1385 else
1386 {
1387 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <h{:d}> context",
1388 parser()->context.token->endTag?"/":"",parser()->context.token->name,m_level);
1389 }
1390 }
1391 break;
1392 default:
1393 char tmp[20];
1394 qsnprintf(tmp,20,"<h%d> tag",m_level);
1396 }
1397 }
1398 tok = parser()->tokenizer.lex();
1399 }
1400 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1401 {
1402 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1403 " <h{:d}> tag",m_level);
1404 }
1405endheader:
1407 return retval;
1408}
1409//---------------------------------------------------------------------------
1410
1412{
1413 AUTO_TRACE();
1414 auto ns = AutoNodeStack(parser(),thisVariant());
1416 Token tok = parser()->tokenizer.lex();
1417 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1418 {
1420 // check of </summary>
1421 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1422 (tagId=Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1423 parser()->context.token->endTag
1424 )
1425 {
1426 break;
1427 }
1428 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1429 {
1430 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1431 }
1432 tok = parser()->tokenizer.lex();
1433 }
1435 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1436 {
1437 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1438 " <summary> tag");
1439 }
1440}
1441
1442//---------------------------------------------------------------------------
1443
1445{
1446 AUTO_TRACE();
1447 Token retval(TokenRetval::TK_NONE);
1448 auto ns = AutoNodeStack(parser(),thisVariant());
1449
1450 // parse one or more paragraphs
1451 bool isFirst=TRUE;
1452 DocPara *par=nullptr;
1453 do
1454 {
1456 par = children().get_last<DocPara>();
1457 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1458 retval=par->parse();
1459 }
1460 while (retval.is(TokenRetval::TK_NEWPARA));
1461 if (par) par->markLast();
1462
1463 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1464 {
1465 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1466 }
1467
1468 if (!summary())
1469 {
1470 HtmlAttribList summaryAttribs;
1472 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1473 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1474 }
1475 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1476 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1477}
1478
1486
1487//---------------------------------------------------------------------------
1488
1490{
1491 AUTO_TRACE();
1492 Token retval(TokenRetval::RetVal_OK);
1493 auto ns = AutoNodeStack(parser(),thisVariant());
1494
1495 Token tok = parser()->tokenizer.lex();
1496 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1497 {
1498 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1499 {
1500 switch (tok.value())
1501 {
1502 case TokenRetval::TK_HTMLTAG:
1503 {
1504 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1505 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1506 {
1507 goto endhref;
1508 }
1509 else if (tagId==HtmlTagType::HTML_BR)
1510 {
1512 }
1513 else
1514 {
1515 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <a href=...> context",
1516 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1517 }
1518 }
1519 break;
1520 default:
1521 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1522 break;
1523 }
1524 }
1525 tok = parser()->tokenizer.lex();
1526 }
1527 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1528 {
1529 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1530 " <a href=...> tag");
1531 }
1532endhref:
1534 return retval;
1535}
1536
1537//---------------------------------------------------------------------------
1538
1540{
1541 AUTO_TRACE();
1542 Token retval(TokenRetval::RetVal_OK);
1543 auto ns = AutoNodeStack(parser(),thisVariant());
1544
1545 // first parse any number of paragraphs
1546 bool isFirst=TRUE;
1547 DocPara *lastPar=nullptr;
1548 do
1549 {
1551 DocPara *par = children().get_last<DocPara>();
1552 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1553 retval=par->parse();
1554 if (!par->isEmpty())
1555 {
1556 if (lastPar) lastPar->markLast(FALSE);
1557 lastPar=par;
1558 }
1559 else
1560 {
1561 children().pop_back();
1562 }
1563 if (retval.is(TokenRetval::TK_LISTITEM))
1564 {
1565 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1566 }
1567 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1568 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1569 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1570 TokenRetval::RetVal_EndInternal));
1571 if (lastPar) lastPar->markLast();
1572
1573 // then parse any number of level-n sections
1574 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1575 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1576 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1577 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1578 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1579 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1580 )
1581 {
1583 level,
1585 retval = children().get_last<DocSection>()->parse();
1586 }
1587
1588 if (retval.is(TokenRetval::RetVal_Internal))
1589 {
1590 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1591 }
1592
1593 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1594 return retval;
1595}
1596
1597//---------------------------------------------------------------------------
1598
1600{
1601 AUTO_TRACE();
1602 Token retval(TokenRetval::RetVal_OK);
1603 auto ns = AutoNodeStack(parser(),thisVariant());
1604 Token tok=parser()->tokenizer.lex();
1605 if (!tok.is(TokenRetval::TK_WHITESPACE))
1606 {
1607 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1608 goto endindexentry;
1609 }
1611 m_entry="";
1612 tok = parser()->tokenizer.lex();
1613 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1614 {
1615 switch (tok.value())
1616 {
1617 case TokenRetval::TK_WHITESPACE:
1618 m_entry+=" ";
1619 break;
1620 case TokenRetval::TK_WORD:
1621 case TokenRetval::TK_LNKWORD:
1623 break;
1624 case TokenRetval::TK_SYMBOL:
1625 {
1626 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1627 switch (s)
1628 {
1629 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1630 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1631 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1632 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1633 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1634 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1635 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1636 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1637 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1638 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1639 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1640 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1641 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1642 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1643 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1644 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1645 default:
1646 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '{}' found as argument of \\addindex",parser()->context.token->name);
1647 break;
1648 }
1649 }
1650 break;
1651 case TokenRetval::TK_COMMAND_AT:
1652 // fall through
1653 case TokenRetval::TK_COMMAND_BS:
1654 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1655 {
1656 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1657 case CommandType::CMD_AT: m_entry+='@'; break;
1658 case CommandType::CMD_LESS: m_entry+='<'; break;
1659 case CommandType::CMD_GREATER: m_entry+='>'; break;
1660 case CommandType::CMD_AMP: m_entry+='&'; break;
1661 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1662 case CommandType::CMD_HASH: m_entry+='#'; break;
1663 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1664 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1665 case CommandType::CMD_NDASH: m_entry+="--"; break;
1666 case CommandType::CMD_MDASH: m_entry+="---"; break;
1667 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1668 case CommandType::CMD_PUNT: m_entry+='.'; break;
1669 case CommandType::CMD_PLUS: m_entry+='+'; break;
1670 case CommandType::CMD_MINUS: m_entry+='-'; break;
1671 case CommandType::CMD_EQUAL: m_entry+='='; break;
1672 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1673 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1674 default:
1675 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command {} found as argument of \\addindex",
1676 parser()->context.token->name);
1677 break;
1678 }
1679 break;
1680 default:
1681 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
1682 tok.to_string());
1683 break;
1684 }
1685 tok = parser()->tokenizer.lex();
1686 }
1688 m_entry = m_entry.stripWhiteSpace();
1689endindexentry:
1690 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1691 return retval;
1692}
1693
1694//---------------------------------------------------------------------------
1695
1698{
1700 for (const auto &opt : attribs)
1701 {
1702 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1703 {
1704 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1705 if (sec)
1706 {
1707 //printf("Found anchor %s\n",qPrint(id));
1708 m_file = sec->fileName();
1709 m_anchor = sec->label();
1711 }
1712 else
1713 {
1714 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '{}'",opt.value);
1715 }
1716 }
1717 else // copy attribute
1718 {
1719 m_attribs.push_back(opt);
1720 }
1721 }
1722}
1723
1725{
1726 AUTO_TRACE();
1727 Token retval = Token::make_TK_NONE();
1728 auto ns = AutoNodeStack(parser(),thisVariant());
1729 Token tok = parser()->tokenizer.lex();
1730 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1731 {
1732 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1733 {
1734 switch (tok.value())
1735 {
1736 case TokenRetval::TK_HTMLTAG:
1737 {
1738 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1739 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1740 {
1741 retval = Token::make_RetVal_OK();
1742 goto endcaption;
1743 }
1744 else
1745 {
1746 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <caption> context",
1747 parser()->context.token->endTag?"/":"",parser()->context.token->name);
1748 }
1749 }
1750 break;
1751 default:
1752 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1753 break;
1754 }
1755 }
1756 tok = parser()->tokenizer.lex();
1757 }
1758 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1759 {
1760 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1761 " <caption> tag");
1762 }
1763endcaption:
1765 return retval;
1766}
1767
1768//---------------------------------------------------------------------------
1769
1771{
1772 AUTO_TRACE();
1773 Token retval = Token::make_RetVal_OK();
1774 auto ns = AutoNodeStack(parser(),thisVariant());
1775
1776 // parse one or more paragraphs
1777 bool isFirst=TRUE;
1778 DocPara *par=nullptr;
1779 do
1780 {
1782 par = children().get_last<DocPara>();
1783 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1784 retval=par->parse();
1785 if (retval.is(TokenRetval::TK_HTMLTAG))
1786 {
1787 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1788 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1789 {
1790 retval = Token::make_TK_NEWPARA(); // ignore the tag
1791 }
1792 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1793 {
1794 retval = Token::make_TK_NEWPARA(); // ignore the tag
1795 }
1796 }
1797 }
1798 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1799 if (par) par->markLast();
1800
1801 return retval;
1802}
1803
1805{
1806 AUTO_TRACE();
1807 Token retval = Token::make_RetVal_OK();
1808 auto ns = AutoNodeStack(parser(),thisVariant());
1809
1810 // parse one or more paragraphs
1811 bool isFirst=TRUE;
1812 DocPara *par=nullptr;
1813 do
1814 {
1816 par = children().get_last<DocPara>();
1817 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1818 retval=par->parse();
1819 if (retval.is(TokenRetval::TK_HTMLTAG))
1820 {
1821 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1822 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1823 {
1824 retval = Token::make_TK_NEWPARA(); // ignore the tag
1825 }
1826 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1827 {
1828 retval = Token::make_TK_NEWPARA(); // ignore the tag
1829 }
1830 }
1831 }
1832 while (retval.is(TokenRetval::TK_NEWPARA));
1833 if (par) par->markLast();
1834
1835 return retval;
1836}
1837
1838uint32_t DocHtmlCell::rowSpan() const
1839{
1840 for (const auto &attr : attribs())
1841 {
1842 if (attr.name.lower()=="rowspan")
1843 {
1844 return attr.value.toUInt();
1845 }
1846 }
1847 return 0;
1848}
1849
1850uint32_t DocHtmlCell::colSpan() const
1851{
1852 for (const auto &attr : attribs())
1853 {
1854 if (attr.name.lower()=="colspan")
1855 {
1856 return std::max(1u,attr.value.toUInt());
1857 }
1858 }
1859 return 1;
1860}
1861
1863{
1864 for (const auto &attr : attribs())
1865 {
1866 QCString attrName = attr.name.lower();
1867 QCString attrValue = attr.value.lower();
1868 if (attrName=="align")
1869 {
1870 if (attrValue=="center")
1871 return Center;
1872 else if (attrValue=="right")
1873 return Right;
1874 else return Left;
1875 }
1876 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1877 {
1878 if (attrValue=="markdowntableheadcenter")
1879 return Center;
1880 else if (attrValue=="markdowntableheadright")
1881 return Right;
1882 else if (attrValue=="markdowntableheadleft")
1883 return Left;
1884 else if (attrValue=="markdowntableheadnone")
1885 return Center;
1886 else if (attrValue=="markdowntablebodycenter")
1887 return Center;
1888 else if (attrValue=="markdowntablebodyright")
1889 return Right;
1890 else if (attrValue=="markdowntablebodyleft")
1891 return Left;
1892 else if (attrValue=="markdowntablebodynone")
1893 return Left;
1894 else return Left;
1895 }
1896 }
1897 return Left;
1898}
1899
1901{
1902 for (const auto &attr : attribs())
1903 {
1904 QCString attrName = attr.name.lower();
1905 QCString attrValue = attr.value.lower();
1906 if (attrName=="valign")
1907 {
1908 if (attrValue=="top")
1909 return Top;
1910 else if (attrValue=="bottom")
1911 return Bottom;
1912 else if (attrValue=="middle")
1913 return Middle;
1914 else return Middle;
1915 }
1916 }
1917 return Middle;
1918}
1919
1920//---------------------------------------------------------------------------
1921
1923{ // a row is a table heading if all cells are marked as such
1924 bool heading=TRUE;
1925 for (const auto &n : children())
1926 {
1927 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1928 if (cell && !cell->isHeading())
1929 {
1930 heading = FALSE;
1931 break;
1932 }
1933 }
1934 return !children().empty() && heading;
1935}
1936
1938{
1939 // get next token
1940 Token tok=parser->tokenizer.lex();
1941 // skip whitespace and tbody, thead and tfoot tags
1942 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA,TokenRetval::TK_HTMLTAG))
1943 {
1944 if (tok.is(TokenRetval::TK_HTMLTAG))
1945 {
1947 // skip over tbody, thead, tfoot tags
1948 if (tagId==HtmlTagType::HTML_TBODY ||
1949 tagId==HtmlTagType::HTML_THEAD ||
1951 {
1952 tok=parser->tokenizer.lex();
1953 }
1954 else
1955 {
1956 break;
1957 }
1958 }
1959 else
1960 {
1961 tok=parser->tokenizer.lex();
1962 }
1963 }
1964 return tok;
1965}
1966
1967
1969{
1970 AUTO_TRACE();
1971 Token retval = Token::make_RetVal_OK();
1972 auto ns = AutoNodeStack(parser(),thisVariant());
1973
1974 bool isHeading=FALSE;
1975 bool isFirst=TRUE;
1976 DocHtmlCell *cell=nullptr;
1977
1979 // should find a html tag now
1980 if (tok.is(TokenRetval::TK_HTMLTAG))
1981 {
1982 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1983 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
1984 {
1985 }
1986 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
1987 {
1989 }
1990 else // found some other tag
1991 {
1992 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
1993 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
1994 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
1995 goto endrow;
1996 }
1997 }
1998 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
1999 {
2000 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2001 " for a html description title");
2002 goto endrow;
2003 }
2004 else // token other than html token
2005 {
2006 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2007 tok.to_string());
2008 goto endrow;
2009 }
2010
2011 // parse one or more cells
2012 do
2013 {
2016 isHeading);
2017 cell = children().get_last<DocHtmlCell>();
2018 cell->markFirst(isFirst);
2019 isFirst=FALSE;
2020 retval=cell->parse();
2021 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
2022 //printf("DocHtmlRow:retval=%s\n",retval.to_string());
2023 if (retval.is(TokenRetval::RetVal_EndTableCell))
2024 {
2025 // get next token
2026 retval = skipSpacesForTable(parser());
2027 //printf("DocHtmlRow:retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2028 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2029 if (tok.is(TokenRetval::TK_HTMLTAG))
2030 {
2031 if ((tagId==HtmlTagType::HTML_TD || tagId==HtmlTagType::HTML_TH) &&
2032 !parser()->context.token->endTag) // found new <td> or <td> tag
2033 {
2034 retval = Token::make_RetVal_TableCell();
2036 }
2037 else if (tagId==HtmlTagType::HTML_TR)
2038 {
2039 if (parser()->context.token->endTag) // found </tr> tag
2040 {
2041 retval = Token::make_RetVal_EndTableRow();
2042 }
2043 else // found <tr> tag
2044 {
2045 retval = Token::make_RetVal_TableRow();
2046 }
2047 }
2048 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag) // found </table>
2049 {
2050 retval = Token::make_RetVal_EndTable();
2051 }
2052 else // found some other tag
2053 {
2054 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but "
2055 "found <{}{}> instead!",parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2056 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2057 goto endrow;
2058 }
2059 }
2060 else // token other than html token
2061 {
2062 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td>, <th> or <tr> tag but found {} token instead!",
2063 tok.to_string());
2064 goto endrow;
2065 }
2066 }
2067 }
2068 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2069 cell->markLast(TRUE);
2070
2071endrow:
2072 return retval;
2073}
2074
2076{
2077 AUTO_TRACE();
2078 Token retval = Token::make_RetVal_OK();
2079 auto ns = AutoNodeStack(parser(),thisVariant());
2080
2081 bool isFirst=TRUE;
2082 DocHtmlCell *cell=nullptr;
2083
2084 // get next token
2085 Token tok=parser()->tokenizer.lex();
2086 // skip whitespace
2087 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2088 // should find a html tag now
2089 if (tok.is(TokenRetval::TK_HTMLTAG))
2090 {
2091 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2092 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
2093 {
2094 }
2095 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
2096 {
2097 }
2098 else // found some other tag
2099 {
2100 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
2101 "found <{}> instead!",parser()->context.token->name);
2102 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2103 goto endrow;
2104 }
2105 }
2106 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2107 {
2108 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2109 " for a html description title");
2110 goto endrow;
2111 }
2112 else // token other than html token
2113 {
2114 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found {} token instead!",
2115 tok.to_string());
2116 goto endrow;
2117 }
2118
2119 do
2120 {
2122 cell = children().get_last<DocHtmlCell>();
2123 cell->markFirst(isFirst);
2124 isFirst=FALSE;
2125 retval=cell->parseXml();
2126 }
2127 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2128 cell->markLast(TRUE);
2129
2130endrow:
2131 return retval;
2132}
2133
2134//---------------------------------------------------------------------------
2135
2137{
2138 return m_caption!=nullptr;
2139}
2140
2142{
2143 return m_caption.get();
2144}
2145
2147{
2148 if (!children().empty() && std::holds_alternative<DocHtmlRow>(children().front()))
2149 {
2150 return &children().front();
2151 }
2152 return nullptr;
2153}
2154
2156{
2157 AUTO_TRACE();
2158 Token retval = Token::make_RetVal_OK();
2159 auto ns = AutoNodeStack(parser(),thisVariant());
2160
2161getrow:
2162 // skip whitespace and tbody, thead and tfoot tags
2164 // should find a html tag now
2165 if (tok.is(TokenRetval::TK_HTMLTAG))
2166 {
2167 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2168 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2169 {
2170 // no caption, just rows
2171 retval = Token::make_RetVal_TableRow();
2172 }
2173 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2174 {
2175 if (m_caption)
2176 {
2177 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2178 }
2179 else
2180 {
2181 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2182 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2183
2184 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2185 {
2186 goto getrow;
2187 }
2188 }
2189 }
2190 else // found wrong token
2191 {
2192 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2193 "found <{}{}> instead!", parser()->context.token->endTag ? "/" : "", parser()->context.token->name);
2194 }
2195 }
2196 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2197 {
2198 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2199 " for a <tr> or <caption> tag");
2200 }
2201 else // token other than html token
2202 {
2203 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found {} token instead!",
2204 tok.to_string());
2205 }
2206
2207 // parse one or more rows
2208 while (retval.is(TokenRetval::RetVal_TableRow))
2209 {
2211 retval = children().get_last<DocHtmlRow>()->parse();
2212 //printf("DocHtmlTable::retval=%s\n",retval.to_string());
2213 if (retval.is(TokenRetval::RetVal_EndTableRow))
2214 {
2215 // get next token
2216 retval = skipSpacesForTable(parser());
2217 //printf("DocHtmlTable::retval= next=%s name=%s endTag=%d\n",retval.to_string(),qPrint(parser()->context.token->name),parser()->context.token->endTag);
2218 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2219 if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag)
2220 {
2221 retval = Token::make_RetVal_TableRow();
2222 }
2223 else if (tagId==HtmlTagType::HTML_TABLE && parser()->context.token->endTag)
2224 {
2225 retval = Token::make_RetVal_EndTable();
2226 }
2227 else // found some other tag
2228 {
2229 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or </table> tag but "
2230 "found token {} instead!",retval.to_string());
2231 retval=Token::make_RetVal_OK();
2232 break;
2233 }
2234 }
2235 }
2236
2238
2239 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2240}
2241
2243{
2244 AUTO_TRACE();
2245 Token retval = Token::make_RetVal_OK();
2246 auto ns = AutoNodeStack(parser(),thisVariant());
2247
2248 // get next token
2249 Token tok=parser()->tokenizer.lex();
2250 // skip whitespace
2251 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2252 // should find a html tag now
2254 bool isHeader=FALSE;
2255 if (tok.is(TokenRetval::TK_HTMLTAG))
2256 {
2257 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2258 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2259 {
2260 retval = Token::make_RetVal_TableRow();
2261 }
2262 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2263 {
2264 retval = Token::make_RetVal_TableRow();
2265 isHeader=TRUE;
2266 }
2267 }
2268
2269 // parse one or more rows
2270 while (retval.is(TokenRetval::RetVal_TableRow))
2271 {
2274 retval=tr->parseXml(isHeader);
2275 isHeader=FALSE;
2276 }
2277
2279
2280 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2281 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2282}
2283
2284/** Helper class to compute the grid for an HTML style table */
2286{
2287 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2288 uint32_t rowsLeft;
2289 uint32_t column;
2290};
2291
2292/** List of ActiveRowSpan classes. */
2293typedef std::vector<ActiveRowSpan> RowSpanList;
2294
2295/** determines the location of all cells in a grid, resolving row and
2296 column spans. For each the total number of visible cells is computed,
2297 and the total number of visible columns over all rows is stored.
2298 */
2300{
2301 //printf("computeTableGrid()\n");
2302 RowSpanList rowSpans;
2303 uint32_t maxCols=0;
2304 uint32_t rowIdx=1;
2305 for (auto &rowNode : children())
2306 {
2307 uint32_t colIdx=1;
2308 uint32_t cells=0;
2309 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2310 if (row)
2311 {
2312 for (auto &cellNode : row->children())
2313 {
2314 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2315 if (cell)
2316 {
2317 uint32_t rs = cell->rowSpan();
2318 uint32_t cs = cell->colSpan();
2319
2320 for (size_t i=0;i<rowSpans.size();i++)
2321 {
2322 if (rowSpans[i].rowsLeft>0 &&
2323 rowSpans[i].column==colIdx)
2324 {
2325 colIdx=rowSpans[i].column+1;
2326 cells++;
2327 }
2328 }
2329 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2330 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2331 cell->setRowIndex(rowIdx);
2332 cell->setColumnIndex(colIdx);
2333 colIdx+=cs;
2334 cells++;
2335 }
2336 }
2337 for (size_t i=0;i<rowSpans.size();i++)
2338 {
2339 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2340 }
2341 row->setVisibleCells(cells);
2342 row->setRowIndex(rowIdx);
2343 rowIdx++;
2344 }
2345 if (colIdx-1>maxCols) maxCols=colIdx-1;
2346 }
2347 m_numCols = maxCols;
2348}
2349
2350//---------------------------------------------------------------------------
2351
2353{
2354 AUTO_TRACE();
2355 Token retval = Token::make_TK_NONE();
2356 auto ns = AutoNodeStack(parser(),thisVariant());
2357
2358 Token tok = parser()->tokenizer.lex();
2359 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2360 {
2361 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2362 {
2363 switch (tok.value())
2364 {
2365 case TokenRetval::TK_COMMAND_AT:
2366 // fall through
2367 case TokenRetval::TK_COMMAND_BS:
2368 {
2369 QCString cmdName=parser()->context.token->name;
2370 bool isJavaLink=FALSE;
2371 switch (Mappers::cmdMapper->map(cmdName))
2372 {
2374 {
2375 tok=parser()->tokenizer.lex();
2376 if (!tok.is(TokenRetval::TK_WHITESPACE))
2377 {
2378 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
2379 tok.command_to_char(),cmdName);
2380 }
2381 else
2382 {
2384 tok=parser()->tokenizer.lex(); // get the reference id
2385 if (!tok.is(TokenRetval::TK_WORD))
2386 {
2387 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}' command",
2388 tok.to_string(),tok.command_to_char(),cmdName);
2389 }
2390 else
2391 {
2393 children().get_last<DocRef>()->parse();
2394 }
2396 }
2397 }
2398 break;
2400 isJavaLink=TRUE;
2401 // fall through
2403 {
2404 tok=parser()->tokenizer.lex();
2405 if (!tok.is(TokenRetval::TK_WHITESPACE))
2406 {
2407 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
2408 cmdName);
2409 }
2410 else
2411 {
2413 tok=parser()->tokenizer.lex();
2414 if (!tok.is(TokenRetval::TK_WORD))
2415 {
2416 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of \\{} command",
2417 tok.to_string(),cmdName);
2418 }
2419 else
2420 {
2423 DocLink *lnk = children().get_last<DocLink>();
2424 QCString leftOver = lnk->parse(isJavaLink);
2425 if (!leftOver.isEmpty())
2426 {
2427 children().append<DocWord>(parser(),thisVariant(),leftOver);
2428 }
2429 }
2430 }
2431 }
2432
2433 break;
2434 default:
2435 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '{:c}{}' found as part of a <dt> tag",
2436 tok.command_to_char(),cmdName);
2437 }
2438 }
2439 break;
2440 case TokenRetval::TK_SYMBOL:
2441 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found as part of a <dt> tag",
2442 parser()->context.token->name);
2443 break;
2444 case TokenRetval::TK_HTMLTAG:
2445 {
2446 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2447 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2448 {
2449 retval = Token::make_RetVal_DescData();
2450 goto endtitle;
2451 }
2452 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2453 {
2454 // ignore </dt> tag.
2455 }
2456 else if (tagId==HtmlTagType::HTML_DT)
2457 {
2458 // missing <dt> tag.
2459 retval = Token::make_RetVal_DescTitle();
2460 goto endtitle;
2461 }
2462 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2463 {
2464 retval = Token::make_RetVal_EndDesc();
2465 goto endtitle;
2466 }
2467 else if (tagId==HtmlTagType::HTML_A)
2468 {
2469 if (!parser()->context.token->endTag)
2470 {
2471 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2472 }
2473 }
2474 else
2475 {
2476 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <{}{}> found within <dt> context",
2477 parser()->context.token->endTag?"/":"",parser()->context.token->name);
2478 }
2479 }
2480 break;
2481 default:
2482 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {} found as part of a <dt> tag",
2483 tok.to_string());
2484 break;
2485 }
2486 }
2487 tok = parser()->tokenizer.lex();
2488 }
2489 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2490 {
2491 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2492 " <dt> tag");
2493 }
2494endtitle:
2496 return retval;
2497}
2498
2499//---------------------------------------------------------------------------
2500
2502{
2503 AUTO_TRACE();
2505 Token retval = Token::make_TK_NONE();
2506 auto ns = AutoNodeStack(parser(),thisVariant());
2507
2508 bool isFirst=TRUE;
2509 DocPara *par=nullptr;
2510 do
2511 {
2513 par = children().get_last<DocPara>();
2514 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2515 retval=par->parse();
2516 }
2517 while (retval.is(TokenRetval::TK_NEWPARA));
2518 if (par) par->markLast();
2519
2520 return retval;
2521}
2522
2523//---------------------------------------------------------------------------
2524
2526{
2527 AUTO_TRACE();
2528 Token retval = Token::make_RetVal_OK();
2529 auto ns = AutoNodeStack(parser(),thisVariant());
2530
2531 // get next token
2532 Token tok=parser()->tokenizer.lex();
2533 // skip whitespace
2534 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2535 // should find a html tag now
2536 if (tok.is(TokenRetval::TK_HTMLTAG))
2537 {
2538 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2539 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2540 {
2541 // continue
2542 }
2543 else // found some other tag
2544 {
2545 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2546 "found <{}> instead!",parser()->context.token->name);
2547 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2548 goto enddesclist;
2549 }
2550 }
2551 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2552 {
2553 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2554 " for a html description title");
2555 goto enddesclist;
2556 }
2557 else // token other than html token
2558 {
2559 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found {} token instead!",
2560 tok.to_string());
2561 goto enddesclist;
2562 }
2563
2564 do
2565 {
2570 retval=dt->parse();
2571 if (retval.is(TokenRetval::RetVal_DescData))
2572 {
2573 retval=dd->parse();
2574 while (retval.is(TokenRetval::RetVal_DescData))
2575 {
2578 retval=dd->parse();
2579 }
2580 }
2581 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2582 {
2583 // error
2584 break;
2585 }
2586 } while (retval.is(TokenRetval::RetVal_DescTitle));
2587
2588 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2589 {
2590 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2591 }
2592
2593enddesclist:
2594
2595 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2596}
2597
2598//---------------------------------------------------------------------------
2599
2601{
2602 AUTO_TRACE();
2603 Token retval = Token::make_TK_NONE();
2604 auto ns = AutoNodeStack(parser(),thisVariant());
2605
2606 // parse one or more paragraphs
2607 bool isFirst=TRUE;
2608 DocPara *par=nullptr;
2609 do
2610 {
2612 par = children().get_last<DocPara>();
2613 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2614 retval=par->parse();
2615 }
2616 while (retval.is(TokenRetval::TK_NEWPARA));
2617 if (par) par->markLast();
2618
2619 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2620 return retval;
2621}
2622
2624{
2625 AUTO_TRACE();
2626 Token retval = Token::make_TK_NONE();
2627 auto ns = AutoNodeStack(parser(),thisVariant());
2628
2629 // parse one or more paragraphs
2630 bool isFirst=TRUE;
2631 DocPara *par=nullptr;
2632 do
2633 {
2635 par = children().get_last<DocPara>();
2636 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2637 retval=par->parse();
2638 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2639
2640 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2641 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2642 if (retval.is(TokenRetval::RetVal_ListItem))
2643 {
2644 break;
2645 }
2646 }
2647 while (!retval.is(TokenRetval::RetVal_CloseXml));
2648
2649 if (par) par->markLast();
2650
2651 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2652 return retval;
2653}
2654
2655//---------------------------------------------------------------------------
2656
2658{
2659 AUTO_TRACE();
2660 Token retval = Token::make_RetVal_OK();
2661 int num=1;
2662 auto ns = AutoNodeStack(parser(),thisVariant());
2663
2664 // get next token
2665 Token tok=parser()->tokenizer.lex();
2666 // skip whitespace and paragraph breaks
2667 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2668 // should find a html tag now
2669 if (tok.is(TokenRetval::TK_HTMLTAG))
2670 {
2671 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2672 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2673 {
2674 // ok, we can go on.
2675 }
2676 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2678 ) && parser()->context.token->endTag
2679 ) // found empty list
2680 {
2681 // add dummy item to obtain valid HTML
2683 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2684 retval = Token::make_RetVal_EndList();
2685 goto endlist;
2686 }
2687 else // found some other tag
2688 {
2689 // add dummy item to obtain valid HTML
2691 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2692 "found <{}{}> instead!",parser()->context.token->endTag?"/":"",parser()->context.token->name);
2693 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2694 goto endlist;
2695 }
2696 }
2697 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2698 {
2699 // add dummy item to obtain valid HTML
2701 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2702 " for a html list item");
2703 goto endlist;
2704 }
2705 else // token other than html token
2706 {
2707 // add dummy item to obtain valid HTML
2709 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found {} token instead!",
2710 tok.to_string());
2711 goto endlist;
2712 }
2713
2714 do
2715 {
2718 retval=li->parse();
2719 } while (retval.is(TokenRetval::RetVal_ListItem));
2720
2721 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2722 {
2723 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <{:c}l> block",
2724 m_type==Unordered ? 'u' : 'o');
2725 }
2726
2727endlist:
2728 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2729 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2730}
2731
2733{
2734 AUTO_TRACE();
2735 Token retval = Token::make_RetVal_OK();
2736 int num=1;
2737 auto ns = AutoNodeStack(parser(),thisVariant());
2738
2739 // get next token
2740 Token tok=parser()->tokenizer.lex();
2741 // skip whitespace and paragraph breaks
2742 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2743 // should find a html tag now
2744 if (tok.is(TokenRetval::TK_HTMLTAG))
2745 {
2746 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2747 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2748 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2749 {
2750 // ok, we can go on.
2751 }
2752 else // found some other tag
2753 {
2754 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2755 "found <{}> instead!",parser()->context.token->name);
2756 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2757 goto endlist;
2758 }
2759 }
2760 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2761 {
2762 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2763 " for a html list item");
2764 goto endlist;
2765 }
2766 else // token other than html token
2767 {
2768 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found {} token instead!",
2769 tok.to_string());
2770 goto endlist;
2771 }
2772
2773 do
2774 {
2777 retval=li->parseXml();
2778 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2779 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2780 } while (retval.is(TokenRetval::RetVal_ListItem));
2781
2782 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2783 {
2784 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"{}\"> block",
2785 m_type==Unordered ? "bullet" : "number");
2786 }
2787
2788endlist:
2789 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2790 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2791 Token::make_RetVal_OK() : retval;
2792}
2793
2794//--------------------------------------------------------------------------
2795
2797{
2798 AUTO_TRACE();
2799 Token retval = Token::make_TK_NONE();
2800 auto ns = AutoNodeStack(parser(),thisVariant());
2801
2802 // parse one or more paragraphs
2803 bool isFirst=TRUE;
2804 DocPara *par=nullptr;
2805 do
2806 {
2808 par = children().get_last<DocPara>();
2809 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2810 retval=par->parse();
2811 }
2812 while (retval.is(TokenRetval::TK_NEWPARA));
2813 if (par) par->markLast();
2814
2815 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2816 {
2817 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2818 }
2819
2820 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2821 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2822}
2823
2824//---------------------------------------------------------------------------
2825
2827{
2828 AUTO_TRACE();
2829 Token retval = Token::make_TK_NONE();
2830 auto ns = AutoNodeStack(parser(),thisVariant());
2831
2832 // parse one or more paragraphs
2833 bool isFirst=TRUE;
2834 DocPara *par=nullptr;
2835 do
2836 {
2838 par = children().get_last<DocPara>();
2839 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2840 retval=par->parse();
2841 }
2842 while (retval.is(TokenRetval::TK_NEWPARA));
2843 if (par) par->markLast();
2844
2845 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2846 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2847}
2848
2849//---------------------------------------------------------------------------
2850
2855
2856
2858{
2859 auto ns = AutoNodeStack(parser(),thisVariant());
2861 DocPara *par = &std::get<DocPara>(*m_paragraph);
2862 Token rv=par->parse();
2863 par->markFirst();
2864 par->markLast();
2865 return rv;
2866}
2867
2868//--------------------------------------------------------------------------
2869
2871{
2872 auto ns = AutoNodeStack(parser(),thisVariant());
2873 Token rv = Token::make_TK_NONE();
2874 do
2875 {
2878 rv=li->parse();
2879 } while (rv.is(TokenRetval::RetVal_ListItem));
2880 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2881}
2882
2883//--------------------------------------------------------------------------
2884
2889
2891{
2892 AUTO_TRACE();
2893 Token retval = Token::make_RetVal_OK();
2894 auto ns = AutoNodeStack(parser(),thisVariant());
2895
2896 // first parse any number of paragraphs
2897 bool isFirst=TRUE;
2898 DocPara *lastPar=nullptr;
2899 do
2900 {
2902 DocPara *par = children().get_last<DocPara>();
2903 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2904 retval=par->parse();
2905 if (!par->isEmpty())
2906 {
2907 if (lastPar) lastPar->markLast(FALSE);
2908 lastPar=par;
2909 }
2910 else
2911 {
2912 children().pop_back();
2913 }
2914 // next paragraph should be more indented than the - marker to belong
2915 // to this item
2916 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2917 if (lastPar) lastPar->markLast();
2918
2919 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2920 return retval;
2921}
2922
2923//--------------------------------------------------------------------------
2924
2931
2933{
2934 AUTO_TRACE();
2935 Token retval = Token::make_RetVal_OK();
2936 int num=1;
2937 auto ns = AutoNodeStack(parser(),thisVariant());
2939 // first item or sub list => create new list
2940 do
2941 {
2942 switch (parser()->context.token->id)
2943 {
2944 case -1:
2945 break;
2946 case DocAutoList::Unchecked: // unchecked
2947 case DocAutoList::Checked_x: // checked with x
2948 case DocAutoList::Checked_X: // checked with X
2949 num = parser()->context.token->id;
2950 break;
2951 default: // explicitly numbered list
2952 num=parser()->context.token->id; // override num with real number given
2953 break;
2954 }
2955
2957 retval = children().get_last<DocAutoListItem>()->parse();
2958 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
2959 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
2960 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
2961 // qPrint(parser()->context.token->name));
2962 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
2963 }
2964 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
2965 m_indent==parser()->context.token->indent && // at same indent level
2966 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
2967 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
2968 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
2969 );
2970
2972 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2973 return retval;
2974}
2975
2976//--------------------------------------------------------------------------
2977
2979{
2980 AUTO_TRACE();
2981 auto ns = AutoNodeStack(parser(),thisVariant());
2983 Token tok = parser()->tokenizer.lex();
2984 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2985 {
2986 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2987 {
2988 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
2989 }
2990 tok = parser()->tokenizer.lex();
2991 }
2994}
2995
2997{
2999 parser()->pushContext(); // this will create a new parser->context.token
3001 parser()->popContext(); // this will restore the old parser->context.token
3005}
3006
3007//--------------------------------------------------------------------------
3008
3013
3015{
3016 return m_title && std::get<DocTitle>(*m_title).hasTitle();
3017}
3018
3019Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
3020{
3021 AUTO_TRACE();
3022 auto ns = AutoNodeStack(parser(),thisVariant());
3023
3024 // handle case for user defined title
3025 if (userTitle)
3026 {
3028 std::get_if<DocTitle>(m_title.get())->parse();
3029 }
3030
3031 // add new paragraph as child
3032 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3033 {
3034 std::get<DocPara>(children().back()).markLast(FALSE);
3035 }
3036 bool markFirst = children().empty();
3037 if (needsSeparator)
3038 {
3040 }
3042 DocPara *par = children().get_last<DocPara>();
3043 if (markFirst)
3044 {
3045 par->markFirst();
3046 }
3047 par->markLast();
3048
3049 // parse the contents of the paragraph
3050 Token retval = par->parse();
3051
3052 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3053 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
3054}
3055
3057{
3058 AUTO_TRACE();
3059 auto ns = AutoNodeStack(parser(),thisVariant());
3060
3062 DocTitle *title = &std::get<DocTitle>(*m_title);
3063 title->parseFromString(thisVariant(),parser()->context.token->name);
3064
3065 QCString text = parser()->context.token->text;
3066 parser()->pushContext(); // this will create a new parser->context.token
3068 parser()->popContext(); // this will restore the old parser->context.token
3069
3070 return Token::make_RetVal_OK();
3071}
3072
3074{
3075 AUTO_TRACE();
3076 auto ns = AutoNodeStack(parser(),thisVariant());
3077
3078 Token retval = Token::make_RetVal_OK();
3079 for (;;)
3080 {
3081 // add new paragraph as child
3082 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
3083 {
3084 std::get<DocPara>(children().back()).markLast(false);
3085 }
3086 bool markFirst = children().empty();
3088 DocPara *par = children().get_last<DocPara>();
3089 if (markFirst)
3090 {
3091 par->markFirst();
3092 }
3093 par->markLast();
3094
3095 // parse the contents of the paragraph
3096 retval = par->parse();
3097 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3098 if (retval.is(TokenRetval::RetVal_CloseXml))
3099 {
3100 retval = Token::make_RetVal_OK();
3101 break;
3102 }
3103 }
3104
3105 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3106 return retval;
3107}
3108
3110{
3111 DocPara *p=nullptr;
3112 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
3113 {
3115 p = children().get_last<DocPara>();
3116 }
3117 else
3118 {
3119 // Comma-separate <seealso> links.
3120 p->injectToken(Token::make_TK_WORD(),",");
3121 p->injectToken(Token::make_TK_WHITESPACE()," ");
3122 }
3123
3125 p->injectToken(Token::make_TK_LNKWORD(),word);
3127}
3128
3130{
3131 switch (m_type)
3132 {
3133 case Unknown: break;
3134 case See: return "see";
3135 case Return: return "return";
3136 case Author: // fall through
3137 case Authors: return "author";
3138 case Version: return "version";
3139 case Since: return "since";
3140 case Date: return "date";
3141 case Note: return "note";
3142 case Warning: return "warning";
3143 case Pre: return "pre";
3144 case Post: return "post";
3145 case Copyright: return "copyright";
3146 case Invar: return "invariant";
3147 case Remark: return "remark";
3148 case Attention: return "attention";
3149 case Important: return "important";
3150 case User: return "user";
3151 case Rcs: return "rcs";
3152 }
3153 return "unknown";
3154}
3155
3156//--------------------------------------------------------------------------
3157
3159{
3160 AUTO_TRACE();
3161 Token retval = Token::make_RetVal_OK();
3162 auto ns = AutoNodeStack(parser(),thisVariant());
3163 DocPara *par=nullptr;
3164 QCString saveCmdName = cmdName;
3165
3166 Token tok=parser()->tokenizer.lex();
3167 if (!tok.is(TokenRetval::TK_WHITESPACE))
3168 {
3169 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3170 saveCmdName);
3171 retval = Token::make_RetVal_EndParBlock();
3172 goto endparamlist;
3173 }
3175 tok=parser()->tokenizer.lex();
3176 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3177 {
3179 {
3180 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3181 if (typeSeparator!=-1)
3182 {
3183 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3184 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3187 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3188 {
3189 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3190 }
3191 }
3192 else
3193 {
3196 }
3197 }
3198 else if (m_type==DocParamSect::RetVal)
3199 {
3202 }
3203 //m_params.append(parser()->context.token->name);
3205 tok=parser()->tokenizer.lex();
3206 }
3208 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3209 {
3210 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3211 "argument of command {}",saveCmdName);
3212 retval = Token::make_RetVal_EndParBlock();
3213 goto endparamlist;
3214 }
3215 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3216 {
3217 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3218 {
3219 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} in comment block while parsing the "
3220 "argument of command {}",tok.to_string(),saveCmdName);
3221 }
3222 retval = Token::make_RetVal_EndParBlock();
3223 goto endparamlist;
3224 }
3225
3227 par = m_paragraphs.get_last<DocPara>();
3228 retval = par->parse();
3229 par->markFirst();
3230 par->markLast();
3231
3232endparamlist:
3233 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3234 return retval;
3235}
3236
3238{
3239 AUTO_TRACE();
3240 Token retval = Token::make_RetVal_OK();
3241 auto ns = AutoNodeStack(parser(),thisVariant());
3242
3243 parser()->context.token->name = paramName;
3245 {
3248 }
3249 else if (m_type==DocParamSect::RetVal)
3250 {
3253 }
3254
3256
3257 do
3258 {
3260 DocPara *par = m_paragraphs.get_last<DocPara>();
3261 retval = par->parse();
3262 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3263 // after </para> and before </param>
3264 {
3265 m_paragraphs.pop_back();
3266 break;
3267 }
3268 else // append the paragraph to the list
3269 {
3270 if (!m_paragraphs.empty())
3271 {
3272 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3273 }
3274 bool markFirst = m_paragraphs.empty();
3275 par = &std::get<DocPara>(m_paragraphs.back());
3276 if (markFirst)
3277 {
3278 par->markFirst();
3279 }
3280 par->markLast();
3281 }
3282
3283 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3284
3285 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3286 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3287 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3288 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3289
3290 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3291 {
3292 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3293 }
3294 else
3295 {
3296 retval = Token::make_RetVal_OK();
3297 }
3298
3299 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3300 return retval;
3301}
3302
3303//--------------------------------------------------------------------------
3304
3305Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3306{
3307 AUTO_TRACE();
3308 Token retval = Token::make_RetVal_OK();
3309 auto ns = AutoNodeStack(parser(),thisVariant());
3310
3311 if (d!=Unspecified)
3312 {
3314 }
3315
3316 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3317 {
3318 DocParamList &lastPl = std::get<DocParamList>(children().back());
3319 lastPl.markLast(false);
3320 }
3321 bool markFirst = children().empty();
3324 if (markFirst)
3325 {
3326 pl->markFirst();
3327 }
3328 pl->markLast();
3329 if (xmlContext)
3330 {
3331 retval = pl->parseXml(cmdName);
3332 }
3333 else
3334 {
3335 retval = pl->parse(cmdName);
3336 }
3337 if (retval.is(TokenRetval::RetVal_EndParBlock))
3338 {
3339 retval = Token::make_RetVal_OK();
3340 }
3341
3342 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3343 return retval;
3344}
3345
3346//--------------------------------------------------------------------------
3347
3353
3355{
3356 AUTO_TRACE();
3357 DocSimpleSect *ss=nullptr;
3358 bool needsSeparator = FALSE;
3359 if (!children().empty() && // has previous element
3360 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3361 ss->type()==t && // of same type
3362 t!=DocSimpleSect::User) // but not user defined
3363 {
3364 // append to previous section
3365 needsSeparator = TRUE;
3366 }
3367 else // start new section
3368 {
3371 }
3372 Token rv = Token::make_RetVal_OK();
3373 if (xmlContext)
3374 {
3375 return ss->parseXml();
3376 }
3377 else
3378 {
3379 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3380 }
3381 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3382}
3383
3386 bool xmlContext=FALSE,
3387 int direction=DocParamSect::Unspecified)
3388{
3389 AUTO_TRACE();
3390 DocParamSect *ps = nullptr;
3391 if (!children().empty() && // previous element
3392 (ps=children().get_last<DocParamSect>()) && // was a param sect
3393 ps->type()==t) // of same type
3394 { // append to previous section ps
3395 }
3396 else // start new section
3397 {
3399 ps = children().get_last<DocParamSect>();
3400 }
3401 Token rv=ps->parse(cmdName,xmlContext,
3402 static_cast<DocParamSect::Direction>(direction));
3403 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3404 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3405}
3406
3407void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3408{
3409 AUTO_TRACE();
3410 QCString saveCmdName = cmdName;
3411 // get the argument of the cite command.
3412 Token tok=parser()->tokenizer.lex();
3413
3414 CiteInfoOption option;
3415 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3416 {
3418 parser()->tokenizer.lex();
3419 StringVector optList=split(parser()->context.token->name.str(),",");
3420 for (auto const &opt : optList)
3421 {
3422 if (opt == "number")
3423 {
3424 if (!option.isUnknown())
3425 {
3426 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3427 }
3428 else
3429 {
3430 option = CiteInfoOption::makeNumber();
3431 }
3432 }
3433 else if (opt == "year")
3434 {
3435 if (!option.isUnknown())
3436 {
3437 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3438 }
3439 else
3440 {
3441 option = CiteInfoOption::makeYear();
3442 }
3443 }
3444 else if (opt == "shortauthor")
3445 {
3446 if (!option.isUnknown())
3447 {
3448 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple options specified with \\{}, discarding '{}'", saveCmdName, opt);
3449 }
3450 else
3451 {
3453 }
3454 }
3455 else if (opt == "nopar")
3456 {
3457 option.setNoPar();
3458 }
3459 else if (opt == "nocite")
3460 {
3461 option.setNoCite();
3462 }
3463 else
3464 {
3465 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unknown option specified with \\{}, discarding '{}'", saveCmdName, opt);
3466 }
3467 }
3468
3469 if (option.isUnknown()) option.changeToNumber();
3470
3472 tok=parser()->tokenizer.lex();
3473 if (!tok.is(TokenRetval::TK_WHITESPACE))
3474 {
3475 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3476 saveCmdName);
3477 return;
3478 }
3479 }
3480 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3481 {
3482 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3483 cmdChar,saveCmdName);
3484 return;
3485 }
3486 else
3487 {
3488 option = CiteInfoOption::makeNumber();
3489 }
3490
3492 tok=parser()->tokenizer.lex();
3493 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3494 {
3495 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"THE ONE unexpected end of comment block while parsing the "
3496 "argument of command '{:c}{}'",cmdChar,saveCmdName);
3497 return;
3498 }
3499 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3500 {
3501 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3502 tok.to_string(),cmdChar,saveCmdName);
3503 return;
3504 }
3508
3510}
3511
3512void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3513{
3514 AUTO_TRACE();
3515 // get the argument of the emoji command.
3516 Token tok=parser()->tokenizer.lex();
3517 if (!tok.is(TokenRetval::TK_WHITESPACE))
3518 {
3519 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3520 cmdChar,cmdName);
3521 return;
3522 }
3524 tok=parser()->tokenizer.lex();
3525 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3526 {
3527 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3528 "argument of command '{:c}{}'",cmdChar,cmdName);
3530 return;
3531 }
3532 else if (!tok.is(TokenRetval::TK_WORD))
3533 {
3534 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3535 tok.to_string(),cmdChar,cmdName);
3537 return;
3538 }
3541}
3542
3543void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3544{
3545 // get the argument of the cite command.
3546 Token tok=parser()->tokenizer.lex();
3547 if (!tok.is(TokenRetval::TK_WHITESPACE))
3548 {
3549 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3550 cmdChar,cmdName);
3551 return;
3552 }
3554 tok=parser()->tokenizer.lex();
3555 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3556 {
3557 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3558 "argument of command '{:c}{}'",cmdChar,cmdName);
3559 return;
3560 }
3561 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3562 {
3563 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3564 tok.to_string(),cmdChar,cmdName);
3565 return;
3566 }
3567 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3568 if (opt)
3569 {
3570 QCString optionValue;
3571 switch (opt->kind())
3572 {
3574 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3575 break;
3577 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3578 break;
3580 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3581 break;
3583 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3584 break;
3586 {
3587 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3588 optionValue="";
3589 if (!lst->empty())
3590 {
3591 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3592 static const reg::Ex marker(R"(@(\d+))");
3593 reg::Iterator it(lstFormat,marker);
3595 size_t index=0;
3596 // now replace all markers with the real text
3597 for ( ; it!=end ; ++it)
3598 {
3599 const auto &match = *it;
3600 size_t newIndex = match.position();
3601 size_t matchLen = match.length();
3602 optionValue += lstFormat.substr(index,newIndex-index);
3603 unsigned long entryIndex = std::stoul(match[1].str());
3604 if (entryIndex<(unsigned long)lst->size())
3605 {
3606 optionValue += lst->at(entryIndex);
3607 }
3608 index=newIndex+matchLen;
3609 }
3610 optionValue+=lstFormat.substr(index);
3611 }
3612 }
3613 break;
3615 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '{:c}{}': '{}'",
3616 cmdChar,cmdName,parser()->context.token->name);
3617 break;
3619 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3620 "Disabled setting (i.e. not supported in this doxygen executable) for '{:c}{}': '{}'",
3621 cmdChar,cmdName,parser()->context.token->name);
3622 break;
3624 // nothing to show here
3625 break;
3626 }
3627 if (!optionValue.isEmpty())
3628 {
3629 children().append<DocWord>(parser(),thisVariant(),optionValue);
3630 }
3631 }
3632 else
3633 {
3634 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '{:c}{}': '{}'",
3635 cmdChar,cmdName,parser()->context.token->name);
3637 }
3639}
3640
3642{
3643 AUTO_TRACE();
3644 Token retval=parser()->tokenizer.lex();
3645 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3647 retval=parser()->tokenizer.lex();
3648 if (retval.is(TokenRetval::RetVal_OK))
3649 {
3653 if (!ref->parse())
3654 {
3655 children().pop_back();
3656 }
3657 }
3659 return retval;
3660}
3661
3662void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3663{
3664 AUTO_TRACE();
3665 QCString fmt;
3666 QCString date;
3667 Token tok=parser()->tokenizer.lex();
3668 if (!tok.is(TokenRetval::TK_WHITESPACE))
3669 {
3670 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3671 cmdChar,cmdName);
3672 return;
3673 }
3675 tok = parser()->tokenizer.lex();
3676 if (!tok.is(TokenRetval::TK_WORD))
3677 {
3678 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '{:c}{}'",
3679 cmdChar,cmdName);
3681 return;
3682 }
3683 fmt = parser()->context.token->name;
3684
3686 tok = parser()->tokenizer.lex();
3687
3688 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3689 QCString specDate = specDateRaw.stripWhiteSpace();
3690 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3691 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3692 {
3693 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}'",
3694 cmdChar,cmdName);
3696 return;
3697 }
3698
3699 std::tm dat{};
3700 int specFormat=0;
3701 QCString err = dateTimeFromString(specDate,dat,specFormat);
3702 if (!err.isEmpty())
3703 {
3704 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '{:c}{}': {}",
3705 cmdChar,cmdName,err);
3707 return;
3708 }
3709
3710 int usedFormat=0;
3711 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3712
3713 // warn the user if the format contains markers that are not explicitly filled in
3714 for (int i=0;i<SF_NumBits;i++)
3715 {
3716 int bitMask = 1<<i;
3717 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3718 {
3719 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.",
3720 cmdChar,cmdName,fmt,SF_bit2str(i),specDate,SF_bit2str(i));
3721 }
3722 }
3723
3724 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3725 if (specDateOnlyWS) // specDate is only whitespace
3726 {
3728 }
3730}
3731
3732void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3733{
3734 AUTO_TRACE();
3736 Token tok = parser()->tokenizer.lex();
3737 if (!tok.is(TokenRetval::TK_WORD))
3738 {
3739 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '{:c}{}'",
3740 cmdChar,cmdName);
3741 return;
3742 }
3744}
3745
3746void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3747{
3748 AUTO_TRACE();
3749 Token tok=parser()->tokenizer.lex();
3750 if (!tok.is(TokenRetval::TK_WHITESPACE))
3751 {
3752 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3753 cmdChar,cmdName);
3754 return;
3755 }
3757 tok=parser()->tokenizer.lex();
3759 if (!tok.is(TokenRetval::TK_WORD))
3760 {
3761 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3762 tok.to_string(),cmdChar,cmdName);
3763 return;
3764 }
3767}
3768
3769
3771{
3772 AUTO_TRACE("cmdName={}",cmdName);
3773 QCString saveCmdName = cmdName;
3774 Token tok=parser()->tokenizer.lex();
3775 if (!tok.is(TokenRetval::TK_WHITESPACE))
3776 {
3777 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3778 saveCmdName);
3779 return;
3780 }
3782 tok=parser()->tokenizer.lex();
3784 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3785 {
3786 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3787 "argument of command {}", saveCmdName);
3788 return;
3789 }
3790 else if (!tok.is(TokenRetval::TK_WORD))
3791 {
3792 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3793 tok.to_string(),saveCmdName);
3794 return;
3795 }
3796 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3797 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3798 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3799 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3800 //TODO get from context the stripCodeComments()
3801 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3805 stripCodeComments,
3808 );
3810 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3811 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3812 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3813 bool isFirst = !n1 || // no last node
3814 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3815 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3816 op->markFirst(isFirst);
3817 op->markLast(true);
3818 if (n1_docIncOp)
3819 {
3820 n1_docIncOp->markLast(false);
3821 }
3822 else if (n1_docWs && n2_docIncOp)
3823 {
3824 n2_docIncOp->markLast(false);
3825 }
3826 op->parse();
3827}
3828
3829template<class T>
3830void DocPara::handleFile(const QCString &cmdName)
3831{
3832 AUTO_TRACE("cmdName={}",cmdName);
3833 QCString saveCmdName = cmdName;
3834 Token tok=parser()->tokenizer.lex();
3835 if (!tok.is(TokenRetval::TK_WHITESPACE))
3836 {
3837 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3838 saveCmdName);
3839 return;
3840 }
3842 tok=parser()->tokenizer.lex();
3844 if (!tok.is(TokenRetval::TK_WORD))
3845 {
3846 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
3847 tok.to_string(),saveCmdName);
3848 return;
3849 }
3850 QCString name = parser()->context.token->name;
3851 children().append<T>(parser(),thisVariant(),name,
3855 auto df = children().get_last<T>();
3856 if (!df->parse())
3857 {
3858 children().pop_back();
3859 }
3860}
3861
3868
3869void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3870{
3871 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3872 QCString saveCmdName = cmdName;
3873 Token tok=parser()->tokenizer.lex();
3874 if (!tok.is(TokenRetval::TK_WHITESPACE))
3875 {
3876 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3877 saveCmdName);
3878 return;
3879 }
3881 tok=parser()->tokenizer.lex();
3882 if (!tok.is(TokenRetval::TK_WORD))
3883 {
3884 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"{} as the argument of {}",
3885 tok.to_string(),saveCmdName);
3886 return;
3887 }
3888 if (saveCmdName == "javalink")
3889 {
3891 parser()->context.nodeStack.size(),
3892 DocStyleChange::Code,cmdName,TRUE);
3893 }
3896 DocLink *lnk = children().get_last<DocLink>();
3897 if (saveCmdName == "javalink")
3898 {
3900 parser()->context.nodeStack.size(),
3901 DocStyleChange::Code,cmdName,FALSE);
3902 }
3903 QCString leftOver = lnk->parse(isJavaLink);
3904 if (!leftOver.isEmpty())
3905 {
3906 children().append<DocWord>(parser(),thisVariant(),leftOver);
3907 }
3908}
3909
3910void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3911{
3912 AUTO_TRACE("cmdName={}",cmdName);
3913 QCString saveCmdName = cmdName;
3914 Token tok=parser()->tokenizer.lex();
3915 if (!tok.is(TokenRetval::TK_WHITESPACE))
3916 {
3917 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
3918 cmdChar,qPrint(saveCmdName));
3919 return;
3920 }
3922 tok=parser()->tokenizer.lex(); // get the reference id
3923 if (!tok.is(TokenRetval::TK_WORD))
3924 {
3925 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
3926 tok.to_string(),cmdChar,saveCmdName);
3927 goto endref;
3928 }
3932 children().get_last<DocRef>()->parse();
3933endref:
3935}
3936
3938{
3939 AUTO_TRACE("cmdName={}",cmdName);
3940 QCString saveCmdName = cmdName;
3941 Token tok=parser()->tokenizer.lex();
3942 bool isBlock = false;
3943 bool trimLeft = false;
3944 bool localScope = false;
3945 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3946 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3947 {
3949 parser()->tokenizer.lex();
3951 StringVector optList=split(parser()->context.token->name.str(),",");
3952 auto contains = [&optList](const char *kw)
3953 {
3954 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
3955 };
3956 localScope = contains("local");
3957 if (contains("nostrip"))
3958 {
3959 stripCodeComments = false;
3960 }
3961 else if (contains("strip"))
3962 {
3963 stripCodeComments = true;
3964 }
3965 if (t==DocInclude::Snippet && contains("trimleft"))
3966 {
3967 trimLeft = true;
3968 }
3969
3970 if (contains("lineno"))
3971 {
3975 }
3976 tok=parser()->tokenizer.lex();
3977 if (!tok.is(TokenRetval::TK_WHITESPACE))
3978 {
3979 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3980 saveCmdName);
3981 return;
3982 }
3983 }
3984 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
3985 {
3987 parser()->tokenizer.lex();
3988 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
3990 parser()->tokenizer.lex();
3991 }
3992 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3993 {
3994 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\{} command",
3995 saveCmdName);
3996 return;
3997 }
3999 tok=parser()->tokenizer.lex();
4001 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4002 {
4003 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4004 "argument of command {}",saveCmdName);
4005 return;
4006 }
4007 else if (!tok.is(TokenRetval::TK_WORD))
4008 {
4009 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of {}",
4010 tok.to_string(),saveCmdName);
4011 return;
4012 }
4013 QCString fileName = parser()->context.token->name;
4014 QCString blockId;
4016 {
4017 if (fileName == "this") fileName=parser()->context.fileName;
4019 tok=parser()->tokenizer.lex();
4021 if (!tok.is(TokenRetval::TK_WORD))
4022 {
4023 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token {} instead while parsing the {} command",
4024 tok.to_string(),saveCmdName);
4025 return;
4026 }
4027 blockId = "["+parser()->context.token->name+"]";
4028 }
4029
4031 thisVariant(),
4032 fileName,
4033 localScope ? parser()->context.context : "",
4034 t,
4035 stripCodeComments,
4038 blockId,isBlock,trimLeft);
4040}
4041
4042void DocPara::handleSection(char cmdChar,const QCString &cmdName)
4043{
4044 AUTO_TRACE("cmdName={}",cmdName);
4045 QCString saveCmdName = cmdName;
4046 // get the argument of the section command.
4047 Token tok=parser()->tokenizer.lex();
4048 if (!tok.is(TokenRetval::TK_WHITESPACE))
4049 {
4050 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '{:c}{}' command",
4051 cmdChar,saveCmdName);
4052 return;
4053 }
4054 tok=parser()->tokenizer.lex();
4055 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4056 {
4057 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
4058 "argument of command '{:c}{}'", cmdChar,saveCmdName);
4059 return;
4060 }
4061 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
4062 {
4063 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token {} as the argument of '{:c}{}'",
4064 tok.to_string(),cmdChar,saveCmdName);
4065 return;
4066 }
4069 parser()->tokenizer.lex();
4071}
4072
4073Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
4074{
4075 AUTO_TRACE();
4076 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
4077 Token retval = children().get_last<DocHtmlHeader>()->parse();
4078 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
4079}
4080
4081// For XML tags whose content is stored in attributes rather than
4082// contained within the element, we need a way to inject the attribute
4083// text into the current paragraph.
4084bool DocPara::injectToken(Token tok,const QCString &tokText)
4085{
4086 AUTO_TRACE();
4087 parser()->context.token->name = tokText;
4088 return parser()->defaultHandleToken(thisVariant(),tok,children());
4089}
4090
4092{
4093 AUTO_TRACE();
4094 Token retval = parser()->tokenizer.lex();
4095 QCString lang = parser()->context.token->name;
4096 if (!lang.isEmpty() && lang.at(0)!='.')
4097 {
4098 lang="."+lang;
4099 }
4100 if (parser()->context.xmlComment)
4101 {
4102 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
4103 }
4104 // search for the first non-whitespace line, index is stored in li
4105 size_t i=0,li=0,l=parser()->context.token->verb.length();
4106 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
4107 {
4108 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
4109 i++;
4110 }
4113 stripIndentation(parser()->context.token->verb.mid(li)),
4117 FALSE,lang);
4118 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4119 {
4120 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
4121 }
4123 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4124 return retval;
4125}
4126
4128{
4129 if (parser()->context.memberDef) // inheriting docs from a member
4130 {
4131 const MemberDef *reMd = parser()->context.memberDef->reimplements();
4132 if (reMd) // member from which was inherited.
4133 {
4134 const MemberDef *thisMd = parser()->context.memberDef;
4135 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
4136 parser()->pushContext();
4137 parser()->context.scope=reMd->getOuterScope();
4138 if (parser()->context.scope!=Doxygen::globalScope)
4139 {
4141 }
4142 parser()->context.memberDef=reMd;
4143 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
4144 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
4145 parser()->context.copyStack.push_back(reMd);
4148 parser()->context.copyStack.pop_back();
4149 auto hasParamCommand = parser()->context.hasParamCommand;
4150 auto hasReturnCommand = parser()->context.hasReturnCommand;
4151 auto retvalsFound = parser()->context.retvalsFound;
4152 auto paramsFound = parser()->context.paramsFound;
4153 parser()->popContext();
4154 parser()->context.hasParamCommand = hasParamCommand;
4155 parser()->context.hasReturnCommand = hasReturnCommand;
4156 parser()->context.retvalsFound = retvalsFound;
4157 parser()->context.paramsFound = paramsFound;
4158 parser()->context.memberDef = thisMd;
4159 }
4160 }
4161}
4162
4163
4164Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
4165{
4166 AUTO_TRACE("cmdName={}",cmdName);
4167 Token retval = Token::make_RetVal_OK();
4168 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
4169 switch (cmdId)
4170 {
4172 {
4173 std::string str{cmdChar};
4174 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
4175 if (isAliasCmd(cmdName.view()))
4176 {
4177 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '{:c}{}'. Check if number of arguments passed is correct.",cmdChar,cmdName);
4178 }
4179 else
4180 {
4181 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '{:c}{}'",cmdChar,cmdName);
4182 }
4183 }
4184 break;
4187 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4189 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4190 break;
4193 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4195 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4196 break;
4199 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4201 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4202 break;
4205 break;
4208 break;
4211 break;
4214 break;
4217 break;
4220 break;
4223 break;
4226 break;
4229 break;
4232 break;
4236 break;
4241 break;
4244 break;
4247 break;
4250 break;
4253 break;
4256 break;
4259 break;
4262 break;
4267 break;
4271 break;
4274 break;
4277 break;
4280 break;
4283 break;
4286 break;
4289 break;
4292 break;
4295 break;
4298 break;
4301 break;
4304 break;
4307 break;
4310 break;
4313 break;
4316 break;
4318 {
4320 retval = children().get_last<DocSimpleList>()->parse();
4321 }
4322 break;
4324 {
4325 handleSection(cmdChar,cmdName);
4326 retval = Token::make_RetVal_Section();
4327 }
4328 break;
4330 {
4331 handleSection(cmdChar,cmdName);
4332 retval = Token::make_RetVal_Subsection();
4333 }
4334 break;
4336 {
4337 handleSection(cmdChar,cmdName);
4338 retval = Token::make_RetVal_Subsubsection();
4339 }
4340 break;
4342 {
4343 handleSection(cmdChar,cmdName);
4344 retval = Token::make_RetVal_Paragraph();
4345 }
4346 break;
4348 {
4349 handleSection(cmdChar,cmdName);
4350 retval = Token::make_RetVal_SubParagraph();
4351 }
4352 break;
4354 {
4355 handleSection(cmdChar,cmdName);
4356 retval = Token::make_RetVal_SubSubParagraph();
4357 }
4358 break;
4360 {
4362 retval = handleStartCode();
4363 }
4364 break;
4366 {
4368 retval = handleStartCode();
4369 }
4370 break;
4372 {
4374 retval = parser()->tokenizer.lex();
4376 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4377 {
4378 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4379 }
4381 }
4382 break;
4384 {
4386 retval = parser()->tokenizer.lex();
4388 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4389 {
4390 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4391 }
4393 }
4394 break;
4396 {
4398 retval = parser()->tokenizer.lex();
4400 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4401 {
4402 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4403 }
4405 }
4406 break;
4408 {
4410 retval = parser()->tokenizer.lex();
4412 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4413 {
4414 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4415 }
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(),"xmlonly 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(),"docbookonly section ended without end marker");
4439 }
4441 }
4442 break;
4444 {
4447 parser()->tokenizer.lex();
4448
4449 QCString fullMatch = parser()->context.token->verb;
4450 int idx = fullMatch.find('{');
4451 int idxEnd = fullMatch.find("}",idx+1);
4452 StringVector optList;
4453 if (idx != -1) // options present
4454 {
4455 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4456 optList = split(optStr.str(),",");
4457 for (const auto &opt : optList)
4458 {
4459 if (opt.empty()) continue;
4460 QCString locOpt(opt);
4461 locOpt = locOpt.stripWhiteSpace().lower();
4462 if (locOpt == "code")
4463 {
4465 }
4466 else if (!locOpt.isEmpty())
4467 {
4468 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '{}' for '\\iliteral'",opt);
4469 }
4470 }
4471 }
4472
4474 retval = parser()->tokenizer.lex();
4476 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4477 {
4478 if (t == DocVerbatim::JavaDocCode)
4479 {
4480 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4481 }
4482 else
4483 {
4484 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4485 }
4486 }
4488 }
4489 break;
4492 {
4493 if (cmdId == CommandType::CMD_VERBATIM)
4494 {
4496 }
4497 else
4498 {
4500 }
4501 retval = parser()->tokenizer.lex();
4503 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4504 {
4505 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4506 }
4508 }
4509 break;
4511 {
4520 QCString width,height;
4521 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4523 retval = parser()->tokenizer.lex();
4524 dv->setText(parser()->context.token->verb);
4525 dv->setWidth(width);
4526 dv->setHeight(height);
4527 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4528 if (!Config_getBool(HAVE_DOT))
4529 {
4530 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4531 children().pop_back();
4532 }
4533 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4534 {
4535 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4536 }
4538 }
4539 break;
4541 {
4550 QCString width,height;
4551 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4553 retval = parser()->tokenizer.lex();
4554 dv->setText(parser()->context.token->verb);
4555 dv->setWidth(width);
4556 dv->setHeight(height);
4557 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4558 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4559 {
4560 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4561 }
4563 }
4564 break;
4566 {
4567 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4569 parser()->tokenizer.lex();
4570 QCString fullMatch = parser()->context.token->sectionId;
4571 QCString sectionId = "";
4572 int idx = fullMatch.find('{');
4573 int idxEnd = fullMatch.find("}",idx+1);
4574 StringVector optList;
4575 QCString engine;
4576 if (idx != -1) // options present
4577 {
4578 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4579 optList = split(optStr.str(),",");
4580 for (const auto &opt : optList)
4581 {
4582 if (opt.empty()) continue;
4583 bool found = false;
4584 QCString locOpt(opt);
4585 locOpt = locOpt.stripWhiteSpace().lower();
4586 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4587 {
4588 if (!engine.isEmpty())
4589 {
4590 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4591 }
4592 engine = locOpt;
4593 found = true;
4594 }
4595 if (!found)
4596 {
4597 if (sectionId.isEmpty())
4598 {
4599 sectionId = opt;
4600 }
4601 else
4602 {
4603 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4604 }
4605 }
4606 }
4607 }
4608 else
4609 {
4610 sectionId = parser()->context.token->sectionId;
4611 }
4612 if (engine.isEmpty()) engine = "uml";
4613
4614 if (sectionId.isEmpty())
4615 {
4617 retval = parser()->tokenizer.lex();
4618 assert(retval.is(TokenRetval::RetVal_OK));
4619
4620 sectionId = parser()->context.token->sectionId;
4621 sectionId = sectionId.stripWhiteSpace();
4622 }
4623
4624 QCString plantFile(sectionId);
4629 FALSE,plantFile);
4631 dv->setEngine(engine);
4633 QCString width,height;
4634 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4636 retval = parser()->tokenizer.lex();
4637 int line = 0;
4638 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4639 if (engine == "ditaa")
4640 {
4641 dv->setUseBitmap(true);
4642 }
4643 else if (engine == "uml")
4644 {
4645 int i = trimmedVerb.find('\n');
4646 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4647 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4648 }
4649 dv->setText(trimmedVerb);
4650 dv->setWidth(width);
4651 dv->setHeight(height);
4652 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4653 if (jarPath.isEmpty())
4654 {
4655 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4656 children().pop_back();
4657 }
4658 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4659 {
4660 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4661 }
4663 }
4664 break;
4666 retval = Token::make_RetVal_EndParBlock();
4667 break;
4683 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4684 break;
4686 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4687 break;
4689 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4690 break;
4692 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4693 break;
4696 break;
4698 retval = handleXRefItem();
4699 break;
4701 {
4703 }
4704 break;
4707 {
4709 }
4710 break;
4712 {
4714 }
4715 break;
4717 {
4721 retval = children().get_last<DocIndexEntry>()->parse();
4722 }
4723 break;
4725 retval = Token::make_RetVal_Internal();
4726 break;
4728 retval = Token::make_RetVal_EndInternal();
4729 break;
4731 {
4733 retval = children().get_last<DocParBlock>()->parse();
4734 }
4735 break;
4736 case CommandType::CMD_COPYDOC: // fall through
4737 case CommandType::CMD_COPYBRIEF: // fall through
4739 //retval = Token::make_RetVal_CopyDoc();
4740 // these commands should already be resolved by processCopyDoc()
4741 break;
4744 break;
4747 break;
4750 break;
4753 break;
4756 break;
4759 break;
4762 break;
4765 break;
4768 break;
4771 break;
4774 break;
4777 break;
4780 break;
4783 break;
4786 break;
4789 break;
4792 break;
4794 if (!Config_getBool(HAVE_DOT))
4795 {
4796 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4797 "ignoring \\dotfile command because HAVE_DOT is not set");
4798 }
4799 else
4800 {
4801 handleFile<DocDotFile>(cmdName);
4802 }
4803 break;
4806 break;
4808 handleFile<DocMscFile>(cmdName);
4809 break;
4811 handleFile<DocDiaFile>(cmdName);
4812 break;
4815 break;
4817 handleLink(cmdName,FALSE);
4818 break;
4820 handleLink(cmdName,TRUE);
4821 break;
4823 handleCite(cmdChar,cmdName);
4824 break;
4826 handleEmoji(cmdChar,cmdName);
4827 break;
4829 handleDoxyConfig(cmdChar,cmdName);
4830 break;
4831 case CommandType::CMD_REF: // fall through
4833 handleRef(cmdChar,cmdName);
4834 break;
4836 {
4839 }
4840 break;
4842 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4843 break;
4845 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '{:c}{}'",cmdChar,parser()->context.token->name);
4846 break;
4848 {
4850 }
4851 break;
4852 //case CommandType::CMD_LANGSWITCH:
4853 // retval = handleLanguageSwitch();
4854 // break;
4856 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command {}",parser()->context.token->name);
4857 {
4860 }
4861 break;
4864 break;
4866 handleShowDate(cmdChar,cmdName);
4867 break;
4869 handleILine(cmdChar,cmdName);
4870 break;
4872 handleIFile(cmdChar,cmdName);
4873 break;
4875 {
4877 (void)parser()->tokenizer.lex();
4879 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4881 }
4882 break;
4883 default:
4884 // we should not get here!
4885 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' in paragraph context",cmdName);
4886 break;
4887 }
4888 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4889 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4890 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4891 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4892 TokenRetval::RetVal_EndInternal)
4893 );
4894 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4895 return retval;
4896}
4897
4898static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4899 const char *attrName,
4900 QCString *result)
4901{
4902
4903 for (const auto &opt : tagHtmlAttribs)
4904 {
4905 if (opt.name==attrName)
4906 {
4907 *result = opt.value;
4908 return TRUE;
4909 }
4910 }
4911 return FALSE;
4912}
4913
4914Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4915{
4916 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4917 Token retval = Token::make_RetVal_OK();
4918 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4919 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4922 {
4923 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<{}/>') may not use the 'empty tag' XHTML syntax.",
4924 tagName);
4925 }
4926 switch (tagId)
4927 {
4929 if (!parser()->context.token->emptyTag)
4930 {
4932 tagHtmlAttribs,DocHtmlList::Unordered);
4933 retval=children().get_last<DocHtmlList>()->parse();
4934 }
4935 break;
4937 if (!parser()->context.token->emptyTag)
4938 {
4940 tagHtmlAttribs,DocHtmlList::Ordered);
4941 retval=children().get_last<DocHtmlList>()->parse();
4942 }
4943 break;
4945 if (parser()->context.token->emptyTag) break;
4947 {
4948 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4949 }
4950 else
4951 {
4952 retval = Token::make_RetVal_ListItem();
4953 }
4954 break;
4956 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
4957 break;
4959 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
4960 break;
4962 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
4963 break;
4965 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
4966 break;
4968 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
4969 break;
4971 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
4972 break;
4974 if (parser()->context.token->emptyTag) break;
4975 if (parser()->context.xmlComment)
4976 // for C# source or inside a <summary> or <remark> section we
4977 // treat <code> as an XML tag (so similar to @code)
4978 {
4980 retval = handleStartCode();
4981 }
4982 else // normal HTML markup
4983 {
4984 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4985 }
4986 break;
4988 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
4989 break;
4991 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Typewriter,tagName,&parser()->context.token->attribs);
4992 break;
4994 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
4995 break;
4997 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
4998 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
4999 break;
5001 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
5002 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
5003 break;
5005 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
5006 break;
5008 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
5009 break;
5011 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
5012 break;
5014 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
5015 break;
5017 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
5018 break;
5020 if (parser()->context.token->emptyTag) break;
5021 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
5024 break;
5026 retval = Token::make_TK_NEWPARA();
5027 break;
5029 if (!parser()->context.token->emptyTag)
5030 {
5031 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
5032 retval=children().get_last<DocHtmlDescList>()->parse();
5033 }
5034 break;
5036 if (insideDL(thisVariant()))
5037 {
5038 retval = Token::make_RetVal_DescTitle();
5039 }
5040 else
5041 {
5042 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
5043 }
5044 break;
5046 if (insideDL(thisVariant()))
5047 {
5048 retval = Token::make_RetVal_DescData();
5049 }
5050 else
5051 {
5052 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
5053 }
5054 break;
5056 if (!parser()->context.token->emptyTag)
5057 {
5058 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
5059 retval=children().get_last<DocHtmlTable>()->parse();
5060 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5061 }
5062 break;
5064 retval = Token::make_RetVal_TableRow();
5065 break;
5067 retval = Token::make_RetVal_TableCell();
5068 break;
5070 retval = Token::make_RetVal_TableHCell();
5071 break;
5075 // for time being ignore </t....> tag
5076 break;
5078 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
5079 break;
5081 {
5082 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
5083 }
5084 break;
5086 {
5087 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
5088 }
5089 break;
5091 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
5092 break;
5094 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
5095 break;
5097 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
5098 break;
5100 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
5101 break;
5103 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
5104 break;
5106 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
5107 break;
5109 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
5110 break;
5112 {
5113 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
5114 }
5115 break;
5117 if (!parser()->context.token->emptyTag)
5118 {
5119 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
5120 retval=children().get_last<DocHtmlDetails>()->parse();
5121 }
5122 break;
5124 if (!parser()->context.token->emptyTag)
5125 {
5126 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
5127 retval = children().get_last<DocHtmlBlockQuote>()->parse();
5128 }
5129 break;
5130
5133 {
5134 if (!parser()->context.token->emptyTag)
5135 {
5137 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
5138 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
5139 if (d)
5140 {
5141 if (!d->summary()) // details section does not have a summary yet
5142 {
5143 d->parseSummary(n,parser()->context.token->attribs);
5144 }
5145 else
5146 {
5147 retval = Token::make_TK_NEWPARA();
5148 }
5149 }
5150 }
5151 }
5152 break;
5156 // fall through
5159 if (!children().empty())
5160 {
5161 retval = Token::make_TK_NEWPARA();
5162 }
5163 break;
5165 if (insideTable(thisVariant()))
5166 {
5167 retval = Token::make_RetVal_TableCell();
5168 }
5169 break;
5170 case HtmlTagType::XML_C:
5171 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
5172 break;
5175 {
5177 QCString paramName;
5178 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5179 {
5180 if (paramName.isEmpty())
5181 {
5182 if (Config_getBool(WARN_NO_PARAMDOC))
5183 {
5184 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5185 }
5186 }
5187 else
5188 {
5189 retval = handleParamSection(paramName,
5191 TRUE);
5192 }
5193 }
5194 else
5195 {
5196 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5197 }
5198 }
5199 break;
5202 {
5203 QCString paramName;
5204 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5205 {
5206 //printf("paramName=%s\n",qPrint(paramName));
5208 children().append<DocWord>(parser(),thisVariant(),paramName);
5210 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5211 }
5212 else
5213 {
5214 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param{}ref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5215 }
5216 }
5217 break;
5219 {
5221 QCString exceptName;
5222 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5223 {
5224 unescapeCRef(exceptName);
5225 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5226 }
5227 else
5228 {
5229 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5230 }
5231 }
5232 break;
5235 if (insideTable(thisVariant()))
5236 {
5237 retval = Token::make_RetVal_TableRow();
5238 }
5239 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5240 {
5241 retval = Token::make_RetVal_ListItem();
5242 }
5243 else
5244 {
5245 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5246 }
5247 break;
5252 break;
5254 if (insideTable(thisVariant()))
5255 {
5256 retval = Token::make_RetVal_TableCell();
5257 }
5258 break;
5260 // I'm not sure if <see> is the same as <seealso> or if it
5261 // should you link a member without producing a section. The
5262 // C# specification is extremely vague about this (but what else
5263 // can we expect from Microsoft...)
5264 {
5265 QCString cref;
5266 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5267 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5268 {
5269 unescapeCRef(cref);
5270 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5271 {
5272 bool inSeeBlock = parser()->context.inSeeBlock;
5273 parser()->context.token->name = cref;
5276 parser()->context.inSeeBlock = inSeeBlock;
5277 }
5278 else // <see cref="...">...</see> style
5279 {
5280 //DocRef *ref = new DocRef(this,cref);
5281 //children().append(ref);
5282 //ref->parse();
5285 DocLink *lnk = children().get_last<DocLink>();
5286 QCString leftOver = lnk->parse(FALSE,TRUE);
5287 if (!leftOver.isEmpty())
5288 {
5289 children().append<DocWord>(parser(),thisVariant(),leftOver);
5290 }
5291 }
5292 }
5293 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5294 {
5295 bool inSeeBlock = parser()->context.inSeeBlock;
5296 parser()->context.token->name = cref;
5301 parser()->context.inSeeBlock = inSeeBlock;
5302 }
5303 else
5304 {
5305 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5306 }
5307 }
5308 break;
5310 {
5312 QCString cref;
5313 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5314 {
5315 unescapeCRef(cref);
5316 // Look for an existing "see" section
5317 DocNodeVariant *vss=nullptr;
5318 for (auto &n : children())
5319 {
5320 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5321 if (candidate && candidate->type()==DocSimpleSect::See)
5322 {
5323 vss = &n;
5324 }
5325 }
5326
5327 if (!vss) // start new section
5328 {
5330 vss = &children().back();
5331 }
5332
5333 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5334 retval = Token::make_RetVal_OK();
5335 }
5336 else
5337 {
5338 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5339 }
5340 }
5341 break;
5343 {
5344 QCString type;
5345 findAttribute(tagHtmlAttribs,"type",&type);
5347 HtmlAttribList emptyList;
5348 if (type=="number")
5349 {
5350 listType=DocHtmlList::Ordered;
5351 }
5352 if (type=="table")
5353 {
5354 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5355 retval=children().get_last<DocHtmlTable>()->parseXml();
5356 if (children().get_last<DocHtmlTable>()->children().empty()) children().pop_back();
5357 }
5358 else
5359 {
5360 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5361 retval=children().get_last<DocHtmlList>()->parseXml();
5362 }
5363 }
5364 break;
5367 // These tags are defined in .Net but are currently unsupported
5369 break;
5371 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <{}> found", tagName);
5372 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5373 break;
5376 break;
5377 default:
5378 // we should not get here!
5379 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag {}",tagName);
5380 ASSERT(0);
5381 break;
5382 }
5383 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5384 return retval;
5385}
5386
5388{
5389 AUTO_TRACE("tagName={}",tagName);
5390 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5391 Token retval = Token::make_RetVal_OK();
5392 switch (tagId)
5393 {
5395 if (!insideUL(thisVariant()))
5396 {
5397 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5398 }
5399 else
5400 {
5401 retval = Token::make_RetVal_EndList();
5402 }
5403 break;
5405 if (!insideOL(thisVariant()))
5406 {
5407 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5408 }
5409 else
5410 {
5411 retval = Token::make_RetVal_EndList();
5412 }
5413 break;
5415 if (!insideLI(thisVariant()))
5416 {
5417 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5418 }
5419 else
5420 {
5421 // ignore </li> tags
5422 }
5423 break;
5425 if (!insideDetails(thisVariant()))
5426 {
5427 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5428 }
5429 else
5430 {
5431 retval = Token::make_RetVal_EndHtmlDetails();
5432 }
5433 break;
5436 {
5437 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5438 }
5439 else
5440 {
5441 retval = Token::make_RetVal_EndBlockQuote();
5442 }
5443 break;
5446 break;
5449 break;
5452 break;
5455 break;
5458 break;
5461 break;
5464 break;
5467 break;
5470 break;
5473 break;
5476 break;
5479 break;
5482 break;
5485 break;
5488 break;
5491 break;
5494 break;
5499 break;
5501 retval = Token::make_TK_NEWPARA();
5502 break;
5504 retval = Token::make_RetVal_EndDesc();
5505 break;
5507 // ignore </dt> tag
5508 break;
5510 // ignore </dd> tag
5511 break;
5513 retval = Token::make_RetVal_EndTable();
5514 break;
5516 retval = Token::make_RetVal_EndTableRow();
5517 break;
5519 retval = Token::make_RetVal_EndTableCell();
5520 break;
5522 retval = Token::make_RetVal_EndTableCell();
5523 break;
5527 // for time being ignore </t....> tag
5528 break;
5530 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5531 break;
5533 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5534 break;
5536 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5537 break;
5539 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5540 break;
5542 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5543 break;
5545 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5546 break;
5548 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5549 break;
5551 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5552 break;
5554 break;
5556 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5557 break;
5559 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5560 // ignore </a> tag (can be part of <a name=...></a>
5561 break;
5562
5564 break;
5566 retval = Token::make_TK_NEWPARA();
5567 break;
5580 retval = Token::make_RetVal_CloseXml();
5581 break;
5582 case HtmlTagType::XML_C:
5584 break;
5592 // These tags are defined in .Net but are currently unsupported
5593 break;
5595 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </{}> found", tagName);
5596 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5597 break;
5598 default:
5599 // we should not get here!
5600 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag {}",tagName);
5601 ASSERT(0);
5602 break;
5603 }
5604 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5605 return retval;
5606}
5607
5609{
5610 // expected hierarchy:
5611 // 1. DocAutoListItem <- n
5612 // 2. DocAutoList <- parent(n)
5613 // 3. DocPara <- parent(parent(n))
5614
5615 // step 1
5616 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5617 {
5618 return false;
5619 }
5620
5621 // step 2
5622 n = parent(n);
5623 int indent = 0;
5624 const auto docAutoList = std::get_if<DocAutoList>(n);
5625 if (docAutoList) // capture indent
5626 {
5627 indent = docAutoList->indent();
5628 }
5629 else
5630 {
5631 return false;
5632 }
5633
5634 // step 3
5635 n = parent(n);
5636 const auto docPara = std::get_if<DocPara>(n);
5637 if (docPara)
5638 {
5639 QCString tagNameLower = QCString(parser->context.token->name).lower();
5640 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5641 {
5642 return std::get<DocStyleChange>(*stack.top());
5643 };
5644
5645 if (parser->context.styleStack.empty() || // no style change
5646 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5647 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5648 )
5649 {
5650 // insert an artificial 'end of autolist' marker and parse again
5651 QCString indentStr;
5652 indentStr.fill(' ',indent);
5653 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5654 return true;
5655 }
5656 }
5657 return false;
5658}
5659
5661{
5662 AUTO_TRACE();
5663 auto ns = AutoNodeStack(parser(),thisVariant());
5664 // handle style commands "inherited" from the previous paragraph
5666 Token tok=parser()->tokenizer.lex();
5667 Token retval = Token::make_TK_NONE();
5668 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5669 {
5670reparsetoken:
5671 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5672 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5673 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5674 )
5675 {
5676 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5677 }
5678 switch(tok.value())
5679 {
5680 case TokenRetval::TK_WORD:
5682 break;
5683 case TokenRetval::TK_LNKWORD:
5685 break;
5686 case TokenRetval::TK_URL:
5688 break;
5689 case TokenRetval::TK_WHITESPACE:
5690 {
5691 // prevent leading whitespace and collapse multiple whitespace areas
5692 if (insidePRE(thisVariant()) || // all whitespace is relevant
5693 (
5694 // remove leading whitespace
5695 !children().empty() &&
5696 // and whitespace after certain constructs
5700 )
5701 )
5702 {
5704 }
5705 }
5706 break;
5707 case TokenRetval::TK_LISTITEM:
5708 {
5709 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5710 const DocNodeVariant *n=parent();
5711 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5712 const DocAutoList *al = std::get_if<DocAutoList>(n);
5713 if (al) // we found an auto list up in the hierarchy
5714 {
5715 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5716 if (al->indent()>=parser()->context.token->indent)
5717 // new item at the same or lower indent level
5718 {
5719 retval = Token::make_TK_LISTITEM();
5720 goto endparagraph;
5721 }
5722 }
5723
5724 // determine list depth
5725 int depth = 0;
5726 n=parent();
5727 while (n)
5728 {
5729 al = std::get_if<DocAutoList>(n);
5730 if (al && al->isEnumList()) depth++;
5731 n=::parent(n);
5732 }
5733
5734 // first item or sub list => create new list
5735 do
5736 {
5739 parser()->context.token->isEnumList,depth,
5741 al = children().get_last<DocAutoList>();
5742 retval = children().get_last<DocAutoList>()->parse();
5743 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5744 al->indent()==parser()->context.token->indent // at same indent level
5745 );
5746
5747 // check the return value
5748 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5749 {
5750 // Reparse the token that ended the section at this level,
5751 // so a new simple section will be started at this level.
5752 // This is the same as unputting the last read token and continuing.
5754 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5755 {
5758 tok = Token::make_TK_RCSTAG();
5759 }
5760 else // other section
5761 {
5762 tok = Token::make_TK_COMMAND_BS();
5763 }
5764 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5765 goto reparsetoken;
5766 }
5767 else if (retval.is(TokenRetval::TK_ENDLIST))
5768 {
5769 if (al->indent()>parser()->context.token->indent) // end list
5770 {
5771 goto endparagraph;
5772 }
5773 else // continue with current paragraph
5774 {
5775 }
5776 }
5777 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5778 {
5779 goto endparagraph;
5780 }
5781 }
5782 break;
5783 case TokenRetval::TK_ENDLIST:
5784 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5785 if (std::get_if<DocAutoListItem>(parent()))
5786 {
5787 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5788 if (al && al->indent()>=parser()->context.token->indent)
5789 {
5790 // end of list marker ends this paragraph
5791 retval = Token::make_TK_ENDLIST();
5792 goto endparagraph;
5793 }
5794 else
5795 {
5796 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5797 "has invalid indent level");
5798 }
5799 }
5800 else
5801 {
5802 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5803 "list items");
5804 }
5805 break;
5806 case TokenRetval::TK_COMMAND_AT:
5807 // fall through
5808 case TokenRetval::TK_COMMAND_BS:
5809 {
5810 // see if we have to start a simple section
5811 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5812 const DocNodeVariant *n=parent();
5813 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5814 !std::holds_alternative<DocParamSect>(*n))
5815 {
5816 n=::parent(n);
5817 }
5819 {
5820 if (n) // already in a simple section
5821 {
5822 // simple section cannot start in this paragraph, need
5823 // to unwind the stack and remember the command.
5825 retval = Token::make_RetVal_SimpleSec();
5826 goto endparagraph;
5827 }
5828 }
5829 // see if we are in a simple list
5830 n=parent();
5831 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5832 if (n)
5833 {
5834 if (cmd==CommandType::CMD_LI)
5835 {
5836 retval = Token::make_RetVal_ListItem();
5837 goto endparagraph;
5838 }
5839 }
5840
5841 // handle the command
5842 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5843 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5844
5845 // check the return value
5846 if (retval.is(TokenRetval::RetVal_SimpleSec))
5847 {
5848 // Reparse the token that ended the section at this level,
5849 // so a new simple section will be started at this level.
5850 // This is the same as unputting the last read token and continuing.
5852 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5853 {
5856 tok = Token::make_TK_RCSTAG();
5857 }
5858 else // other section
5859 {
5860 tok = Token::make_TK_COMMAND_BS();
5861 }
5862 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5863 goto reparsetoken;
5864 }
5865 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5866 {
5867 // the command ended with a new command, reparse this token
5868 tok = retval;
5869 goto reparsetoken;
5870 }
5871 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5872 // or some auto list marker
5873 {
5874 goto endparagraph;
5875 }
5876 }
5877 break;
5878 case TokenRetval::TK_HTMLTAG:
5879 {
5880 if (!parser()->context.token->endTag) // found a start tag
5881 {
5882 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5883 }
5884 else // found an end tag
5885 {
5887 {
5888 break; // new code has been pushed back to the scanner, need to reparse
5889 }
5890 retval = handleHtmlEndTag(parser()->context.token->name);
5891 }
5892 if (!retval.is(TokenRetval::RetVal_OK))
5893 {
5894 goto endparagraph;
5895 }
5896 }
5897 break;
5898 case TokenRetval::TK_SYMBOL:
5899 {
5900 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5902 {
5904 }
5905 else
5906 {
5908 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
5909 parser()->context.token->name);
5910 }
5911 break;
5912 }
5913 case TokenRetval::TK_NEWPARA:
5914 retval = Token::make_TK_NEWPARA();
5915 goto endparagraph;
5916 case TokenRetval::TK_RCSTAG:
5917 {
5918 const DocNodeVariant *n=parent();
5919 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5920 !std::holds_alternative<DocParamSect>(*n))
5921 {
5922 n=::parent(n);
5923 }
5924 if (n) // already in a simple section
5925 {
5926 // simple section cannot start in this paragraph, need
5927 // to unwind the stack and remember the command.
5930 retval = Token::make_RetVal_SimpleSec();
5931 goto endparagraph;
5932 }
5933
5934 // see if we are in a simple list
5936 children().get_last<DocSimpleSect>()->parseRcs();
5937 }
5938 break;
5939 default:
5940 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5941 "Found unexpected token (id={})",tok.to_string());
5942 break;
5943 }
5944 tok=parser()->tokenizer.lex();
5945 }
5946 retval=Token::make_TK_NONE();
5947endparagraph:
5949 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5950 if (!parser()->context.token->endTag && par &&
5951 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5952 {
5953 par->setAttribs(parser()->context.token->attribs);
5954 }
5955 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
5956 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
5957 );
5958
5959 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5960 return retval;
5961}
5962
5963//--------------------------------------------------------------------------
5964
5966{
5967 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
5968 Token retval = Token::make_RetVal_OK();
5969 auto ns = AutoNodeStack(parser(),thisVariant());
5970
5971 if (!m_id.isEmpty())
5972 {
5974 if (sec)
5975 {
5976 m_file = sec->fileName();
5977 m_anchor = sec->label();
5978 QCString titleStr = sec->title();
5979 if (titleStr.isEmpty()) titleStr = sec->label();
5981 DocTitle *title = &std::get<DocTitle>(*m_title);
5982 title->parseFromString(thisVariant(),titleStr);
5983 }
5984 }
5985
5986 // first parse any number of paragraphs
5987 bool isFirst=TRUE;
5988 DocPara *lastPar=nullptr;
5989 do
5990 {
5992 DocPara *par = children().get_last<DocPara>();
5993 if (isFirst) { par->markFirst(); isFirst=FALSE; }
5994 retval=par->parse();
5995 if (!par->isEmpty())
5996 {
5997 if (lastPar) lastPar->markLast(FALSE);
5998 lastPar = par;
5999 }
6000 else
6001 {
6002 children().pop_back();
6003 }
6004 if (retval.is(TokenRetval::TK_LISTITEM))
6005 {
6006 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6007 }
6008 if (retval.is(TokenRetval::RetVal_Internal))
6009 {
6011 retval = children().get_last<DocInternal>()->parse(m_level+1);
6012 if (retval.is(TokenRetval::RetVal_EndInternal))
6013 {
6014 retval = Token::make_RetVal_OK();
6015 }
6016 }
6017 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6018 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
6019 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
6020 );
6021
6022 if (lastPar) lastPar->markLast();
6023
6024 while (true)
6025 {
6026 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
6027 {
6028 // then parse any number of nested sections
6029 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
6030 {
6032 2,
6034 retval = children().get_last<DocSection>()->parse();
6035 }
6036 break;
6037 }
6038 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
6039 {
6040 if ((m_level <= 1) &&
6041 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6042 {
6043 warn_doc_error(parser()->context.fileName,
6044 parser()->tokenizer.getLineNr(),
6045 "Unexpected subsubsection command found inside {}!",
6047 }
6048 // then parse any number of nested sections
6049 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
6050 {
6052 3,
6054 retval = children().get_last<DocSection>()->parse();
6055 }
6056 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
6057 }
6058 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
6059 {
6060 if ((m_level <= 2) &&
6061 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6062 {
6063 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6064 "Unexpected paragraph command found inside {}!",
6066 }
6067 // then parse any number of nested sections
6068 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
6069 {
6071 4,
6073 retval = children().get_last<DocSection>()->parse();
6074 }
6075 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
6076 }
6077 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
6078 {
6079 if ((m_level <= 3) &&
6080 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6081 {
6082 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6083 "Unexpected subparagraph command found inside {}!",
6085 }
6086 // then parse any number of nested sections
6087 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
6088 {
6090 5,
6092 retval = children().get_last<DocSection>()->parse();
6093 }
6094 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
6095 }
6096 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
6097 {
6098 if ((m_level <= 4) &&
6099 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6100 {
6101 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
6102 "Unexpected subsubparagraph command found inside {}!",
6104 }
6105 // then parse any number of nested sections
6106 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
6107 {
6109 6,
6111 retval = children().get_last<DocSection>()->parse();
6112 }
6113 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
6114 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
6115 }
6116 else
6117 {
6118 break;
6119 }
6120 }
6121
6122 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
6123 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
6124 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
6125 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
6126 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
6127 );
6128
6129 AUTO_TRACE_EXIT("retval={}", retval.to_string());
6130 return retval;
6131}
6132
6133//--------------------------------------------------------------------------
6134
6136{
6137 AUTO_TRACE();
6138 auto ns = AutoNodeStack(parser(),thisVariant());
6140
6141 Token tok = parser()->tokenizer.lex();
6142 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
6143 {
6144 switch(tok.value())
6145 {
6146 case TokenRetval::TK_WORD:
6148 break;
6149 case TokenRetval::TK_WHITESPACE:
6151 break;
6152 case TokenRetval::TK_SYMBOL:
6153 {
6154 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
6156 {
6158 }
6159 else
6160 {
6161 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '{}' found",
6162 parser()->context.token->name);
6163 }
6164 }
6165 break;
6166 case TokenRetval::TK_COMMAND_AT:
6167 // fall through
6168 case TokenRetval::TK_COMMAND_BS:
6169 switch (Mappers::cmdMapper->map(parser()->context.token->name))
6170 {
6173 break;
6176 break;
6179 break;
6182 break;
6185 break;
6188 break;
6191 break;
6194 break;
6197 break;
6201 break;
6206 break;
6209 break;
6212 break;
6215 break;
6218 break;
6221 break;
6224 break;
6227 break;
6228 default:
6229 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '{}' found",
6230 parser()->context.token->name);
6231 break;
6232 }
6233 break;
6234 default:
6235 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token {}",
6236 tok.to_string());
6237 break;
6238 }
6239 tok = parser()->tokenizer.lex();
6240 }
6241
6243
6244}
6245
6246
6247//--------------------------------------------------------------------------
6248
6250{
6251 AUTO_TRACE();
6252 auto ns = AutoNodeStack(parser(),thisVariant());
6254 Token retval = Token::make_TK_NONE();
6255
6256 // first parse any number of paragraphs
6257 bool isFirst=TRUE;
6258 DocPara *lastPar = nullptr;
6259 do
6260 {
6261 {
6263 DocPara *par = children().get_last<DocPara>();
6264 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6265 retval=par->parse();
6266 if (par->isEmpty() && par->attribs().empty())
6267 {
6268 children().pop_back();
6269 }
6270 else
6271 {
6272 lastPar = par;
6273 }
6274 }
6275 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6276 if (retval == t)
6277 {
6278 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6279 {
6280 warn_doc_error(parser()->context.fileName,
6281 parser()->tokenizer.getLineNr(),
6282 "found {} command (id: '{}') outside of {} context!",
6283 sectionType,parser()->context.token->sectionId,parentSectionType);
6284 }
6285 while (retval==t)
6286 {
6287 if (!parser()->context.token->sectionId.isEmpty())
6288 {
6289 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6290 if (sec)
6291 {
6293 level,
6295 retval = children().get_last<DocSection>()->parse();
6296 }
6297 else
6298 {
6299 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid {} id '{}'; ignoring {}",
6300 sectionType,parser()->context.token->sectionId,sectionType);
6301 retval = Token::make_TK_NONE();
6302 }
6303 }
6304 else
6305 {
6306 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for {}; ignoring {}",sectionType,sectionType);
6307 retval = Token::make_TK_NONE();
6308 }
6309 }
6310 }
6311 };
6312 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6313 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6314 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6315 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6316 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6317
6318 if (retval.is(TokenRetval::TK_LISTITEM))
6319 {
6320 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6321 }
6322 if (retval.is(TokenRetval::RetVal_Internal))
6323 {
6325 retval = children().get_last<DocInternal>()->parse(1);
6326 }
6327 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6328 if (lastPar) lastPar->markLast();
6329
6330 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6331 // then parse any number of level1 sections
6332 while (retval.is(TokenRetval::RetVal_Section))
6333 {
6334 if (!parser()->context.token->sectionId.isEmpty())
6335 {
6336 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6337 if (sec)
6338 {
6340 1,
6342 retval = children().get_last<DocSection>()->parse();
6343 }
6344 else
6345 {
6346 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '{}'; ignoring section",parser()->context.token->sectionId);
6347 retval = Token::make_TK_NONE();
6348 }
6349 }
6350 else
6351 {
6352 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6353 retval = Token::make_TK_NONE();
6354 }
6355 }
6356
6358}
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 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:2932
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:2925
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:2885
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:939
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:903
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:1175
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1168
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:1097
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1090
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:1489
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:1696
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:1900
void setColumnIndex(uint32_t idx)
Definition docnode.h:1217
bool isFirst() const
Definition docnode.h:1201
Token parseXml()
Definition docnode.cpp:1804
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:1838
void markFirst(bool v=TRUE)
Definition docnode.h:1203
Alignment alignment() const
Definition docnode.cpp:1862
bool isHeading() const
Definition docnode.h:1200
const HtmlAttribList & attribs() const
Definition docnode.h:1205
Token parse()
Definition docnode.cpp:1770
uint32_t colSpan() const
Definition docnode.cpp:1850
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:1479
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:1304
Node representing a Html list.
Definition docnode.h:1000
Type m_type
Definition docnode.h:1011
Token parseXml()
Definition docnode.cpp:2732
Token parse()
Definition docnode.cpp:2657
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:2075
void setVisibleCells(uint32_t n)
Definition docnode.h:1256
bool isHeading() const
Definition docnode.cpp:1922
void setRowIndex(uint32_t idx)
Definition docnode.h:1261
Token parse()
Definition docnode.cpp:1968
Node Html summary.
Definition docnode.h:844
Node representing a HTML table.
Definition docnode.h:1269
Token parseXml()
Definition docnode.cpp:2242
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1284
Token parse()
Definition docnode.cpp:2155
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2299
size_t m_numCols
Definition docnode.h:1286
const DocNodeVariant * caption() const
Definition docnode.cpp:2141
bool hasCaption() const
Definition docnode.cpp:2136
const DocNodeVariant * firstRow() const
Definition docnode.cpp:2146
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:1281
std::unique_ptr< Private > p
Definition docnode.h:675
void parse()
Definition docnode.cpp:1296
bool isSVG() const
Definition docnode.cpp:1287
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:1599
Node representing an internal section of documentation.
Definition docnode.h:969
Token parse(int)
Definition docnode.cpp:1539
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:1128
bool parse()
Definition docnode.cpp:1135
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:2826
Node representing a paragraph in the documentation tree.
Definition docnode.h:1080
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3354
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3869
void handleInheritDoc()
Definition docnode.cpp:4127
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3407
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3348
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3937
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4164
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3543
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:4042
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3830
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3746
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3384
void markLast(bool v=TRUE)
Definition docnode.h:1086
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4914
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3512
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3770
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:3910
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3732
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1115
bool m_isFirst
Definition docnode.h:1118
Token parse()
Definition docnode.cpp:5660
void handleVhdlFlow()
Definition docnode.cpp:3862
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:4073
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3662
bool m_isLast
Definition docnode.h:1119
Token handleXRefItem()
Definition docnode.cpp:3641
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5387
Token handleStartCode()
Definition docnode.cpp:4091
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:4084
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:3237
void markLast(bool b=TRUE)
Definition docnode.h:1135
Token parse(const QCString &cmdName)
Definition docnode.cpp:3158
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:3305
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:1207
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:857
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:6249
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:5965
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:2870
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:2851
Node representing a simple section.
Definition docnode.h:1017
QCString typeString() const
Definition docnode.cpp:3129
Type type() const
Definition docnode.h:1026
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:3019
Token parseRcs()
Definition docnode.cpp:3056
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:3009
const DocNodeVariant * title() const
Definition docnode.h:1033
Token parseXml()
Definition docnode.cpp:3073
void appendLinkWord(const QCString &word)
Definition docnode.cpp:3109
bool hasTitle() const
Definition docnode.cpp:3014
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:6135
Node representing a simple section title.
Definition docnode.h:608
void parse()
Definition docnode.cpp:2978
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:2996
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:1251
void parse()
Definition docnode.cpp:1255
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 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
T & front()
access the first element
Definition growvector.h:130
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:825
static Token skipSpacesForTable(DocParser *parser)
Definition docnode.cpp:1937
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4898
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2293
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:118
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5608
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:1932
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:2288
uint32_t column
Definition docnode.cpp:2289
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2287
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:816
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:75
bool includeFileShowLineNo
Definition docparser_p.h:89
DocStyleChangeStack styleStack
Definition docparser_p.h:67
size_t includeFileLength
Definition docparser_p.h:87
QCString fileName
Definition docparser_p.h:70
DocNodeStack nodeStack
Definition docparser_p.h:66
StringMultiSet paramsFound
Definition docparser_p.h:76
DefinitionStack copyStack
Definition docparser_p.h:69
QCString exampleName
Definition docparser_p.h:79
const Definition * scope
Definition docparser_p.h:61
QCString includeFileText
Definition docparser_p.h:85
TokenInfo * token
Definition docparser_p.h:92
QCString includeFileName
Definition docparser_p.h:84
size_t includeFileOffset
Definition docparser_p.h:86
const MemberDef * memberDef
Definition docparser_p.h:77
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:3220
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5718
QCString stripIndentation(const QCString &s, bool skipFirstLine)
Definition util.cpp:6462
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3542
QCString stripScope(const QCString &name)
Definition util.cpp:4292
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, SrcLangExt lang, const QCString &prefix)
Definition util.cpp:3246
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:4017
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:7129
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5537
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:3416
A bunch of utility functions.