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 }
147 return "<invalid>";
148}
149
150//----------- DocSymbol
151
156
157//----------- DocEmoji
158
160 DocNode(parser,parent), m_symName(symName), m_index(-1)
161{
162 QCString locSymName = symName;
163 size_t len=locSymName.length();
164 if (len>0)
165 {
166 if (locSymName.at(len-1)!=':') locSymName.append(":");
167 if (locSymName.at(0)!=':') locSymName.prepend(":");
168 }
169 m_symName = locSymName;
171 if (m_index==-1)
172 {
173 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Found unsupported emoji symbol '%s'",qPrint(m_symName));
174 }
175}
176
177//---------------------------------------------------------------------------
178
181{
182 //printf("new word %s url=%s\n",qPrint(word),qPrint(parser->context.searchUrl));
183 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
184 {
185 Doxygen::searchIndex.addWord(word,false);
186 }
187}
188
189//---------------------------------------------------------------------------
190
192 const QCString &ref,const QCString &file,
193 const QCString &anchor,const QCString &tooltip) :
197{
198 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
199 // qPrint(word),qPrint(parser->context.searchUrl),qPrint(tooltip));
200 if (Doxygen::searchIndex.enabled() && !parser->context.searchUrl.isEmpty())
201 {
202 Doxygen::searchIndex.addWord(word,false);
203 }
204}
205
206//---------------------------------------------------------------------------
207
209{
210 if (id.isEmpty())
211 {
212 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Empty anchor label");
213 return;
214 }
215
217 QCString anchorPrefix = ct.anchorPrefix();
218 if (id.left(anchorPrefix.length()) == anchorPrefix)
219 {
220 const CiteInfo *cite = ct.find(id.mid(anchorPrefix.length()));
221 if (cite)
222 {
224 m_anchor = id;
225 }
226 else
227 {
228 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid cite anchor id '%s'",qPrint(id));
229 m_anchor = "invalid";
230 m_file = "invalid";
231 }
232 }
233 else if (newAnchor) // found <a name="label">
234 {
235 m_anchor = id;
236 }
237 else // found \anchor label
238 {
239 const SectionInfo *sec = SectionManager::instance().find(id);
240 if (sec)
241 {
242 //printf("Found anchor %s\n",qPrint(id));
243 m_file = sec->fileName();
244 m_anchor = sec->label();
245 }
246 else
247 {
248 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid anchor id '%s'",qPrint(id));
249 m_anchor = "invalid";
250 m_file = "invalid";
251 }
252 }
253}
254
255//---------------------------------------------------------------------------
256
263
264
265//---------------------------------------------------------------------------
266
268{
269 AUTO_TRACE("file={} text={}",m_file,Trace::trunc(m_text));
270 switch(m_type)
271 {
272 case DontIncWithLines:
273 // fall through
274 case IncWithLines:
275 // fall through
276 case Include:
277 // fall through
278 case DontInclude:
287 //printf("parser->context.includeFile=<<%s>>\n",qPrint(parser->context.includeFileText));
288 break;
289 case VerbInclude:
290 // fall through
291 case HtmlInclude:
292 case LatexInclude:
298 break;
299 case Snippet:
300 case SnippetWithLines:
302 // check here for the existence of the blockId inside the file, so we
303 // only generate the warning once.
304 int count = 0;
305 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
306 {
307 warn_doc_error(parser()->context.fileName,
308 parser()->tokenizer.getLineNr(),
309 "block marked with %s for \\snippet should appear twice in file %s, found it %d times",
310 qPrint(m_blockId),qPrint(m_file),count);
311 }
312 break;
313 }
314}
315
316//---------------------------------------------------------------------------
317
319{
320 if (parser()->context.includeFileName.isEmpty())
321 {
322 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
323 "No previous '\\include' or '\\dontinclude' command for '\\%s' present",
324 typeAsString());
325 }
326 bool found = false;
327
329 const char *p = parser()->context.includeFileText.data();
330 size_t l = parser()->context.includeFileLength;
331 size_t o = parser()->context.includeFileOffset;
332 int il = parser()->context.includeFileLine;
333 AUTO_TRACE("text={} off={} len={}",Trace::trunc(p),o,l);
334 size_t so = o, bo = 0;
335 bool nonEmpty = FALSE;
336 switch(type())
337 {
338 case Line:
339 while (o<l)
340 {
341 char c = p[o];
342 if (c=='\n')
343 {
345 if (nonEmpty) break; // we have a pattern to match
346 so=o+1; // no pattern, skip empty line
347 }
348 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
349 {
350 nonEmpty=TRUE;
351 }
352 o++;
353 }
354 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
355 {
356 m_line = il;
358 found = true;
359 AUTO_TRACE_ADD("\\line {}",Trace::trunc(m_text));
360 }
361 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
364 break;
365 case SkipLine:
366 while (o<l)
367 {
368 so=o;
369 while (o<l)
370 {
371 char c = p[o];
372 if (c=='\n')
373 {
375 if (nonEmpty) break; // we have a pattern to match
376 so=o+1; // no pattern, skip empty line
377 }
378 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
379 {
380 nonEmpty=TRUE;
381 }
382 o++;
383 }
384 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
385 {
386 m_line = il;
388 found = true;
389 AUTO_TRACE_ADD("\\skipline {}",Trace::trunc(m_text));
390 break;
391 }
392 o++; // skip new line
393 }
394 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
397 break;
398 case Skip:
399 while (o<l)
400 {
401 so=o;
402 while (o<l)
403 {
404 char c = p[o];
405 if (c=='\n')
406 {
408 if (nonEmpty) break; // we have a pattern to match
409 so=o+1; // no pattern, skip empty line
410 }
411 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
412 {
413 nonEmpty=TRUE;
414 }
415 o++;
416 }
417 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
418 {
419 found = true;
420 break;
421 }
422 o++; // skip new line
423 }
424 parser()->context.includeFileOffset = so; // set pointer to start of new line
427 break;
428 case Until:
429 bo=o;
430 while (o<l)
431 {
432 so=o;
433 while (o<l)
434 {
435 char c = p[o];
436 if (c=='\n')
437 {
439 if (nonEmpty) break; // we have a pattern to match
440 so=o+1; // no pattern, skip empty line
441 }
442 else if (!isspace(static_cast<uint8_t>(c))) // no white space char
443 {
444 nonEmpty=TRUE;
445 }
446 o++;
447 }
448 if (parser()->context.includeFileText.mid(so,o-so).find(m_pattern)!=-1)
449 {
450 m_line = il;
452 found = true;
453 AUTO_TRACE_ADD("\\until {}",Trace::trunc(m_text));
454 break;
455 }
456 o++; // skip new line
457 }
458 parser()->context.includeFileOffset = std::min(l,o+1); // set pointer to start of new line
461 break;
462 }
463 if (!found)
464 {
465 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
466 "referenced pattern '%s' for command '\\%s' not found",qPrint(m_pattern),typeAsString());
467 }
468}
469
470//---------------------------------------------------------------------------
471
476
478{
480 if (refList && refList->isEnabled())
481 {
482 RefItem *item = refList->find(m_id);
483 ASSERT(item!=nullptr);
484 if (item)
485 {
486 if (parser()->context.memberDef && parser()->context.memberDef->name().at(0)=='@')
487 {
488 m_file = "@"; // can't cross reference anonymous enum
489 m_anchor = "@";
490 }
491 else
492 {
493 m_file = refList->fileName();
494 m_anchor = item->anchor();
495 }
496 m_title = refList->sectionTitle();
497 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
498 // qPrint(m_file),qPrint(m_anchor),qPrint(m_title));
499
500 if (!item->text().isEmpty())
501 {
502 parser()->pushContext();
504 parser()->popContext();
505 }
506 }
507 return TRUE;
508 }
509 return FALSE;
510}
511
512//---------------------------------------------------------------------------
513
515 m_relPath(parser->context.relPath)
516{
517 const Formula *formula = FormulaManager::instance().findFormula(id);
518 if (formula && !formula->text().isEmpty())
519 {
520 m_id = id;
521 m_name.sprintf("form_%d",m_id);
522 m_text = formula->text();
523 }
524 else // wrong \_form#<n> command
525 {
526 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Wrong formula id %d",id);
527 m_id = -1;
528 }
529}
530
531//---------------------------------------------------------------------------
532
537
539{
540 AUTO_TRACE();
541 auto ns = AutoNodeStack(parser(),thisVariant());
542
544 Token tok = parser()->tokenizer.lex();
545 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
546 {
547 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
548 {
549 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\refitem");
550 }
551 tok = parser()->tokenizer.lex();
552 }
555
556 if (!m_target.isEmpty())
557 {
559 if (sec==nullptr && parser()->context.lang==SrcLangExt::Markdown) // lookup as markdown file
560 {
562 }
563 if (sec) // ref to section or anchor
564 {
565 // set defaults
566 m_ref = sec->ref();
569 m_anchor = sec->label();
570 m_isSubPage = false;
571 // adjust if needed
572 switch (sec->type().level())
573 {
575 {
577 m_isSubPage = pd && pd->hasParentPage();
578 if (!m_isSubPage)
579 {
580 m_anchor="";
581 }
582 }
583 break;
586 break;
589 break;
590 default:
591 break;
592 }
593 //printf("m_ref=%s,m_file=%s,type=%d\n",
594 // qPrint(m_ref),qPrint(m_file),m_refType);
595 }
596 else
597 {
598 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"reference to unknown section %s",
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 %s 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%s' 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 %s 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 //printf("DocRef::DocRef(target=%s,context=%s)\n",qPrint(target),qPrint(context));
711 ASSERT(!target.isEmpty());
712 m_relPath = parser->context.relPath;
713 const SectionInfo *sec = SectionManager::instance().find(parser->context.prefix+target);
714 if (sec==nullptr && getLanguageFromFileName(target)==SrcLangExt::Markdown) // lookup as markdown file
715 {
717 }
718 if (sec) // ref to section or anchor
719 {
720 PageDef *pd = nullptr;
721 int secLevel = sec->type().level();
722 if (secLevel==SectionType::Page)
723 {
724 pd = Doxygen::pageLinkedMap->find(target);
725 }
726 m_text = sec->title();
727 if (m_text.isEmpty()) m_text = sec->label();
728
729 m_ref = sec->ref();
731 if (secLevel==SectionType::Anchor)
732 {
734 }
735 else if (secLevel==SectionType::Table)
736 {
738 }
739 else
740 {
742 }
743 m_isSubPage = pd && pd->hasParentPage();
744 if (secLevel!=SectionType::Page || m_isSubPage) m_anchor = sec->label();
745 m_sectionType = sec->type();
746 //printf("m_text=%s,m_ref=%s,m_file=%s,type=%d\n",
747 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),m_refType);
748 return;
749 }
750 else if (resolveLink(context,target,true,&compound,anchor,parser->context.prefix))
751 {
752 bool isFile = compound ?
753 (compound->definitionType()==Definition::TypeFile ||
755 FALSE;
756 m_text = linkToText(parser->context.lang,target,isFile);
758 if (compound && compound->isLinkable()) // ref to compound
759 {
760 if (anchor.isEmpty() && /* compound link */
761 compound->definitionType()==Definition::TypeGroup && /* is group */
762 !toGroupDef(compound)->groupTitle().isEmpty() /* with title */
763 )
764 {
765 m_text=(toGroupDef(compound))->groupTitle(); // use group's title as link
766 }
767 else if (compound->definitionType()==Definition::TypeMember &&
768 toMemberDef(compound)->isObjCMethod())
769 {
770 // Objective C Method
771 const MemberDef *member = toMemberDef(compound);
772 bool localLink = parser->context.memberDef ? member->getClassDef()==parser->context.memberDef->getClassDef() : FALSE;
773 m_text = member->objCMethodName(localLink,parser->context.inSeeBlock);
774 }
775 else if (Config_getBool(HIDE_SCOPE_NAMES))
776 {
778 }
779
780 m_file = compound->getOutputFileBase();
781 m_ref = compound->getReference();
782 //printf("isFile=%d compound=%s (%d)\n",isFile,qPrint(compound->name()),
783 // compound->definitionType());
784 return;
785 }
786 else if (compound && compound->definitionType()==Definition::TypeFile &&
787 toFileDef(compound)->generateSourceFile()
788 ) // undocumented file that has source code we can link to
789 {
790 m_file = compound->getSourceFileBase();
791 m_ref = compound->getReference();
792 return;
793 }
794 }
795 m_text = target;
796 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '%s' for \\ref command",
797 qPrint(target));
798}
799
801{
802 for (auto &&elem : elements)
803 {
804 emplace_back(std::move(elem));
805 }
806 elements.clear();
807}
808
809static void flattenParagraphs(DocNodeVariant *root,DocNodeList &children)
810{
811 DocNodeList newChildren;
812 for (auto &dn : children)
813 {
814 DocPara *para = std::get_if<DocPara>(&dn);
815 if (para)
816 {
817 //// move the children of the paragraph to the end of the newChildren list
818 newChildren.move_append(para->children());
819 }
820 }
821
822 // replace the children list by the newChildren list
823 children.clear();
824 children.move_append(newChildren);
825 // reparent the children
826 for (auto &cn : children)
827 {
828 setParent(&cn,root);
829 // we also need to set the parent for each child of cn, as cn's address may have changed.
830 auto opt_children = call_method_children(&cn);
831 if (opt_children)
832 {
833 for (auto &ccn : *opt_children)
834 {
835 setParent(&ccn,&cn);
836 }
837 }
838 }
839}
840
842{
843 AUTO_TRACE();
844 auto ns = AutoNodeStack(parser(),thisVariant());
845
846 Token tok = parser()->tokenizer.lex();
847 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
848 {
849 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
850 {
851 switch (tok.value())
852 {
853 case TokenRetval::TK_HTMLTAG:
854 break;
855 default:
857 break;
858 }
859 }
860 tok=parser()->tokenizer.lex();
861 }
862
863 if (children().empty() && !m_text.isEmpty())
864 {
865 QCString text = m_text;
866 if (parser()->context.insideHtmlLink)
867 {
868 // we already in a link/title only output anchor
869 text = m_anchor;
870 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
871 "Potential recursion while resolving \\ref command!");
872 }
874 parser()->pushContext();
876 parser()->popContext();
880 }
881
883}
884
885//---------------------------------------------------------------------------
886
888{
889 size_t numBibFiles = Config_getList(CITE_BIB_FILES).size();
890 //printf("DocCite::DocCite(target=%s)\n",qPrint(target));
891 ASSERT(!target.isEmpty());
892 m_relPath = parser->context.relPath;
894 const CiteInfo *cite = ct.find(target);
895 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?qPrint(cite->text):"<null>",numBibFiles);
896 if (numBibFiles>0 && cite && !cite->text().isEmpty()) // ref to citation
897 {
898 m_text = cite->text();
899 m_ref = "";
900 m_anchor = ct.anchorPrefix()+cite->label();
902 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
903 // qPrint(m_text),qPrint(m_ref),qPrint(m_file),qPrint(m_anchor));
904 return;
905 }
906 m_text = target;
907 if (numBibFiles==0)
908 {
909 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command found but no bib files specified via CITE_BIB_FILES!");
910 }
911 else if (cite==nullptr)
912 {
913 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve reference to '%s' for \\cite command",
914 qPrint(target));
915 }
916 else
917 {
918 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"\\cite command to '%s' does not have an associated number",
919 qPrint(target));
920 }
921}
922
923//---------------------------------------------------------------------------
924
926{
927 const Definition *compound = nullptr;
929 m_refText = target;
930 m_relPath = parser->context.relPath;
931 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
932 {
933 m_refText = m_refText.right(m_refText.length()-1);
934 }
935 if (resolveLink(parser->context.context,stripKnownExtensions(target),parser->context.inSeeBlock,&compound,anchor,parser->context.prefix))
936 {
937 m_anchor = anchor;
938 if (compound && compound->isLinkable())
939 {
940 m_file = compound->getOutputFileBase();
941 m_ref = compound->getReference();
942 }
943 else if (compound && compound->definitionType()==Definition::TypeFile &&
944 (toFileDef(compound))->generateSourceFile()
945 ) // undocumented file that has source code we can link to
946 {
947 m_file = compound->getSourceFileBase();
948 m_ref = compound->getReference();
949 }
950 return;
951 }
952
953 // bogus link target
954 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"unable to resolve link to '%s' for \\link command",
955 qPrint(target));
956}
957
958
959QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
960{
961 AUTO_TRACE();
962 QCString result;
963 auto ns = AutoNodeStack(parser(),thisVariant());
964
965 Token tok = parser()->tokenizer.lex();
966 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
967 {
968 if (!parser()->defaultHandleToken(thisVariant(),tok,children(),FALSE))
969 {
970 switch (tok.value())
971 {
972 case TokenRetval::TK_COMMAND_AT:
973 // fall through
974 case TokenRetval::TK_COMMAND_BS:
975 switch (Mappers::cmdMapper->map(parser()->context.token->name))
976 {
978 if (isJavaLink)
979 {
980 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'{@link...' ended with '%c%s' command",
981 tok.command_to_char(),qPrint(parser()->context.token->name));
982 }
983 goto endlink;
984 default:
985 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '%c%s' as part of a \\link",
986 tok.command_to_char(),qPrint(parser()->context.token->name));
987 break;
988 }
989 break;
990 case TokenRetval::TK_SYMBOL:
991 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '%s' found as part of a \\link",
992 qPrint(parser()->context.token->name));
993 break;
994 case TokenRetval::TK_HTMLTAG:
995 if (parser()->context.token->name!="see" || !isXmlLink)
996 {
997 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected xml/html command %s found as part of a \\link",
998 qPrint(parser()->context.token->name));
999 }
1000 goto endlink;
1001 case TokenRetval::TK_LNKWORD:
1002 case TokenRetval::TK_WORD:
1003 if (isJavaLink) // special case to detect closing }
1004 {
1006 int p = 0;
1007 if (w=="}")
1008 {
1009 goto endlink;
1010 }
1011 else if ((p=w.find('}'))!=-1)
1012 {
1013 int l = static_cast<int>(w.length());
1015 if (p<l-1) // something left after the } (for instance a .)
1016 {
1017 result=w.right(l-p-1);
1018 }
1019 goto endlink;
1020 }
1021 }
1023 break;
1024 default:
1025 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token %s",tok.to_string());
1026 break;
1027 }
1028 }
1029 tok = parser()->tokenizer.lex();
1030 }
1031 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1032 {
1033 warn_doc_error(parser()->context.fileName,
1034 parser()->tokenizer.getLineNr(),
1035 "Unexpected end of comment while inside link command");
1036 }
1037endlink:
1038
1039 if (children().empty()) // no link text
1040 {
1042 }
1043
1045 return result;
1046}
1047
1048
1049//---------------------------------------------------------------------------
1050
1057
1059{
1060 bool ok = false;
1062
1063 bool ambig = false;
1065 if (fd==nullptr && !p->name.endsWith(".dot")) // try with .dot extension as well
1066 {
1067 fd = findFileDef(Doxygen::dotFileNameLinkedMap,p->name+".dot",ambig);
1068 }
1069 if (fd)
1070 {
1071 p->file = fd->absFilePath();
1072 ok = true;
1073 if (ambig)
1074 {
1075 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file name '%s' is ambiguous.\n"
1076 "Possible candidates:\n%s",qPrint(p->name),
1078 );
1079 }
1080 }
1081 else
1082 {
1083 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dot file '%s' is not found "
1084 "in any of the paths specified via DOTFILE_DIRS!",qPrint(p->name));
1085 }
1086 return ok;
1087}
1088
1095
1097{
1098 bool ok = false;
1100
1101 bool ambig = false;
1103 if (fd==nullptr && !p->name.endsWith(".msc")) // try with .msc extension as well
1104 {
1105 fd = findFileDef(Doxygen::mscFileNameLinkedMap,p->name+".msc",ambig);
1106 }
1107 if (fd)
1108 {
1109 p->file = fd->absFilePath();
1110 ok = true;
1111 if (ambig)
1112 {
1113 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file name '%s' is ambiguous.\n"
1114 "Possible candidates:\n%s",qPrint(p->name),
1116 );
1117 }
1118 }
1119 else
1120 {
1121 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included msc file '%s' is not found "
1122 "in any of the paths specified via MSCFILE_DIRS!",qPrint(p->name));
1123 }
1124 return ok;
1125}
1126
1127//---------------------------------------------------------------------------
1128
1135
1137{
1138 bool ok = false;
1140
1141 bool ambig = false;
1143 if (fd==nullptr && !p->name.endsWith(".dia")) // try with .dia extension as well
1144 {
1145 fd = findFileDef(Doxygen::diaFileNameLinkedMap,p->name+".dia",ambig);
1146 }
1147 if (fd)
1148 {
1149 p->file = fd->absFilePath();
1150 ok = true;
1151 if (ambig)
1152 {
1153 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file name '%s' is ambiguous.\n"
1154 "Possible candidates:\n%s",qPrint(p->name),
1156 );
1157 }
1158 }
1159 else
1160 {
1161 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included dia file '%s' is not found "
1162 "in any of the paths specified via DIAFILE_DIRS!",qPrint(p->name));
1163 }
1164 return ok;
1165}
1166//---------------------------------------------------------------------------
1167
1174
1176{
1177 bool ok = false;
1179
1180 bool ambig = false;
1182 if (fd==nullptr && !p->name.endsWith(".puml")) // try with .puml extension as well
1183 {
1184 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".puml",ambig);
1185 if (fd==nullptr && !p->name.endsWith(".pu")) // try with .pu extension as well
1186 {
1187 fd = findFileDef(Doxygen::plantUmlFileNameLinkedMap,p->name+".pu",ambig);
1188 }
1189 }
1190 if (fd)
1191 {
1192 p->file = fd->absFilePath();
1193 ok = true;
1194 if (ambig)
1195 {
1196 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file name '%s' is ambiguous.\n"
1197 "Possible candidates:\n%s",qPrint(p->name),
1199 );
1200 }
1201 }
1202 else
1203 {
1204 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"included uml file '%s' is not found "
1205 "in any of the paths specified via PLANTUMLFILE_DIRS!",qPrint(p->name));
1206 }
1207 return ok;
1208}
1209
1210//---------------------------------------------------------------------------
1211
1215
1217{
1218 AUTO_TRACE();
1219 auto ns = AutoNodeStack(parser(),thisVariant());
1220
1222 Token tok = parser()->tokenizer.lex();
1223 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1224 {
1225 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1226 {
1227 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"\\vhdlflow");
1228 }
1229 tok = parser()->tokenizer.lex();
1230 }
1231 parser()->tokenizer.lex();
1232
1235
1236 VhdlDocGen::createFlowChart(parser()->context.memberDef);
1237}
1238
1239
1240//---------------------------------------------------------------------------
1241
1243 Type t,const QCString &url, bool inlineImage) :
1244 DocCompoundNode(parser,parent), p(std::make_unique<Private>(attribs, name, t, parser->context.relPath, url, inlineImage))
1245{
1246}
1247
1249{
1250 QCString locName = p->url.isEmpty() ? p->name : p->url;
1251 int len = static_cast<int>(locName.length());
1252 int fnd = locName.find('?'); // ignore part from ? until end
1253 if (fnd==-1) fnd=len;
1254 return fnd>=4 && locName.mid(fnd-4,4)==".svg";
1255}
1256
1261
1262
1263//---------------------------------------------------------------------------
1264
1266{
1267 AUTO_TRACE();
1268 Token retval(TokenRetval::RetVal_OK);
1269 auto ns = AutoNodeStack(parser(),thisVariant());
1270
1271 Token tok = parser()->tokenizer.lex();
1272 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1273 {
1274 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1275 {
1276 switch (tok.value())
1277 {
1278 case TokenRetval::TK_HTMLTAG:
1279 {
1280 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1281 if (tagId==HtmlTagType::HTML_H1 && parser()->context.token->endTag) // found </h1> tag
1282 {
1283 if (m_level!=1)
1284 {
1285 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h%d> ended with </h1>",
1286 m_level);
1287 }
1288 goto endheader;
1289 }
1290 else if (tagId==HtmlTagType::HTML_H2 && parser()->context.token->endTag) // found </h2> tag
1291 {
1292 if (m_level!=2)
1293 {
1294 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h%d> ended with </h2>",
1295 m_level);
1296 }
1297 goto endheader;
1298 }
1299 else if (tagId==HtmlTagType::HTML_H3 && parser()->context.token->endTag) // found </h3> tag
1300 {
1301 if (m_level!=3)
1302 {
1303 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h%d> ended with </h3>",
1304 m_level);
1305 }
1306 goto endheader;
1307 }
1308 else if (tagId==HtmlTagType::HTML_H4 && parser()->context.token->endTag) // found </h4> tag
1309 {
1310 if (m_level!=4)
1311 {
1312 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h%d> ended with </h4>",
1313 m_level);
1314 }
1315 goto endheader;
1316 }
1317 else if (tagId==HtmlTagType::HTML_H5 && parser()->context.token->endTag) // found </h5> tag
1318 {
1319 if (m_level!=5)
1320 {
1321 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h%d> ended with </h5>",
1322 m_level);
1323 }
1324 goto endheader;
1325 }
1326 else if (tagId==HtmlTagType::HTML_H6 && parser()->context.token->endTag) // found </h6> tag
1327 {
1328 if (m_level!=6)
1329 {
1330 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"<h%d> ended with </h6>",
1331 m_level);
1332 }
1333 goto endheader;
1334 }
1335 else if (tagId==HtmlTagType::HTML_A)
1336 {
1337 if (!parser()->context.token->endTag)
1338 {
1339 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
1340 }
1341 }
1342 else if (tagId==HtmlTagType::HTML_BR)
1343 {
1345 }
1346 else
1347 {
1348 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <%s%s> found within <h%d> context",
1349 parser()->context.token->endTag?"/":"",qPrint(parser()->context.token->name),m_level);
1350 }
1351 }
1352 break;
1353 default:
1354 char tmp[20];
1355 qsnprintf(tmp,20,"<h%d>tag",m_level);
1357 }
1358 }
1359 tok = parser()->tokenizer.lex();
1360 }
1361 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1362 {
1363 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1364 " <h%d> tag",m_level);
1365 }
1366endheader:
1368 return retval;
1369}
1370//---------------------------------------------------------------------------
1371
1373{
1374 AUTO_TRACE();
1375 auto ns = AutoNodeStack(parser(),thisVariant());
1377 Token tok = parser()->tokenizer.lex();
1378 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1379 {
1381 // check of </summary>
1382 if (tok.value()==TokenRetval::TK_HTMLTAG &&
1383 (tagId=Mappers::htmlTagMapper->map(parser()->context.token->name))==HtmlTagType::XML_SUMMARY &&
1384 parser()->context.token->endTag
1385 )
1386 {
1387 break;
1388 }
1389 else if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1390 {
1391 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"summary section");
1392 }
1393 tok = parser()->tokenizer.lex();
1394 }
1396 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1397 {
1398 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1399 " <summary> tag");
1400 }
1401}
1402
1403//---------------------------------------------------------------------------
1404
1406{
1407 AUTO_TRACE();
1408 Token retval(TokenRetval::TK_NONE);
1409 auto ns = AutoNodeStack(parser(),thisVariant());
1410
1411 // parse one or more paragraphs
1412 bool isFirst=TRUE;
1413 DocPara *par=nullptr;
1414 do
1415 {
1417 par = children().get_last<DocPara>();
1418 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1419 retval=par->parse();
1420 }
1421 while (retval.is(TokenRetval::TK_NEWPARA));
1422 if (par) par->markLast();
1423
1424 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1425 {
1426 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <details> block");
1427 }
1428
1429 if (!summary())
1430 {
1431 HtmlAttribList summaryAttribs;
1433 DocHtmlSummary *summary = &std::get<DocHtmlSummary>(*m_summary);
1434 summary->children().append<DocWord>(parser(),thisVariant(),theTranslator->trDetails());
1435 }
1436 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1437 return retval.is(TokenRetval::RetVal_EndHtmlDetails) ? Token::make_RetVal_OK() : retval;
1438}
1439
1447
1448//---------------------------------------------------------------------------
1449
1451{
1452 AUTO_TRACE();
1453 Token retval(TokenRetval::RetVal_OK);
1454 auto ns = AutoNodeStack(parser(),thisVariant());
1455
1456 Token tok = parser()->tokenizer.lex();
1457 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1458 {
1459 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1460 {
1461 switch (tok.value())
1462 {
1463 case TokenRetval::TK_HTMLTAG:
1464 {
1465 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1466 if (tagId==HtmlTagType::HTML_A && parser()->context.token->endTag) // found </a> tag
1467 {
1468 goto endhref;
1469 }
1470 else if (tagId==HtmlTagType::HTML_BR)
1471 {
1473 }
1474 else
1475 {
1476 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <%s%s> found within <a href=...> context",
1477 parser()->context.token->endTag?"/":"",qPrint(parser()->context.token->name));
1478 }
1479 }
1480 break;
1481 default:
1482 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<a>..</a> block");
1483 break;
1484 }
1485 }
1486 tok = parser()->tokenizer.lex();
1487 }
1488 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1489 {
1490 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1491 " <a href=...> tag");
1492 }
1493endhref:
1495 return retval;
1496}
1497
1498//---------------------------------------------------------------------------
1499
1501{
1502 AUTO_TRACE();
1503 Token retval(TokenRetval::RetVal_OK);
1504 auto ns = AutoNodeStack(parser(),thisVariant());
1505
1506 // first parse any number of paragraphs
1507 bool isFirst=TRUE;
1508 DocPara *lastPar=nullptr;
1509 do
1510 {
1512 DocPara *par = children().get_last<DocPara>();
1513 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1514 retval=par->parse();
1515 if (!par->isEmpty())
1516 {
1517 if (lastPar) lastPar->markLast(FALSE);
1518 lastPar=par;
1519 }
1520 else
1521 {
1522 children().pop_back();
1523 }
1524 if (retval.is(TokenRetval::TK_LISTITEM))
1525 {
1526 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
1527 }
1528 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
1529 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
1530 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
1531 TokenRetval::RetVal_EndInternal));
1532 if (lastPar) lastPar->markLast();
1533
1534 // then parse any number of level-n sections
1535 while ((level==1 && retval.is(TokenRetval::RetVal_Section)) ||
1536 (level==2 && retval.is(TokenRetval::RetVal_Subsection)) ||
1537 (level==3 && retval.is(TokenRetval::RetVal_Subsubsection)) ||
1538 (level==4 && retval.is(TokenRetval::RetVal_Paragraph)) ||
1539 (level==5 && retval.is(TokenRetval::RetVal_SubParagraph)) ||
1540 (level==6 && retval.is(TokenRetval::RetVal_SubSubParagraph))
1541 )
1542 {
1544 level,
1546 retval = children().get_last<DocSection>()->parse();
1547 }
1548
1549 if (retval.is(TokenRetval::RetVal_Internal))
1550 {
1551 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"\\internal command found inside internal section");
1552 }
1553
1554 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1555 return retval;
1556}
1557
1558//---------------------------------------------------------------------------
1559
1561{
1562 AUTO_TRACE();
1563 Token retval(TokenRetval::RetVal_OK);
1564 auto ns = AutoNodeStack(parser(),thisVariant());
1565 Token tok=parser()->tokenizer.lex();
1566 if (!tok.is(TokenRetval::TK_WHITESPACE))
1567 {
1568 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\addindex command");
1569 goto endindexentry;
1570 }
1572 m_entry="";
1573 tok = parser()->tokenizer.lex();
1574 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1575 {
1576 switch (tok.value())
1577 {
1578 case TokenRetval::TK_WHITESPACE:
1579 m_entry+=" ";
1580 break;
1581 case TokenRetval::TK_WORD:
1582 case TokenRetval::TK_LNKWORD:
1584 break;
1585 case TokenRetval::TK_SYMBOL:
1586 {
1587 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
1588 switch (s)
1589 {
1590 case HtmlEntityMapper::Sym_BSlash: m_entry+='\\'; break;
1591 case HtmlEntityMapper::Sym_At: m_entry+='@'; break;
1592 case HtmlEntityMapper::Sym_Less: m_entry+='<'; break;
1593 case HtmlEntityMapper::Sym_Greater: m_entry+='>'; break;
1594 case HtmlEntityMapper::Sym_Amp: m_entry+='&'; break;
1595 case HtmlEntityMapper::Sym_Dollar: m_entry+='$'; break;
1596 case HtmlEntityMapper::Sym_Hash: m_entry+='#'; break;
1597 case HtmlEntityMapper::Sym_Percent: m_entry+='%'; break;
1598 case HtmlEntityMapper::Sym_apos: m_entry+='\''; break;
1599 case HtmlEntityMapper::Sym_Quot: m_entry+='"'; break;
1600 case HtmlEntityMapper::Sym_lsquo: m_entry+='`'; break;
1601 case HtmlEntityMapper::Sym_rsquo: m_entry+='\''; break;
1602 case HtmlEntityMapper::Sym_ldquo: m_entry+="``"; break;
1603 case HtmlEntityMapper::Sym_rdquo: m_entry+="''"; break;
1604 case HtmlEntityMapper::Sym_ndash: m_entry+="--"; break;
1605 case HtmlEntityMapper::Sym_mdash: m_entry+="---"; break;
1606 default:
1607 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected symbol '%s' found as argument of \\addindex",qPrint(parser()->context.token->name));
1608 break;
1609 }
1610 }
1611 break;
1612 case TokenRetval::TK_COMMAND_AT:
1613 // fall through
1614 case TokenRetval::TK_COMMAND_BS:
1615 switch (Mappers::cmdMapper->map(parser()->context.token->name))
1616 {
1617 case CommandType::CMD_BSLASH: m_entry+='\\'; break;
1618 case CommandType::CMD_AT: m_entry+='@'; break;
1619 case CommandType::CMD_LESS: m_entry+='<'; break;
1620 case CommandType::CMD_GREATER: m_entry+='>'; break;
1621 case CommandType::CMD_AMP: m_entry+='&'; break;
1622 case CommandType::CMD_DOLLAR: m_entry+='$'; break;
1623 case CommandType::CMD_HASH: m_entry+='#'; break;
1624 case CommandType::CMD_DCOLON: m_entry+="::"; break;
1625 case CommandType::CMD_PERCENT: m_entry+='%'; break;
1626 case CommandType::CMD_NDASH: m_entry+="--"; break;
1627 case CommandType::CMD_MDASH: m_entry+="---"; break;
1628 case CommandType::CMD_QUOTE: m_entry+='"'; break;
1629 case CommandType::CMD_PUNT: m_entry+='.'; break;
1630 case CommandType::CMD_PLUS: m_entry+='+'; break;
1631 case CommandType::CMD_MINUS: m_entry+='-'; break;
1632 case CommandType::CMD_EQUAL: m_entry+='='; break;
1633 case CommandType::CMD_EXCLAMATION: m_entry+='!'; break;
1634 case CommandType::CMD_QUESTION: m_entry+='?'; break;
1635 default:
1636 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command %s found as argument of \\addindex",
1637 qPrint(parser()->context.token->name));
1638 break;
1639 }
1640 break;
1641 default:
1642 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token %s",
1643 tok.to_string());
1644 break;
1645 }
1646 tok = parser()->tokenizer.lex();
1647 }
1649 m_entry = m_entry.stripWhiteSpace();
1650endindexentry:
1651 AUTO_TRACE_EXIT("retval={}",retval.to_string());
1652 return retval;
1653}
1654
1655//---------------------------------------------------------------------------
1656
1659{
1661 for (const auto &opt : attribs)
1662 {
1663 if (opt.name=="id" && !opt.value.isEmpty()) // interpret id attribute as an anchor
1664 {
1665 const SectionInfo *sec = SectionManager::instance().find(opt.value);
1666 if (sec)
1667 {
1668 //printf("Found anchor %s\n",qPrint(id));
1669 m_file = sec->fileName();
1670 m_anchor = sec->label();
1672 }
1673 else
1674 {
1675 warn_doc_error(parser->context.fileName,parser->tokenizer.getLineNr(),"Invalid caption id '%s'",qPrint(opt.value));
1676 }
1677 }
1678 else // copy attribute
1679 {
1680 m_attribs.push_back(opt);
1681 }
1682 }
1683}
1684
1686{
1687 AUTO_TRACE();
1688 Token retval = Token::make_TK_NONE();
1689 auto ns = AutoNodeStack(parser(),thisVariant());
1690 Token tok = parser()->tokenizer.lex();
1691 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
1692 {
1693 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
1694 {
1695 switch (tok.value())
1696 {
1697 case TokenRetval::TK_HTMLTAG:
1698 {
1699 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1700 if (tagId==HtmlTagType::HTML_CAPTION && parser()->context.token->endTag) // found </caption> tag
1701 {
1702 retval = Token::make_RetVal_OK();
1703 goto endcaption;
1704 }
1705 else
1706 {
1707 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <%s%s> found within <caption> context",
1708 parser()->context.token->endTag?"/":"",qPrint(parser()->context.token->name));
1709 }
1710 }
1711 break;
1712 default:
1713 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"<caption> tag");
1714 break;
1715 }
1716 }
1717 tok = parser()->tokenizer.lex();
1718 }
1719 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
1720 {
1721 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
1722 " <caption> tag");
1723 }
1724endcaption:
1726 return retval;
1727}
1728
1729//---------------------------------------------------------------------------
1730
1732{
1733 AUTO_TRACE();
1734 Token retval = Token::make_RetVal_OK();
1735 auto ns = AutoNodeStack(parser(),thisVariant());
1736
1737 // parse one or more paragraphs
1738 bool isFirst=TRUE;
1739 DocPara *par=nullptr;
1740 do
1741 {
1743 par = children().get_last<DocPara>();
1744 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1745 retval=par->parse();
1746 if (retval.is(TokenRetval::TK_HTMLTAG))
1747 {
1748 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1749 if (tagId==HtmlTagType::HTML_TD && parser()->context.token->endTag) // found </td> tag
1750 {
1751 retval = Token::make_TK_NEWPARA(); // ignore the tag
1752 }
1753 else if (tagId==HtmlTagType::HTML_TH && parser()->context.token->endTag) // found </th> tag
1754 {
1755 retval = Token::make_TK_NEWPARA(); // ignore the tag
1756 }
1757 }
1758 }
1759 while (retval.is_any_of(TokenRetval::TK_NEWPARA,TokenRetval::RetVal_EndParBlock));
1760 if (par) par->markLast();
1761
1762 return retval;
1763}
1764
1766{
1767 AUTO_TRACE();
1768 Token retval = Token::make_RetVal_OK();
1769 auto ns = AutoNodeStack(parser(),thisVariant());
1770
1771 // parse one or more paragraphs
1772 bool isFirst=TRUE;
1773 DocPara *par=nullptr;
1774 do
1775 {
1777 par = children().get_last<DocPara>();
1778 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1779 retval=par->parse();
1780 if (retval.is(TokenRetval::TK_HTMLTAG))
1781 {
1782 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1783 if (tagId==HtmlTagType::XML_ITEM && parser()->context.token->endTag) // found </item> tag
1784 {
1785 retval = Token::make_TK_NEWPARA(); // ignore the tag
1786 }
1787 else if (tagId==HtmlTagType::XML_DESCRIPTION && parser()->context.token->endTag) // found </description> tag
1788 {
1789 retval = Token::make_TK_NEWPARA(); // ignore the tag
1790 }
1791 }
1792 }
1793 while (retval.is(TokenRetval::TK_NEWPARA));
1794 if (par) par->markLast();
1795
1796 return retval;
1797}
1798
1799uint32_t DocHtmlCell::rowSpan() const
1800{
1801 for (const auto &attr : attribs())
1802 {
1803 if (attr.name.lower()=="rowspan")
1804 {
1805 return attr.value.toUInt();
1806 }
1807 }
1808 return 0;
1809}
1810
1811uint32_t DocHtmlCell::colSpan() const
1812{
1813 for (const auto &attr : attribs())
1814 {
1815 if (attr.name.lower()=="colspan")
1816 {
1817 return std::max(1u,attr.value.toUInt());
1818 }
1819 }
1820 return 1;
1821}
1822
1824{
1825 for (const auto &attr : attribs())
1826 {
1827 QCString attrName = attr.name.lower();
1828 QCString attrValue = attr.value.lower();
1829 if (attrName=="align")
1830 {
1831 if (attrValue=="center")
1832 return Center;
1833 else if (attrValue=="right")
1834 return Right;
1835 else return Left;
1836 }
1837 else if (attrName=="class" && attrValue.startsWith("markdowntable"))
1838 {
1839 if (attrValue=="markdowntableheadcenter")
1840 return Center;
1841 else if (attrValue=="markdowntableheadright")
1842 return Right;
1843 else if (attrValue=="markdowntableheadleft")
1844 return Left;
1845 else if (attrValue=="markdowntableheadnone")
1846 return Center;
1847 else if (attrValue=="markdowntablebodycenter")
1848 return Center;
1849 else if (attrValue=="markdowntablebodyright")
1850 return Right;
1851 else if (attrValue=="markdowntablebodyleft")
1852 return Left;
1853 else if (attrValue=="markdowntablebodynone")
1854 return Left;
1855 else return Left;
1856 }
1857 }
1858 return Left;
1859}
1860
1862{
1863 for (const auto &attr : attribs())
1864 {
1865 QCString attrName = attr.name.lower();
1866 QCString attrValue = attr.value.lower();
1867 if (attrName=="valign")
1868 {
1869 if (attrValue=="top")
1870 return Top;
1871 else if (attrValue=="bottom")
1872 return Bottom;
1873 else if (attrValue=="middle")
1874 return Middle;
1875 else return Middle;
1876 }
1877 }
1878 return Middle;
1879}
1880
1881//---------------------------------------------------------------------------
1882
1884{ // a row is a table heading if all cells are marked as such
1885 bool heading=TRUE;
1886 for (const auto &n : children())
1887 {
1888 const DocHtmlCell *cell = std::get_if<DocHtmlCell>(&n);
1889 if (cell && !cell->isHeading())
1890 {
1891 heading = FALSE;
1892 break;
1893 }
1894 }
1895 return !children().empty() && heading;
1896}
1897
1899{
1900 AUTO_TRACE();
1901 Token retval = Token::make_RetVal_OK();
1902 auto ns = AutoNodeStack(parser(),thisVariant());
1903
1904 bool isHeading=FALSE;
1905 bool isFirst=TRUE;
1906 DocHtmlCell *cell=nullptr;
1907
1908 // get next token
1909 Token tok=parser()->tokenizer.lex();
1910 // skip whitespace
1911 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
1912 // should find a html tag now
1913 if (tok.is(TokenRetval::TK_HTMLTAG))
1914 {
1915 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1916 if (tagId==HtmlTagType::HTML_TD && !parser()->context.token->endTag) // found <td> tag
1917 {
1918 }
1919 else if (tagId==HtmlTagType::HTML_TH && !parser()->context.token->endTag) // found <th> tag
1920 {
1922 }
1923 else // found some other tag
1924 {
1925 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but "
1926 "found <%s> instead!",qPrint(parser()->context.token->name));
1927 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
1928 goto endrow;
1929 }
1930 }
1931 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
1932 {
1933 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
1934 " for a html description title");
1935 goto endrow;
1936 }
1937 else // token other than html token
1938 {
1939 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found %s token instead!",
1940 tok.to_string());
1941 goto endrow;
1942 }
1943
1944 // parse one or more cells
1945 do
1946 {
1949 isHeading);
1950 cell = children().get_last<DocHtmlCell>();
1951 cell->markFirst(isFirst);
1952 isFirst=FALSE;
1953 retval=cell->parse();
1954 isHeading = retval.is(TokenRetval::RetVal_TableHCell);
1955 }
1956 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
1957 cell->markLast(TRUE);
1958
1959endrow:
1960 return retval;
1961}
1962
1964{
1965 AUTO_TRACE();
1966 Token retval = Token::make_RetVal_OK();
1967 auto ns = AutoNodeStack(parser(),thisVariant());
1968
1969 bool isFirst=TRUE;
1970 DocHtmlCell *cell=nullptr;
1971
1972 // get next token
1973 Token tok=parser()->tokenizer.lex();
1974 // skip whitespace
1975 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
1976 // should find a html tag now
1977 if (tok.is(TokenRetval::TK_HTMLTAG))
1978 {
1979 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
1980 if (tagId==HtmlTagType::XML_TERM && !parser()->context.token->endTag) // found <term> tag
1981 {
1982 }
1983 else if (tagId==HtmlTagType::XML_DESCRIPTION && !parser()->context.token->endTag) // found <description> tag
1984 {
1985 }
1986 else // found some other tag
1987 {
1988 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <term> or <description> tag but "
1989 "found <%s> instead!",qPrint(parser()->context.token->name));
1990 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
1991 goto endrow;
1992 }
1993 }
1994 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
1995 {
1996 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
1997 " for a html description title");
1998 goto endrow;
1999 }
2000 else // token other than html token
2001 {
2002 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <td> or <th> tag but found %s token instead!",
2003 tok.to_string());
2004 goto endrow;
2005 }
2006
2007 do
2008 {
2010 cell = children().get_last<DocHtmlCell>();
2011 cell->markFirst(isFirst);
2012 isFirst=FALSE;
2013 retval=cell->parseXml();
2014 }
2015 while (retval.is_any_of(TokenRetval::RetVal_TableCell,TokenRetval::RetVal_TableHCell));
2016 cell->markLast(TRUE);
2017
2018endrow:
2019 return retval;
2020}
2021
2022//---------------------------------------------------------------------------
2023
2025{
2026 return m_caption!=nullptr;
2027}
2028
2030{
2031 return m_caption.get();
2032}
2033
2035{
2036 if (!children().empty() && std::holds_alternative<DocHtmlRow>(children().front()))
2037 {
2038 return &children().front();
2039 }
2040 return nullptr;
2041}
2042
2044{
2045 AUTO_TRACE();
2046 Token retval = Token::make_RetVal_OK();
2047 auto ns = AutoNodeStack(parser(),thisVariant());
2048
2049getrow:
2050 // get next token
2051 Token tok=parser()->tokenizer.lex();
2052 // skip whitespace
2053 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2054 // should find a html tag now
2055 if (tok.is(TokenRetval::TK_HTMLTAG))
2056 {
2057 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2058 if (tagId==HtmlTagType::HTML_THEAD && !parser()->context.token->endTag) // found <thead> tag
2059 {
2060 goto getrow;
2061 }
2062 else if (tagId==HtmlTagType::HTML_TBODY && !parser()->context.token->endTag) // found <tbody> tag
2063 {
2064 goto getrow;
2065 }
2066 else if (tagId==HtmlTagType::HTML_TFOOT && !parser()->context.token->endTag) // found <tfoot> tag
2067 {
2068 goto getrow;
2069 }
2070 else if (tagId==HtmlTagType::HTML_TR && !parser()->context.token->endTag) // found <tr> tag
2071 {
2072 // no caption, just rows
2073 retval = Token::make_RetVal_TableRow();
2074 }
2075 else if (tagId==HtmlTagType::HTML_CAPTION && !parser()->context.token->endTag) // found <caption> tag
2076 {
2077 if (m_caption)
2078 {
2079 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"table already has a caption, found another one");
2080 }
2081 else
2082 {
2083 m_caption = createDocNode<DocHtmlCaption>(parser(),thisVariant(),parser()->context.token->attribs);
2084 retval=std::get<DocHtmlCaption>(*m_caption).parse();
2085
2086 if (retval.is(TokenRetval::RetVal_OK)) // caption was parsed ok
2087 {
2088 goto getrow;
2089 }
2090 }
2091 }
2092 else // found wrong token
2093 {
2094 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> or <caption> tag but "
2095 "found <%s%s> instead!", parser()->context.token->endTag ? "/" : "", qPrint(parser()->context.token->name));
2096 }
2097 }
2098 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2099 {
2100 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2101 " for a <tr> or <caption> tag");
2102 }
2103 else // token other than html token
2104 {
2105 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <tr> tag but found %s token instead!",
2106 tok.to_string());
2107 }
2108
2109 // parse one or more rows
2110 while (retval.is(TokenRetval::RetVal_TableRow))
2111 {
2113 retval = children().get_last<DocHtmlRow>()->parse();
2114 }
2115
2117
2118 return retval.is(TokenRetval::RetVal_EndTable) ? Token::make_RetVal_OK() : retval;
2119}
2120
2122{
2123 AUTO_TRACE();
2124 Token retval = Token::make_RetVal_OK();
2125 auto ns = AutoNodeStack(parser(),thisVariant());
2126
2127 // get next token
2128 Token tok=parser()->tokenizer.lex();
2129 // skip whitespace
2130 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2131 // should find a html tag now
2133 bool isHeader=FALSE;
2134 if (tok.is(TokenRetval::TK_HTMLTAG))
2135 {
2136 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2137 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2138 {
2139 retval = Token::make_RetVal_TableRow();
2140 }
2141 if (tagId==HtmlTagType::XML_LISTHEADER && !parser()->context.token->endTag) // found <listheader> tag
2142 {
2143 retval = Token::make_RetVal_TableRow();
2144 isHeader=TRUE;
2145 }
2146 }
2147
2148 // parse one or more rows
2149 while (retval.is(TokenRetval::RetVal_TableRow))
2150 {
2153 retval=tr->parseXml(isHeader);
2154 isHeader=FALSE;
2155 }
2156
2158
2159 tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2160 return tagId==HtmlTagType::XML_LIST && parser()->context.token->endTag ? Token::make_RetVal_OK() : retval;
2161}
2162
2163/** Helper class to compute the grid for an HTML style table */
2165{
2166 ActiveRowSpan(uint32_t rows,uint32_t col) : rowsLeft(rows), column(col) {}
2167 uint32_t rowsLeft;
2168 uint32_t column;
2169};
2170
2171/** List of ActiveRowSpan classes. */
2172typedef std::vector<ActiveRowSpan> RowSpanList;
2173
2174/** determines the location of all cells in a grid, resolving row and
2175 column spans. For each the total number of visible cells is computed,
2176 and the total number of visible columns over all rows is stored.
2177 */
2179{
2180 //printf("computeTableGrid()\n");
2181 RowSpanList rowSpans;
2182 uint32_t maxCols=0;
2183 uint32_t rowIdx=1;
2184 for (auto &rowNode : children())
2185 {
2186 uint32_t colIdx=1;
2187 uint32_t cells=0;
2188 DocHtmlRow *row = std::get_if<DocHtmlRow>(&rowNode);
2189 if (row)
2190 {
2191 for (auto &cellNode : row->children())
2192 {
2193 DocHtmlCell *cell = std::get_if<DocHtmlCell>(&cellNode);
2194 if (cell)
2195 {
2196 uint32_t rs = cell->rowSpan();
2197 uint32_t cs = cell->colSpan();
2198
2199 for (size_t i=0;i<rowSpans.size();i++)
2200 {
2201 if (rowSpans[i].rowsLeft>0 &&
2202 rowSpans[i].column==colIdx)
2203 {
2204 colIdx=rowSpans[i].column+1;
2205 cells++;
2206 }
2207 }
2208 if (rs>0) rowSpans.emplace_back(rs,colIdx);
2209 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
2210 cell->setRowIndex(rowIdx);
2211 cell->setColumnIndex(colIdx);
2212 colIdx+=cs;
2213 cells++;
2214 }
2215 }
2216 for (size_t i=0;i<rowSpans.size();i++)
2217 {
2218 if (rowSpans[i].rowsLeft>0) rowSpans[i].rowsLeft--;
2219 }
2220 row->setVisibleCells(cells);
2221 row->setRowIndex(rowIdx);
2222 rowIdx++;
2223 }
2224 if (colIdx-1>maxCols) maxCols=colIdx-1;
2225 }
2226 m_numCols = maxCols;
2227}
2228
2229//---------------------------------------------------------------------------
2230
2232{
2233 AUTO_TRACE();
2234 Token retval = Token::make_TK_NONE();
2235 auto ns = AutoNodeStack(parser(),thisVariant());
2236
2237 Token tok = parser()->tokenizer.lex();
2238 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2239 {
2240 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2241 {
2242 switch (tok.value())
2243 {
2244 case TokenRetval::TK_COMMAND_AT:
2245 // fall through
2246 case TokenRetval::TK_COMMAND_BS:
2247 {
2248 QCString cmdName=parser()->context.token->name;
2249 bool isJavaLink=FALSE;
2250 switch (Mappers::cmdMapper->map(cmdName))
2251 {
2253 {
2254 tok=parser()->tokenizer.lex();
2255 if (!tok.is(TokenRetval::TK_WHITESPACE))
2256 {
2257 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
2258 tok.command_to_char(),qPrint(cmdName));
2259 }
2260 else
2261 {
2263 tok=parser()->tokenizer.lex(); // get the reference id
2264 if (!tok.is(TokenRetval::TK_WORD))
2265 {
2266 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s' command",
2267 tok.to_string(),tok.command_to_char(),qPrint(cmdName));
2268 }
2269 else
2270 {
2272 children().get_last<DocRef>()->parse();
2273 }
2275 }
2276 }
2277 break;
2279 isJavaLink=TRUE;
2280 // fall through
2282 {
2283 tok=parser()->tokenizer.lex();
2284 if (!tok.is(TokenRetval::TK_WHITESPACE))
2285 {
2286 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
2287 qPrint(cmdName));
2288 }
2289 else
2290 {
2292 tok=parser()->tokenizer.lex();
2293 if (!tok.is(TokenRetval::TK_WORD))
2294 {
2295 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of \\%s command",
2296 tok.to_string(),qPrint(cmdName));
2297 }
2298 else
2299 {
2302 DocLink *lnk = children().get_last<DocLink>();
2303 QCString leftOver = lnk->parse(isJavaLink);
2304 if (!leftOver.isEmpty())
2305 {
2306 children().append<DocWord>(parser(),thisVariant(),leftOver);
2307 }
2308 }
2309 }
2310 }
2311
2312 break;
2313 default:
2314 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal command '%c%s' found as part of a <dt> tag",
2315 tok.command_to_char(),qPrint(cmdName));
2316 }
2317 }
2318 break;
2319 case TokenRetval::TK_SYMBOL:
2320 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '%s' found as part of a <dt> tag",
2321 qPrint(parser()->context.token->name));
2322 break;
2323 case TokenRetval::TK_HTMLTAG:
2324 {
2325 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2326 if (tagId==HtmlTagType::HTML_DD && !parser()->context.token->endTag) // found <dd> tag
2327 {
2328 retval = Token::make_RetVal_DescData();
2329 goto endtitle;
2330 }
2331 else if (tagId==HtmlTagType::HTML_DT && parser()->context.token->endTag)
2332 {
2333 // ignore </dt> tag.
2334 }
2335 else if (tagId==HtmlTagType::HTML_DT)
2336 {
2337 // missing <dt> tag.
2338 retval = Token::make_RetVal_DescTitle();
2339 goto endtitle;
2340 }
2341 else if (tagId==HtmlTagType::HTML_DL && parser()->context.token->endTag)
2342 {
2343 retval = Token::make_RetVal_EndDesc();
2344 goto endtitle;
2345 }
2346 else if (tagId==HtmlTagType::HTML_A)
2347 {
2348 if (!parser()->context.token->endTag)
2349 {
2350 parser()->handleAHref(thisVariant(),children(),parser()->context.token->attribs);
2351 }
2352 }
2353 else
2354 {
2355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected html tag <%s%s> found within <dt> context",
2356 parser()->context.token->endTag?"/":"",qPrint(parser()->context.token->name));
2357 }
2358 }
2359 break;
2360 default:
2361 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token %s found as part of a <dt> tag",
2362 tok.to_string());
2363 break;
2364 }
2365 }
2366 tok = parser()->tokenizer.lex();
2367 }
2368 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2369 {
2370 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end of comment while inside"
2371 " <dt> tag");
2372 }
2373endtitle:
2375 return retval;
2376}
2377
2378//---------------------------------------------------------------------------
2379
2381{
2382 AUTO_TRACE();
2384 Token retval = Token::make_TK_NONE();
2385 auto ns = AutoNodeStack(parser(),thisVariant());
2386
2387 bool isFirst=TRUE;
2388 DocPara *par=nullptr;
2389 do
2390 {
2392 par = children().get_last<DocPara>();
2393 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2394 retval=par->parse();
2395 }
2396 while (retval.is(TokenRetval::TK_NEWPARA));
2397 if (par) par->markLast();
2398
2399 return retval;
2400}
2401
2402//---------------------------------------------------------------------------
2403
2405{
2406 AUTO_TRACE();
2407 Token retval = Token::make_RetVal_OK();
2408 auto ns = AutoNodeStack(parser(),thisVariant());
2409
2410 // get next token
2411 Token tok=parser()->tokenizer.lex();
2412 // skip whitespace
2413 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2414 // should find a html tag now
2415 if (tok.is(TokenRetval::TK_HTMLTAG))
2416 {
2417 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2418 if (tagId==HtmlTagType::HTML_DT && !parser()->context.token->endTag) // found <dt> tag
2419 {
2420 // continue
2421 }
2422 else // found some other tag
2423 {
2424 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but "
2425 "found <%s> instead!",qPrint(parser()->context.token->name));
2426 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2427 goto enddesclist;
2428 }
2429 }
2430 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2431 {
2432 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2433 " for a html description title");
2434 goto enddesclist;
2435 }
2436 else // token other than html token
2437 {
2438 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <dt> tag but found %s token instead!",
2439 tok.to_string());
2440 goto enddesclist;
2441 }
2442
2443 do
2444 {
2449 retval=dt->parse();
2450 if (retval.is(TokenRetval::RetVal_DescData))
2451 {
2452 retval=dd->parse();
2453 while (retval.is(TokenRetval::RetVal_DescData))
2454 {
2457 retval=dd->parse();
2458 }
2459 }
2460 else if (!retval.is(TokenRetval::RetVal_DescTitle))
2461 {
2462 // error
2463 break;
2464 }
2465 } while (retval.is(TokenRetval::RetVal_DescTitle));
2466
2467 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2468 {
2469 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <dl> block");
2470 }
2471
2472enddesclist:
2473
2474 return retval.is(TokenRetval::RetVal_EndDesc) ? Token::make_RetVal_OK() : retval;
2475}
2476
2477//---------------------------------------------------------------------------
2478
2480{
2481 AUTO_TRACE();
2482 Token retval = Token::make_TK_NONE();
2483 auto ns = AutoNodeStack(parser(),thisVariant());
2484
2485 // parse one or more paragraphs
2486 bool isFirst=TRUE;
2487 DocPara *par=nullptr;
2488 do
2489 {
2491 par = children().get_last<DocPara>();
2492 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2493 retval=par->parse();
2494 }
2495 while (retval.is(TokenRetval::TK_NEWPARA));
2496 if (par) par->markLast();
2497
2498 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2499 return retval;
2500}
2501
2503{
2504 AUTO_TRACE();
2505 Token retval = Token::make_TK_NONE();
2506 auto ns = AutoNodeStack(parser(),thisVariant());
2507
2508 // parse one or more paragraphs
2509 bool isFirst=TRUE;
2510 DocPara *par=nullptr;
2511 do
2512 {
2514 par = children().get_last<DocPara>();
2515 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2516 retval=par->parse();
2517 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2518
2519 //printf("new item: retval=%x parser()->context.token->name=%s parser()->context.token->endTag=%d\n",
2520 // retval,qPrint(parser()->context.token->name),parser()->context.token->endTag);
2521 if (retval.is(TokenRetval::RetVal_ListItem))
2522 {
2523 break;
2524 }
2525 }
2526 while (!retval.is(TokenRetval::RetVal_CloseXml));
2527
2528 if (par) par->markLast();
2529
2530 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2531 return retval;
2532}
2533
2534//---------------------------------------------------------------------------
2535
2537{
2538 AUTO_TRACE();
2539 Token retval = Token::make_RetVal_OK();
2540 int num=1;
2541 auto ns = AutoNodeStack(parser(),thisVariant());
2542
2543 // get next token
2544 Token tok=parser()->tokenizer.lex();
2545 // skip whitespace and paragraph breaks
2546 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2547 // should find a html tag now
2548 if (tok.is(TokenRetval::TK_HTMLTAG))
2549 {
2550 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2551 if (tagId==HtmlTagType::HTML_LI && !parser()->context.token->endTag) // found <li> tag
2552 {
2553 // ok, we can go on.
2554 }
2555 else if (((m_type==Unordered && tagId==HtmlTagType::HTML_UL) ||
2557 ) && parser()->context.token->endTag
2558 ) // found empty list
2559 {
2560 // add dummy item to obtain valid HTML
2562 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty list!");
2563 retval = Token::make_RetVal_EndList();
2564 goto endlist;
2565 }
2566 else // found some other tag
2567 {
2568 // add dummy item to obtain valid HTML
2570 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but "
2571 "found <%s%s> instead!",parser()->context.token->endTag?"/":"",qPrint(parser()->context.token->name));
2572 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2573 goto endlist;
2574 }
2575 }
2576 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2577 {
2578 // add dummy item to obtain valid HTML
2580 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2581 " for a html list item");
2582 goto endlist;
2583 }
2584 else // token other than html token
2585 {
2586 // add dummy item to obtain valid HTML
2588 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <li> tag but found %s token instead!",
2589 tok.to_string());
2590 goto endlist;
2591 }
2592
2593 do
2594 {
2597 retval=li->parse();
2598 } while (retval.is(TokenRetval::RetVal_ListItem));
2599
2600 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2601 {
2602 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <%cl> block",
2603 m_type==Unordered ? 'u' : 'o');
2604 }
2605
2606endlist:
2607 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2608 return retval.is(TokenRetval::RetVal_EndList) ? Token::make_RetVal_OK() : retval;
2609}
2610
2612{
2613 AUTO_TRACE();
2614 Token retval = Token::make_RetVal_OK();
2615 int num=1;
2616 auto ns = AutoNodeStack(parser(),thisVariant());
2617
2618 // get next token
2619 Token tok=parser()->tokenizer.lex();
2620 // skip whitespace and paragraph breaks
2621 while (tok.is_any_of(TokenRetval::TK_WHITESPACE,TokenRetval::TK_NEWPARA)) tok=parser()->tokenizer.lex();
2622 // should find a html tag now
2623 if (tok.is(TokenRetval::TK_HTMLTAG))
2624 {
2625 HtmlTagType tagId=Mappers::htmlTagMapper->map(parser()->context.token->name);
2626 //printf("parser()->context.token->name=%s parser()->context.token->endTag=%d\n",qPrint(parser()->context.token->name),parser()->context.token->endTag);
2627 if (tagId==HtmlTagType::XML_ITEM && !parser()->context.token->endTag) // found <item> tag
2628 {
2629 // ok, we can go on.
2630 }
2631 else // found some other tag
2632 {
2633 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but "
2634 "found <%s> instead!",qPrint(parser()->context.token->name));
2635 parser()->tokenizer.pushBackHtmlTag(parser()->context.token->name);
2636 goto endlist;
2637 }
2638 }
2639 else if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
2640 {
2641 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while looking"
2642 " for a html list item");
2643 goto endlist;
2644 }
2645 else // token other than html token
2646 {
2647 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected <item> tag but found %s token instead!",
2648 tok.to_string());
2649 goto endlist;
2650 }
2651
2652 do
2653 {
2656 retval=li->parseXml();
2657 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2658 //printf("retval=%x parser()->context.token->name=%s\n",retval,qPrint(parser()->context.token->name));
2659 } while (retval.is(TokenRetval::RetVal_ListItem));
2660
2661 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2662 {
2663 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <list type=\"%s\"> block",
2664 m_type==Unordered ? "bullet" : "number");
2665 }
2666
2667endlist:
2668 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2669 return (retval.is_any_of(TokenRetval::RetVal_EndList,TokenRetval::RetVal_CloseXml) || parser()->context.token->name=="list") ?
2670 Token::make_RetVal_OK() : retval;
2671}
2672
2673//--------------------------------------------------------------------------
2674
2676{
2677 AUTO_TRACE();
2678 Token retval = Token::make_TK_NONE();
2679 auto ns = AutoNodeStack(parser(),thisVariant());
2680
2681 // parse one or more paragraphs
2682 bool isFirst=TRUE;
2683 DocPara *par=nullptr;
2684 do
2685 {
2687 par = children().get_last<DocPara>();
2688 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2689 retval=par->parse();
2690 }
2691 while (retval.is(TokenRetval::TK_NEWPARA));
2692 if (par) par->markLast();
2693
2694 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
2695 {
2696 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment while inside <blockquote> block");
2697 }
2698
2699 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2700 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2701}
2702
2703//---------------------------------------------------------------------------
2704
2706{
2707 AUTO_TRACE();
2708 Token retval = Token::make_TK_NONE();
2709 auto ns = AutoNodeStack(parser(),thisVariant());
2710
2711 // parse one or more paragraphs
2712 bool isFirst=TRUE;
2713 DocPara *par=nullptr;
2714 do
2715 {
2717 par = children().get_last<DocPara>();
2718 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2719 retval=par->parse();
2720 }
2721 while (retval.is(TokenRetval::TK_NEWPARA));
2722 if (par) par->markLast();
2723
2724 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2725 return retval.is(TokenRetval::RetVal_EndBlockQuote) ? Token::make_RetVal_OK() : retval;
2726}
2727
2728//---------------------------------------------------------------------------
2729
2734
2735
2737{
2738 auto ns = AutoNodeStack(parser(),thisVariant());
2740 DocPara *par = &std::get<DocPara>(*m_paragraph);
2741 Token rv=par->parse();
2742 par->markFirst();
2743 par->markLast();
2744 return rv;
2745}
2746
2747//--------------------------------------------------------------------------
2748
2750{
2751 auto ns = AutoNodeStack(parser(),thisVariant());
2752 Token rv = Token::make_TK_NONE();
2753 do
2754 {
2757 rv=li->parse();
2758 } while (rv.is(TokenRetval::RetVal_ListItem));
2759 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
2760}
2761
2762//--------------------------------------------------------------------------
2763
2768
2770{
2771 AUTO_TRACE();
2772 Token retval = Token::make_RetVal_OK();
2773 auto ns = AutoNodeStack(parser(),thisVariant());
2774
2775 // first parse any number of paragraphs
2776 bool isFirst=TRUE;
2777 DocPara *lastPar=nullptr;
2778 do
2779 {
2781 DocPara *par = children().get_last<DocPara>();
2782 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2783 retval=par->parse();
2784 if (!par->isEmpty())
2785 {
2786 if (lastPar) lastPar->markLast(FALSE);
2787 lastPar=par;
2788 }
2789 else
2790 {
2791 children().pop_back();
2792 }
2793 // next paragraph should be more indented than the - marker to belong
2794 // to this item
2795 } while (retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->indent>m_indent);
2796 if (lastPar) lastPar->markLast();
2797
2798 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2799 return retval;
2800}
2801
2802//--------------------------------------------------------------------------
2803
2810
2812{
2813 AUTO_TRACE();
2814 Token retval = Token::make_RetVal_OK();
2815 int num=1;
2816 auto ns = AutoNodeStack(parser(),thisVariant());
2818 // first item or sub list => create new list
2819 do
2820 {
2821 switch (parser()->context.token->id)
2822 {
2823 case -1:
2824 break;
2825 case DocAutoList::Unchecked: // unchecked
2826 case DocAutoList::Checked_x: // checked with x
2827 case DocAutoList::Checked_X: // checked with X
2828 num = parser()->context.token->id;
2829 break;
2830 default: // explicitly numbered list
2831 num=parser()->context.token->id; // override num with real number given
2832 break;
2833 }
2834
2836 retval = children().get_last<DocAutoListItem>()->parse();
2837 //printf("DocAutoList::parse(): retval=0x%x parser()->context.token->indent=%d m_indent=%d "
2838 // "m_isEnumList=%d parser()->context.token->isEnumList=%d parser()->context.token->name=%s\n",
2839 // retval,parser()->context.token->indent,m_indent,m_isEnumList,parser()->context.token->isEnumList,
2840 // qPrint(parser()->context.token->name));
2841 //printf("num=%d parser()->context.token->id=%d\n",num,parser()->context.token->id);
2842 }
2843 while (retval.is(TokenRetval::TK_LISTITEM) && // new list item
2844 m_indent==parser()->context.token->indent && // at same indent level
2845 m_isEnumList==parser()->context.token->isEnumList && // of the same kind
2846 m_isCheckedList==parser()->context.token->isCheckedList && // of the same kind
2847 (parser()->context.token->id==-1 || parser()->context.token->id>=num) // increasing number (or no number or checked list)
2848 );
2849
2851 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2852 return retval;
2853}
2854
2855//--------------------------------------------------------------------------
2856
2858{
2859 AUTO_TRACE();
2860 auto ns = AutoNodeStack(parser(),thisVariant());
2862 Token tok = parser()->tokenizer.lex();
2863 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF))
2864 {
2865 if (!parser()->defaultHandleToken(thisVariant(),tok,children()))
2866 {
2867 parser()->errorHandleDefaultToken(thisVariant(),tok,children(),"title section");
2868 }
2869 tok = parser()->tokenizer.lex();
2870 }
2873}
2874
2876{
2878 parser()->pushContext(); // this will create a new parser->context.token
2880 parser()->popContext(); // this will restore the old parser->context.token
2884}
2885
2886//--------------------------------------------------------------------------
2887
2892
2894{
2895 return m_title && std::get<DocTitle>(*m_title).hasTitle();
2896}
2897
2898Token DocSimpleSect::parse(bool userTitle,bool needsSeparator)
2899{
2900 AUTO_TRACE();
2901 auto ns = AutoNodeStack(parser(),thisVariant());
2902
2903 // handle case for user defined title
2904 if (userTitle)
2905 {
2907 std::get_if<DocTitle>(m_title.get())->parse();
2908 }
2909
2910 // add new paragraph as child
2911 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
2912 {
2913 std::get<DocPara>(children().back()).markLast(FALSE);
2914 }
2915 bool markFirst = children().empty();
2916 if (needsSeparator)
2917 {
2919 }
2921 DocPara *par = children().get_last<DocPara>();
2922 if (markFirst)
2923 {
2924 par->markFirst();
2925 }
2926 par->markLast();
2927
2928 // parse the contents of the paragraph
2929 Token retval = par->parse();
2930
2931 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2932 return retval; // 0==EOF, TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, TokenRetval::TK_ENDLIST, TokenRetval::RetVal_SimpleSec
2933}
2934
2936{
2937 AUTO_TRACE();
2938 auto ns = AutoNodeStack(parser(),thisVariant());
2939
2941 DocTitle *title = &std::get<DocTitle>(*m_title);
2942 title->parseFromString(thisVariant(),parser()->context.token->name);
2943
2944 QCString text = parser()->context.token->text;
2945 parser()->pushContext(); // this will create a new parser->context.token
2947 parser()->popContext(); // this will restore the old parser->context.token
2948
2949 return Token::make_RetVal_OK();
2950}
2951
2953{
2954 AUTO_TRACE();
2955 auto ns = AutoNodeStack(parser(),thisVariant());
2956
2957 Token retval = Token::make_RetVal_OK();
2958 for (;;)
2959 {
2960 // add new paragraph as child
2961 if (!children().empty() && std::holds_alternative<DocPara>(children().back()))
2962 {
2963 std::get<DocPara>(children().back()).markLast(false);
2964 }
2965 bool markFirst = children().empty();
2967 DocPara *par = children().get_last<DocPara>();
2968 if (markFirst)
2969 {
2970 par->markFirst();
2971 }
2972 par->markLast();
2973
2974 // parse the contents of the paragraph
2975 retval = par->parse();
2976 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
2977 if (retval.is(TokenRetval::RetVal_CloseXml))
2978 {
2979 retval = Token::make_RetVal_OK();
2980 break;
2981 }
2982 }
2983
2984 AUTO_TRACE_EXIT("retval={}",retval.to_string());
2985 return retval;
2986}
2987
2989{
2990 DocPara *p=nullptr;
2991 if (children().empty() || (p=std::get_if<DocPara>(&children().back()))==nullptr)
2992 {
2994 p = children().get_last<DocPara>();
2995 }
2996 else
2997 {
2998 // Comma-separate <seealso> links.
2999 p->injectToken(Token::make_TK_WORD(),",");
3000 p->injectToken(Token::make_TK_WHITESPACE()," ");
3001 }
3002
3004 p->injectToken(Token::make_TK_LNKWORD(),word);
3006}
3007
3009{
3010 switch (m_type)
3011 {
3012 case Unknown: break;
3013 case See: return "see";
3014 case Return: return "return";
3015 case Author: // fall through
3016 case Authors: return "author";
3017 case Version: return "version";
3018 case Since: return "since";
3019 case Date: return "date";
3020 case Note: return "note";
3021 case Warning: return "warning";
3022 case Pre: return "pre";
3023 case Post: return "post";
3024 case Copyright: return "copyright";
3025 case Invar: return "invariant";
3026 case Remark: return "remark";
3027 case Attention: return "attention";
3028 case Important: return "important";
3029 case User: return "user";
3030 case Rcs: return "rcs";
3031 }
3032 return "unknown";
3033}
3034
3035//--------------------------------------------------------------------------
3036
3038{
3039 AUTO_TRACE();
3040 Token retval = Token::make_RetVal_OK();
3041 auto ns = AutoNodeStack(parser(),thisVariant());
3042 DocPara *par=nullptr;
3043 QCString saveCmdName = cmdName;
3044
3045 Token tok=parser()->tokenizer.lex();
3046 if (!tok.is(TokenRetval::TK_WHITESPACE))
3047 {
3048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
3049 qPrint(saveCmdName));
3050 retval = Token::make_RetVal_EndParBlock();
3051 goto endparamlist;
3052 }
3054 tok=parser()->tokenizer.lex();
3055 while (tok.is(TokenRetval::TK_WORD)) /* there is a parameter name */
3056 {
3058 {
3059 int typeSeparator = parser()->context.token->name.find('#'); // explicit type position
3060 if (typeSeparator!=-1)
3061 {
3062 parser()->handleParameterType(thisVariant(),m_paramTypes,parser()->context.token->name.left(typeSeparator));
3063 parser()->context.token->name = parser()->context.token->name.mid(typeSeparator+1);
3066 if (parent() && std::holds_alternative<DocParamSect>(*parent()))
3067 {
3068 std::get<DocParamSect>(*parent()).m_hasTypeSpecifier=true;
3069 }
3070 }
3071 else
3072 {
3075 }
3076 }
3077 else if (m_type==DocParamSect::RetVal)
3078 {
3081 }
3082 //m_params.append(parser()->context.token->name);
3084 tok=parser()->tokenizer.lex();
3085 }
3087 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) // premature end of comment
3088 {
3089 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3090 "argument of command %s",qPrint(saveCmdName));
3091 retval = Token::make_RetVal_EndParBlock();
3092 goto endparamlist;
3093 }
3094 if (!tok.is(TokenRetval::TK_WHITESPACE)) /* premature end of comment block */
3095 {
3096 if (!tok.is(TokenRetval::TK_NEWPARA)) /* empty param description */
3097 {
3098 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s in comment block while parsing the "
3099 "argument of command %s",tok.to_string(),qPrint(saveCmdName));
3100 }
3101 retval = Token::make_RetVal_EndParBlock();
3102 goto endparamlist;
3103 }
3104
3106 par = m_paragraphs.get_last<DocPara>();
3107 retval = par->parse();
3108 par->markFirst();
3109 par->markLast();
3110
3111endparamlist:
3112 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3113 return retval;
3114}
3115
3117{
3118 AUTO_TRACE();
3119 Token retval = Token::make_RetVal_OK();
3120 auto ns = AutoNodeStack(parser(),thisVariant());
3121
3122 parser()->context.token->name = paramName;
3124 {
3127 }
3128 else if (m_type==DocParamSect::RetVal)
3129 {
3132 }
3133
3135
3136 do
3137 {
3139 DocPara *par = m_paragraphs.get_last<DocPara>();
3140 retval = par->parse();
3141 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
3142 // after </para> and before </param>
3143 {
3144 m_paragraphs.pop_back();
3145 break;
3146 }
3147 else // append the paragraph to the list
3148 {
3149 if (!m_paragraphs.empty())
3150 {
3151 m_paragraphs.get_last<DocPara>()->markLast(FALSE);
3152 }
3153 bool markFirst = m_paragraphs.empty();
3154 par = &std::get<DocPara>(m_paragraphs.back());
3155 if (markFirst)
3156 {
3157 par->markFirst();
3158 }
3159 par->markLast();
3160 }
3161
3162 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) break;
3163
3164 } while (retval.is(TokenRetval::RetVal_CloseXml) &&
3165 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_PARAM &&
3166 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_TYPEPARAM &&
3167 Mappers::htmlTagMapper->map(parser()->context.token->name)!=HtmlTagType::XML_EXCEPTION);
3168
3169 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF)) /* premature end of comment block */
3170 {
3171 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unterminated param or exception tag");
3172 }
3173 else
3174 {
3175 retval = Token::make_RetVal_OK();
3176 }
3177
3178 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3179 return retval;
3180}
3181
3182//--------------------------------------------------------------------------
3183
3184Token DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
3185{
3186 AUTO_TRACE();
3187 Token retval = Token::make_RetVal_OK();
3188 auto ns = AutoNodeStack(parser(),thisVariant());
3189
3190 if (d!=Unspecified)
3191 {
3193 }
3194
3195 if (!children().empty() && std::holds_alternative<DocParamList>(children().back()))
3196 {
3197 DocParamList &lastPl = std::get<DocParamList>(children().back());
3198 lastPl.markLast(false);
3199 }
3200 bool markFirst = children().empty();
3203 if (markFirst)
3204 {
3205 pl->markFirst();
3206 }
3207 pl->markLast();
3208 if (xmlContext)
3209 {
3210 retval = pl->parseXml(cmdName);
3211 }
3212 else
3213 {
3214 retval = pl->parse(cmdName);
3215 }
3216 if (retval.is(TokenRetval::RetVal_EndParBlock))
3217 {
3218 retval = Token::make_RetVal_OK();
3219 }
3220
3221 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3222 return retval;
3223}
3224
3225//--------------------------------------------------------------------------
3226
3232
3234{
3235 AUTO_TRACE();
3236 DocSimpleSect *ss=nullptr;
3237 bool needsSeparator = FALSE;
3238 if (!children().empty() && // has previous element
3239 (ss=children().get_last<DocSimpleSect>()) && // was a simple sect
3240 ss->type()==t && // of same type
3241 t!=DocSimpleSect::User) // but not user defined
3242 {
3243 // append to previous section
3244 needsSeparator = TRUE;
3245 }
3246 else // start new section
3247 {
3250 }
3251 Token rv = Token::make_RetVal_OK();
3252 if (xmlContext)
3253 {
3254 return ss->parseXml();
3255 }
3256 else
3257 {
3258 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
3259 }
3260 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3261}
3262
3265 bool xmlContext=FALSE,
3266 int direction=DocParamSect::Unspecified)
3267{
3268 AUTO_TRACE();
3269 DocParamSect *ps = nullptr;
3270 if (!children().empty() && // previous element
3271 (ps=children().get_last<DocParamSect>()) && // was a param sect
3272 ps->type()==t) // of same type
3273 { // append to previous section ps
3274 }
3275 else // start new section
3276 {
3278 ps = children().get_last<DocParamSect>();
3279 }
3280 Token rv=ps->parse(cmdName,xmlContext,
3281 static_cast<DocParamSect::Direction>(direction));
3282 AUTO_TRACE_EXIT("retval={}",rv.to_string());
3283 return (!rv.is(TokenRetval::TK_NEWPARA)) ? rv : Token::make_RetVal_OK();
3284}
3285
3286void DocPara::handleCite(char cmdChar,const QCString &cmdName)
3287{
3288 AUTO_TRACE();
3289 // get the argument of the cite command.
3290 Token tok=parser()->tokenizer.lex();
3291 if (!tok.is(TokenRetval::TK_WHITESPACE))
3292 {
3293 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3294 cmdChar,qPrint(cmdName));
3295 return;
3296 }
3298 tok=parser()->tokenizer.lex();
3299 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3300 {
3301 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3302 "argument of command '%c%s'",cmdChar,qPrint(cmdName));
3303 return;
3304 }
3305 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3306 {
3307 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s'",
3308 tok.to_string(),cmdChar,qPrint(cmdName));
3309 return;
3310 }
3314
3316}
3317
3318void DocPara::handleEmoji(char cmdChar,const QCString &cmdName)
3319{
3320 AUTO_TRACE();
3321 // get the argument of the emoji command.
3322 Token tok=parser()->tokenizer.lex();
3323 if (!tok.is(TokenRetval::TK_WHITESPACE))
3324 {
3325 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3326 cmdChar,qPrint(cmdName));
3327 return;
3328 }
3330 tok=parser()->tokenizer.lex();
3331 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3332 {
3333 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"no emoji name given or unexpected end of comment block while parsing the "
3334 "argument of command '%c%s'",cmdChar,qPrint(cmdName));
3336 return;
3337 }
3338 else if (!tok.is(TokenRetval::TK_WORD))
3339 {
3340 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s'",
3341 tok.to_string(),cmdChar,qPrint(cmdName));
3343 return;
3344 }
3347}
3348
3349void DocPara::handleDoxyConfig(char cmdChar,const QCString &cmdName)
3350{
3351 // get the argument of the cite command.
3352 Token tok=parser()->tokenizer.lex();
3353 if (!tok.is(TokenRetval::TK_WHITESPACE))
3354 {
3355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3356 cmdChar,qPrint(cmdName));
3357 return;
3358 }
3360 tok=parser()->tokenizer.lex();
3361 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3362 {
3363 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3364 "argument of command '%c%s'",cmdChar,qPrint(cmdName));
3365 return;
3366 }
3367 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3368 {
3369 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s'",
3370 tok.to_string(),cmdChar,qPrint(cmdName));
3371 return;
3372 }
3373 ConfigOption * opt = ConfigImpl::instance()->get(parser()->context.token->name);
3374 if (opt)
3375 {
3376 QCString optionValue;
3377 switch (opt->kind())
3378 {
3380 optionValue = *(static_cast<ConfigBool*>(opt)->valueStringRef());
3381 break;
3383 optionValue = *(static_cast<ConfigString*>(opt)->valueRef());
3384 break;
3386 optionValue = *(static_cast<ConfigEnum*>(opt)->valueRef());
3387 break;
3389 optionValue = *(static_cast<ConfigInt*>(opt)->valueStringRef());
3390 break;
3392 {
3393 StringVector *lst = static_cast<ConfigList*>(opt)->valueRef();
3394 optionValue="";
3395 if (!lst->empty())
3396 {
3397 std::string lstFormat = theTranslator->trWriteList(static_cast<int>(lst->size())).str();
3398 static const reg::Ex marker(R"(@(\d+))");
3399 reg::Iterator it(lstFormat,marker);
3401 size_t index=0;
3402 // now replace all markers with the real text
3403 for ( ; it!=end ; ++it)
3404 {
3405 const auto &match = *it;
3406 size_t newIndex = match.position();
3407 size_t matchLen = match.length();
3408 optionValue += lstFormat.substr(index,newIndex-index);
3409 unsigned long entryIndex = std::stoul(match[1].str());
3410 if (entryIndex<(unsigned long)lst->size())
3411 {
3412 optionValue += lst->at(entryIndex);
3413 }
3414 index=newIndex+matchLen;
3415 }
3416 optionValue+=lstFormat.substr(index);
3417 }
3418 }
3419 break;
3421 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Obsolete setting for '%c%s': '%s'",
3422 cmdChar,qPrint(cmdName),qPrint(parser()->context.token->name));
3423 break;
3425 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),
3426 "Disabled setting (i.e. not supported in this doxygen executable) for '%c%s': '%s'",
3427 cmdChar,qPrint(cmdName),qPrint(parser()->context.token->name));
3428 break;
3430 // nothing to show here
3431 break;
3432 }
3433 if (!optionValue.isEmpty())
3434 {
3435 children().append<DocWord>(parser(),thisVariant(),optionValue);
3436 }
3437 }
3438 else
3439 {
3440 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option for '%c%s': '%s'",
3441 cmdChar,qPrint(cmdName),qPrint(parser()->context.token->name));
3443 }
3445}
3446
3448{
3449 AUTO_TRACE();
3450 Token retval=parser()->tokenizer.lex();
3451 ASSERT(retval.is(TokenRetval::TK_WHITESPACE));
3453 retval=parser()->tokenizer.lex();
3454 if (retval.is(TokenRetval::RetVal_OK))
3455 {
3459 if (!ref->parse())
3460 {
3461 children().pop_back();
3462 }
3463 }
3465 return retval;
3466}
3467
3468void DocPara::handleShowDate(char cmdChar,const QCString &cmdName)
3469{
3470 AUTO_TRACE();
3471 QCString fmt;
3472 QCString date;
3473 Token tok=parser()->tokenizer.lex();
3474 if (!tok.is(TokenRetval::TK_WHITESPACE))
3475 {
3476 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3477 cmdChar,qPrint(cmdName));
3478 return;
3479 }
3481 tok = parser()->tokenizer.lex();
3482 if (!tok.is(TokenRetval::TK_WORD))
3483 {
3484 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <format> argument for command '%c%s'",
3485 cmdChar,qPrint(cmdName));
3487 return;
3488 }
3489 fmt = parser()->context.token->name;
3490
3492 tok = parser()->tokenizer.lex();
3493
3494 QCString specDateRaw = tok.is(TokenRetval::TK_WORD) ? parser()->context.token->name : QCString();
3495 QCString specDate = specDateRaw.stripWhiteSpace();
3496 bool specDateOnlyWS = !specDateRaw.isEmpty() && specDate.isEmpty();
3497 if (!specDate.isEmpty() && !tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3498 {
3499 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '%c%s'",
3500 cmdChar,qPrint(cmdName));
3502 return;
3503 }
3504
3505 std::tm dat{};
3506 int specFormat=0;
3507 QCString err = dateTimeFromString(specDate,dat,specFormat);
3508 if (!err.isEmpty())
3509 {
3510 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid <date_time> argument for command '%c%s': %s",
3511 cmdChar,qPrint(cmdName),qPrint(err));
3513 return;
3514 }
3515
3516 int usedFormat=0;
3517 QCString dateTimeStr = formatDateTime(fmt,dat,usedFormat);
3518
3519 // warn the user if the format contains markers that are not explicitly filled in
3520 for (int i=0;i<SF_NumBits;i++)
3521 {
3522 int bitMask = 1<<i;
3523 if ((usedFormat&bitMask) && !(specFormat&bitMask)) // a part was used in the format string but its value was not specified.
3524 {
3525 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"'%c%s' <format> parameter '%s' has %s related markers which are not specified in the <date_time> parameter '%s'. Filling in the current value for %s instead.",
3526 cmdChar,qPrint(cmdName),
3527 qPrint(fmt),SF_bit2str(i),qPrint(specDate),SF_bit2str(i));
3528 }
3529 }
3530
3531 children().append<DocWord>(parser(),thisVariant(),dateTimeStr);
3532 if (specDateOnlyWS) // specDate is only whitespace
3533 {
3535 }
3537}
3538
3539void DocPara::handleILine(char cmdChar,const QCString &cmdName)
3540{
3541 AUTO_TRACE();
3543 Token tok = parser()->tokenizer.lex();
3544 if (!tok.is(TokenRetval::TK_WORD))
3545 {
3546 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"invalid argument for command '%c%s'",
3547 cmdChar,qPrint(cmdName));
3548 return;
3549 }
3551}
3552
3553void DocPara::handleIFile(char cmdChar,const QCString &cmdName)
3554{
3555 AUTO_TRACE();
3556 Token tok=parser()->tokenizer.lex();
3557 if (!tok.is(TokenRetval::TK_WHITESPACE))
3558 {
3559 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3560 cmdChar,qPrint(cmdName));
3561 return;
3562 }
3564 tok=parser()->tokenizer.lex();
3566 if (!tok.is(TokenRetval::TK_WORD))
3567 {
3568 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s'",
3569 tok.to_string(),cmdChar,qPrint(cmdName));
3570 return;
3571 }
3574}
3575
3576
3578{
3579 AUTO_TRACE("cmdName={}",cmdName);
3580 QCString saveCmdName = cmdName;
3581 Token tok=parser()->tokenizer.lex();
3582 if (!tok.is(TokenRetval::TK_WHITESPACE))
3583 {
3584 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
3585 qPrint(saveCmdName));
3586 return;
3587 }
3589 tok=parser()->tokenizer.lex();
3591 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3592 {
3593 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3594 "argument of command %s", qPrint(saveCmdName));
3595 return;
3596 }
3597 else if (!tok.is(TokenRetval::TK_WORD))
3598 {
3599 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of %s",
3600 tok.to_string(),qPrint(saveCmdName));
3601 return;
3602 }
3603 auto it1 = children().size()>=1 ? std::prev(children().end()) : children().end();
3604 auto it2 = children().size()>=2 ? std::prev(it1) : children().end();
3605 DocNodeVariant *n1 = it1!=children().end() ? &(*it1) : nullptr;
3606 DocNodeVariant *n2 = it2!=children().end() ? &(*it2) : nullptr;
3607 //TODO get from context the stripCodeComments()
3608 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3612 stripCodeComments,
3615 );
3617 DocIncOperator *n1_docIncOp = std::get_if<DocIncOperator>(n1);
3618 DocWhiteSpace *n1_docWs = std::get_if<DocWhiteSpace >(n1);
3619 DocIncOperator *n2_docIncOp = std::get_if<DocIncOperator>(n2);
3620 bool isFirst = !n1 || // no last node
3621 (!n1_docIncOp && !n1_docWs) || // last node is not operator or whitespace
3622 (n1_docWs && n2 && !n2_docIncOp); // last node is not operator
3623 op->markFirst(isFirst);
3624 op->markLast(true);
3625 if (n1_docIncOp)
3626 {
3627 n1_docIncOp->markLast(false);
3628 }
3629 else if (n1_docWs && n2_docIncOp)
3630 {
3631 n2_docIncOp->markLast(false);
3632 }
3633 op->parse();
3634}
3635
3636template<class T>
3637void DocPara::handleFile(const QCString &cmdName)
3638{
3639 AUTO_TRACE("cmdName={}",cmdName);
3640 QCString saveCmdName = cmdName;
3641 Token tok=parser()->tokenizer.lex();
3642 if (!tok.is(TokenRetval::TK_WHITESPACE))
3643 {
3644 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
3645 qPrint(saveCmdName));
3646 return;
3647 }
3649 tok=parser()->tokenizer.lex();
3651 if (!tok.is(TokenRetval::TK_WORD))
3652 {
3653 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of %s",
3654 tok.to_string(),qPrint(saveCmdName));
3655 return;
3656 }
3657 QCString name = parser()->context.token->name;
3658 children().append<T>(parser(),thisVariant(),name,
3662 auto df = children().get_last<T>();
3663 if (!df->parse())
3664 {
3665 children().pop_back();
3666 }
3667}
3668
3675
3676void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
3677{
3678 AUTO_TRACE("cmdName={} isJavaLink={}",cmdName,isJavaLink);
3679 QCString saveCmdName = cmdName;
3680 Token tok=parser()->tokenizer.lex();
3681 if (!tok.is(TokenRetval::TK_WHITESPACE))
3682 {
3683 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
3684 qPrint(saveCmdName));
3685 return;
3686 }
3688 tok=parser()->tokenizer.lex();
3689 if (!tok.is(TokenRetval::TK_WORD))
3690 {
3691 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"%s as the argument of %s",
3692 tok.to_string(),qPrint(saveCmdName));
3693 return;
3694 }
3695 if (saveCmdName == "javalink")
3696 {
3698 parser()->context.nodeStack.size(),
3699 DocStyleChange::Code,cmdName,TRUE);
3700 }
3703 DocLink *lnk = children().get_last<DocLink>();
3704 if (saveCmdName == "javalink")
3705 {
3707 parser()->context.nodeStack.size(),
3708 DocStyleChange::Code,cmdName,FALSE);
3709 }
3710 QCString leftOver = lnk->parse(isJavaLink);
3711 if (!leftOver.isEmpty())
3712 {
3713 children().append<DocWord>(parser(),thisVariant(),leftOver);
3714 }
3715}
3716
3717void DocPara::handleRef(char cmdChar,const QCString &cmdName)
3718{
3719 AUTO_TRACE("cmdName={}",cmdName);
3720 QCString saveCmdName = cmdName;
3721 Token tok=parser()->tokenizer.lex();
3722 if (!tok.is(TokenRetval::TK_WHITESPACE))
3723 {
3724 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3725 cmdChar,qPrint(saveCmdName));
3726 return;
3727 }
3729 tok=parser()->tokenizer.lex(); // get the reference id
3730 if (!tok.is(TokenRetval::TK_WORD))
3731 {
3732 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s'",
3733 tok.to_string(),cmdChar,qPrint(saveCmdName));
3734 goto endref;
3735 }
3739 children().get_last<DocRef>()->parse();
3740endref:
3742}
3743
3745{
3746 AUTO_TRACE("cmdName={}",cmdName);
3747 QCString saveCmdName = cmdName;
3748 Token tok=parser()->tokenizer.lex();
3749 bool isBlock = false;
3750 bool trimLeft = false;
3751 bool localScope = false;
3752 bool stripCodeComments = Config_getBool(STRIP_CODE_COMMENTS);
3753 if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="{")
3754 {
3756 parser()->tokenizer.lex();
3758 StringVector optList=split(parser()->context.token->name.str(),",");
3759 auto contains = [&optList](const char *kw)
3760 {
3761 return std::find(optList.begin(),optList.end(),kw)!=optList.end();
3762 };
3763 localScope = contains("local");
3764 if (contains("nostrip"))
3765 {
3766 stripCodeComments = false;
3767 }
3768 else if (contains("strip"))
3769 {
3770 stripCodeComments = true;
3771 }
3772 if (t==DocInclude::Snippet && contains("trimleft"))
3773 {
3774 trimLeft = true;
3775 }
3776
3777 if (contains("lineno"))
3778 {
3782 }
3783 tok=parser()->tokenizer.lex();
3784 if (!tok.is(TokenRetval::TK_WHITESPACE))
3785 {
3786 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
3787 qPrint(saveCmdName));
3788 return;
3789 }
3790 }
3791 else if (tok.is(TokenRetval::TK_WORD) && parser()->context.token->name=="[")
3792 {
3794 parser()->tokenizer.lex();
3795 isBlock = (parser()->context.token->name.stripWhiteSpace() == "block");
3797 parser()->tokenizer.lex();
3798 }
3799 else if (!tok.is(TokenRetval::TK_WHITESPACE))
3800 {
3801 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after \\%s command",
3802 qPrint(saveCmdName));
3803 return;
3804 }
3806 tok=parser()->tokenizer.lex();
3808 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3809 {
3810 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3811 "argument of command %s",qPrint(saveCmdName));
3812 return;
3813 }
3814 else if (!tok.is(TokenRetval::TK_WORD))
3815 {
3816 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of %s",
3817 tok.to_string(),qPrint(saveCmdName));
3818 return;
3819 }
3820 QCString fileName = parser()->context.token->name;
3821 QCString blockId;
3823 {
3824 if (fileName == "this") fileName=parser()->context.fileName;
3826 tok=parser()->tokenizer.lex();
3828 if (!tok.is(TokenRetval::TK_WORD))
3829 {
3830 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected block identifier, but found token %s instead while parsing the %s command",
3831 tok.to_string(),qPrint(saveCmdName));
3832 return;
3833 }
3834 blockId = "["+parser()->context.token->name+"]";
3835 }
3836
3838 thisVariant(),
3839 fileName,
3840 localScope ? parser()->context.context : "",
3841 t,
3842 stripCodeComments,
3845 blockId,isBlock,trimLeft);
3847}
3848
3849void DocPara::handleSection(char cmdChar,const QCString &cmdName)
3850{
3851 AUTO_TRACE("cmdName={}",cmdName);
3852 QCString saveCmdName = cmdName;
3853 // get the argument of the section command.
3854 Token tok=parser()->tokenizer.lex();
3855 if (!tok.is(TokenRetval::TK_WHITESPACE))
3856 {
3857 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"expected whitespace after '%c%s' command",
3858 cmdChar,qPrint(saveCmdName));
3859 return;
3860 }
3861 tok=parser()->tokenizer.lex();
3862 if (tok.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3863 {
3864 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected end of comment block while parsing the "
3865 "argument of command '%c%s'", cmdChar,qPrint(saveCmdName));
3866 return;
3867 }
3868 else if (!tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD))
3869 {
3870 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected token %s as the argument of '%c%s'",
3871 tok.to_string(),cmdChar,qPrint(saveCmdName));
3872 return;
3873 }
3876 parser()->tokenizer.lex();
3878}
3879
3880Token DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
3881{
3882 AUTO_TRACE();
3883 children().append<DocHtmlHeader>(parser(),thisVariant(),tagHtmlAttribs,level);
3884 Token retval = children().get_last<DocHtmlHeader>()->parse();
3885 return retval.is(TokenRetval::RetVal_OK) ? Token::make_TK_NEWPARA() : retval;
3886}
3887
3888// For XML tags whose content is stored in attributes rather than
3889// contained within the element, we need a way to inject the attribute
3890// text into the current paragraph.
3891bool DocPara::injectToken(Token tok,const QCString &tokText)
3892{
3893 AUTO_TRACE();
3894 parser()->context.token->name = tokText;
3895 return parser()->defaultHandleToken(thisVariant(),tok,children());
3896}
3897
3899{
3900 AUTO_TRACE();
3901 Token retval = parser()->tokenizer.lex();
3902 QCString lang = parser()->context.token->name;
3903 if (!lang.isEmpty() && lang.at(0)!='.')
3904 {
3905 lang="."+lang;
3906 }
3907 if (parser()->context.xmlComment)
3908 {
3909 parser()->context.token->verb = substitute(substitute(parser()->context.token->verb,"&lt;","<"),"&gt;",">");
3910 }
3911 // search for the first non-whitespace line, index is stored in li
3912 size_t i=0,li=0,l=parser()->context.token->verb.length();
3913 while (i<l && (parser()->context.token->verb.at(i)==' ' || parser()->context.token->verb.at(i)=='\n'))
3914 {
3915 if (parser()->context.token->verb.at(i)=='\n') li=i+1;
3916 i++;
3917 }
3920 stripIndentation(parser()->context.token->verb.mid(li)),
3924 FALSE,lang);
3925 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
3926 {
3927 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"code section ended without end marker");
3928 }
3930 AUTO_TRACE_EXIT("retval={}",retval.to_string());
3931 return retval;
3932}
3933
3935{
3936 if (parser()->context.memberDef) // inheriting docs from a member
3937 {
3938 const MemberDef *reMd = parser()->context.memberDef->reimplements();
3939 if (reMd) // member from which was inherited.
3940 {
3941 const MemberDef *thisMd = parser()->context.memberDef;
3942 //printf("{InheritDocs:%s=>%s}\n",qPrint(parser()->context.memberDef->qualifiedName()),qPrint(reMd->qualifiedName()));
3943 parser()->pushContext();
3944 parser()->context.scope=reMd->getOuterScope();
3945 if (parser()->context.scope!=Doxygen::globalScope)
3946 {
3948 }
3949 parser()->context.memberDef=reMd;
3950 while (!parser()->context.styleStack.empty()) parser()->context.styleStack.pop();
3951 while (!parser()->context.nodeStack.empty()) parser()->context.nodeStack.pop();
3952 parser()->context.copyStack.push_back(reMd);
3955 parser()->context.copyStack.pop_back();
3956 auto hasParamCommand = parser()->context.hasParamCommand;
3957 auto hasReturnCommand = parser()->context.hasReturnCommand;
3958 auto retvalsFound = parser()->context.retvalsFound;
3959 auto paramsFound = parser()->context.paramsFound;
3960 parser()->popContext();
3961 parser()->context.hasParamCommand = hasParamCommand;
3962 parser()->context.hasReturnCommand = hasReturnCommand;
3963 parser()->context.retvalsFound = retvalsFound;
3964 parser()->context.paramsFound = paramsFound;
3965 parser()->context.memberDef = thisMd;
3966 }
3967 }
3968}
3969
3970
3971Token DocPara::handleCommand(char cmdChar, const QCString &cmdName)
3972{
3973 AUTO_TRACE("cmdName={}",cmdName);
3974 Token retval = Token::make_RetVal_OK();
3975 CommandType cmdId = Mappers::cmdMapper->map(cmdName);
3976 switch (cmdId)
3977 {
3979 {
3980 std::string str{cmdChar};
3981 children().append<DocWord>(parser(),thisVariant(),str.c_str() + cmdName);
3982 if (isAliasCmd(cmdName.view()))
3983 {
3984 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unexpanded alias '%c%s'. Check if number of arguments passed is correct.",cmdChar,qPrint(cmdName));
3985 }
3986 else
3987 {
3988 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Found unknown command '%c%s'",cmdChar,qPrint(cmdName));
3989 }
3990 }
3991 break;
3994 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
3996 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
3997 break;
4000 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4002 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4003 break;
4006 retval=parser()->handleStyleArgument(thisVariant(),children(),cmdName);
4008 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
4009 break;
4012 break;
4015 break;
4018 break;
4021 break;
4024 break;
4027 break;
4030 break;
4033 break;
4036 break;
4039 break;
4043 break;
4048 break;
4051 break;
4054 break;
4057 break;
4060 break;
4063 break;
4066 break;
4069 break;
4074 break;
4078 break;
4081 break;
4084 break;
4087 break;
4090 break;
4093 break;
4096 break;
4099 break;
4102 break;
4105 break;
4108 break;
4111 break;
4114 break;
4117 break;
4120 break;
4123 break;
4125 {
4127 retval = children().get_last<DocSimpleList>()->parse();
4128 }
4129 break;
4131 {
4132 handleSection(cmdChar,cmdName);
4133 retval = Token::make_RetVal_Section();
4134 }
4135 break;
4137 {
4138 handleSection(cmdChar,cmdName);
4139 retval = Token::make_RetVal_Subsection();
4140 }
4141 break;
4143 {
4144 handleSection(cmdChar,cmdName);
4145 retval = Token::make_RetVal_Subsubsection();
4146 }
4147 break;
4149 {
4150 handleSection(cmdChar,cmdName);
4151 retval = Token::make_RetVal_Paragraph();
4152 }
4153 break;
4155 {
4156 handleSection(cmdChar,cmdName);
4157 retval = Token::make_RetVal_SubParagraph();
4158 }
4159 break;
4161 {
4162 handleSection(cmdChar,cmdName);
4163 retval = Token::make_RetVal_SubSubParagraph();
4164 }
4165 break;
4167 {
4169 retval = handleStartCode();
4170 }
4171 break;
4173 {
4175 retval = handleStartCode();
4176 }
4177 break;
4179 {
4181 retval = parser()->tokenizer.lex();
4183 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4184 {
4185 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"htmlonly section ended without end marker");
4186 }
4188 }
4189 break;
4191 {
4193 retval = parser()->tokenizer.lex();
4195 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4196 {
4197 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"manonly section ended without end marker");
4198 }
4200 }
4201 break;
4203 {
4205 retval = parser()->tokenizer.lex();
4207 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4208 {
4209 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"rtfonly section ended without end marker");
4210 }
4212 }
4213 break;
4215 {
4217 retval = parser()->tokenizer.lex();
4219 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4220 {
4221 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"latexonly section ended without end marker");
4222 }
4224 }
4225 break;
4227 {
4229 retval = parser()->tokenizer.lex();
4231 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4232 {
4233 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"xmlonly section ended without end marker");
4234 }
4236 }
4237 break;
4239 {
4241 retval = parser()->tokenizer.lex();
4243 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4244 {
4245 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"docbookonly section ended without end marker");
4246 }
4248 }
4249 break;
4251 {
4254 parser()->tokenizer.lex();
4255
4256 QCString fullMatch = parser()->context.token->verb;
4257 int idx = fullMatch.find('{');
4258 int idxEnd = fullMatch.find("}",idx+1);
4259 StringVector optList;
4260 if (idx != -1) // options present
4261 {
4262 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4263 optList = split(optStr.str(),",");
4264 for (const auto &opt : optList)
4265 {
4266 if (opt.empty()) continue;
4267 QCString locOpt(opt);
4268 locOpt = locOpt.stripWhiteSpace().lower();
4269 if (locOpt == "code")
4270 {
4272 }
4273 else if (!locOpt.isEmpty())
4274 {
4275 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Unknown option '%s' for '\\iliteral'",qPrint(opt));
4276 }
4277 }
4278 }
4279
4281 retval = parser()->tokenizer.lex();
4283 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4284 {
4285 if (t == DocVerbatim::JavaDocCode)
4286 {
4287 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc code section ended without end marker");
4288 }
4289 else
4290 {
4291 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"javadoc literal section ended without end marker");
4292 }
4293 }
4295 }
4296 break;
4299 {
4300 if (cmdId == CommandType::CMD_VERBATIM)
4301 {
4303 }
4304 else
4305 {
4307 }
4308 retval = parser()->tokenizer.lex();
4310 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4311 {
4312 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"verbatim section ended without end marker");
4313 }
4315 }
4316 break;
4318 {
4327 QCString width,height;
4328 parser()->defaultHandleTitleAndSize(CommandType::CMD_DOT,&children().back(),dv->children(),width,height);
4330 retval = parser()->tokenizer.lex();
4331 dv->setText(parser()->context.token->verb);
4332 dv->setWidth(width);
4333 dv->setHeight(height);
4334 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4335 if (!Config_getBool(HAVE_DOT))
4336 {
4337 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\dot command because HAVE_DOT is not set");
4338 children().pop_back();
4339 }
4340 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4341 {
4342 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"dot section ended without end marker");
4343 }
4345 }
4346 break;
4348 {
4357 QCString width,height;
4358 parser()->defaultHandleTitleAndSize(CommandType::CMD_MSC,&children().back(),dv->children(),width,height);
4360 retval = parser()->tokenizer.lex();
4361 dv->setText(parser()->context.token->verb);
4362 dv->setWidth(width);
4363 dv->setHeight(height);
4364 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4365 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4366 {
4367 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"msc section ended without end marker");
4368 }
4370 }
4371 break;
4373 {
4374 QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
4376 parser()->tokenizer.lex();
4377 QCString fullMatch = parser()->context.token->sectionId;
4378 QCString sectionId = "";
4379 int idx = fullMatch.find('{');
4380 int idxEnd = fullMatch.find("}",idx+1);
4381 StringVector optList;
4382 QCString engine;
4383 if (idx != -1) // options present
4384 {
4385 QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
4386 optList = split(optStr.str(),",");
4387 for (const auto &opt : optList)
4388 {
4389 if (opt.empty()) continue;
4390 bool found = false;
4391 QCString locOpt(opt);
4392 locOpt = locOpt.stripWhiteSpace().lower();
4393 if (g_plantumlEngine.find(locOpt.str())!=g_plantumlEngine.end())
4394 {
4395 if (!engine.isEmpty())
4396 {
4397 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(), "Multiple definition of engine for '\\startuml'");
4398 }
4399 engine = locOpt;
4400 found = true;
4401 }
4402 if (!found)
4403 {
4404 if (sectionId.isEmpty())
4405 {
4406 sectionId = opt;
4407 }
4408 else
4409 {
4410 warn(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Multiple use of filename for '\\startuml'");
4411 }
4412 }
4413 }
4414 }
4415 else
4416 {
4417 sectionId = parser()->context.token->sectionId;
4418 }
4419 if (engine.isEmpty()) engine = "uml";
4420
4421 if (sectionId.isEmpty())
4422 {
4424 retval = parser()->tokenizer.lex();
4425 assert(retval.is(TokenRetval::RetVal_OK));
4426
4427 sectionId = parser()->context.token->sectionId;
4428 sectionId = sectionId.stripWhiteSpace();
4429 }
4430
4431 QCString plantFile(sectionId);
4436 FALSE,plantFile);
4438 dv->setEngine(engine);
4440 QCString width,height;
4441 parser()->defaultHandleTitleAndSize(CommandType::CMD_STARTUML,&children().back(),dv->children(),width,height);
4443 retval = parser()->tokenizer.lex();
4444 int line = 0;
4445 QCString trimmedVerb = stripLeadingAndTrailingEmptyLines(parser()->context.token->verb,line);
4446 if (engine == "ditaa")
4447 {
4448 dv->setUseBitmap(true);
4449 }
4450 else if (engine == "uml")
4451 {
4452 int i = trimmedVerb.find('\n');
4453 QCString firstLine = i==-1 ? trimmedVerb : trimmedVerb.left(i);
4454 if (firstLine.stripWhiteSpace() == "ditaa") dv->setUseBitmap(true);
4455 }
4456 dv->setText(trimmedVerb);
4457 dv->setWidth(width);
4458 dv->setHeight(height);
4459 dv->setLocation(parser()->context.fileName,parser()->tokenizer.getLineNr());
4460 if (jarPath.isEmpty())
4461 {
4462 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
4463 children().pop_back();
4464 }
4465 if (retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF))
4466 {
4467 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"startuml section ended without end marker");
4468 }
4470 }
4471 break;
4473 retval = Token::make_RetVal_EndParBlock();
4474 break;
4490 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command %s",qPrint(parser()->context.token->name));
4491 break;
4493 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,parser()->context.token->paramDir);
4494 break;
4496 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,parser()->context.token->paramDir);
4497 break;
4499 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4500 break;
4503 break;
4505 retval = handleXRefItem();
4506 break;
4508 {
4510 }
4511 break;
4514 {
4516 }
4517 break;
4519 {
4521 }
4522 break;
4524 {
4528 retval = children().get_last<DocIndexEntry>()->parse();
4529 }
4530 break;
4532 retval = Token::make_RetVal_Internal();
4533 break;
4535 retval = Token::make_RetVal_EndInternal();
4536 break;
4538 {
4540 retval = children().get_last<DocParBlock>()->parse();
4541 }
4542 break;
4543 case CommandType::CMD_COPYDOC: // fall through
4544 case CommandType::CMD_COPYBRIEF: // fall through
4546 //retval = Token::make_RetVal_CopyDoc();
4547 // these commands should already be resolved by processCopyDoc()
4548 break;
4551 break;
4554 break;
4557 break;
4560 break;
4563 break;
4566 break;
4569 break;
4572 break;
4575 break;
4578 break;
4581 break;
4584 break;
4587 break;
4590 break;
4593 break;
4596 break;
4599 break;
4601 if (!Config_getBool(HAVE_DOT))
4602 {
4603 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
4604 "ignoring \\dotfile command because HAVE_DOT is not set");
4605 }
4606 else
4607 {
4608 handleFile<DocDotFile>(cmdName);
4609 }
4610 break;
4613 break;
4615 handleFile<DocMscFile>(cmdName);
4616 break;
4618 handleFile<DocDiaFile>(cmdName);
4619 break;
4622 break;
4624 handleLink(cmdName,FALSE);
4625 break;
4627 handleLink(cmdName,TRUE);
4628 break;
4630 handleCite(cmdChar,cmdName);
4631 break;
4633 handleEmoji(cmdChar,cmdName);
4634 break;
4636 handleDoxyConfig(cmdChar,cmdName);
4637 break;
4638 case CommandType::CMD_REF: // fall through
4640 handleRef(cmdChar,cmdName);
4641 break;
4643 {
4646 }
4647 break;
4649 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '%c%s'",cmdChar,qPrint(parser()->context.token->name));
4650 break;
4652 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command '%c%s'",cmdChar,qPrint(parser()->context.token->name));
4653 break;
4655 {
4657 }
4658 break;
4659 //case CommandType::CMD_LANGSWITCH:
4660 // retval = handleLanguageSwitch();
4661 // break;
4663 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"unexpected command %s",qPrint(parser()->context.token->name));
4664 {
4667 }
4668 break;
4671 break;
4673 handleShowDate(cmdChar,cmdName);
4674 break;
4676 handleILine(cmdChar,cmdName);
4677 break;
4679 handleIFile(cmdChar,cmdName);
4680 break;
4682 {
4684 (void)parser()->tokenizer.lex();
4686 //printf("Found scope='%s'\n",qPrint(parser()->context.context));
4688 }
4689 break;
4690 default:
4691 // we should not get here!
4692 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '%s' in paragraph context",qPrint(cmdName));
4693 break;
4694 }
4695 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_OK,TokenRetval::RetVal_SimpleSec
4696 TokenRetval::TK_LISTITEM,TokenRetval::TK_ENDLIST,TokenRetval::TK_NEWPARA
4697 TokenRetval::RetVal_Section,TokenRetval::RetVal_EndList
4698 TokenRetval::RetVal_Internal,TokenRetval::RetVal_SwitchLang
4699 TokenRetval::RetVal_EndInternal)
4700 );
4701 AUTO_TRACE_EXIT("retval={}",retval.to_string());
4702 return retval;
4703}
4704
4705static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
4706 const char *attrName,
4707 QCString *result)
4708{
4709
4710 for (const auto &opt : tagHtmlAttribs)
4711 {
4712 if (opt.name==attrName)
4713 {
4714 *result = opt.value;
4715 return TRUE;
4716 }
4717 }
4718 return FALSE;
4719}
4720
4721Token DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
4722{
4723 AUTO_TRACE("tagName={} #tagHtmlAttrs={}",tagName,tagHtmlAttribs.size());
4724 Token retval = Token::make_RetVal_OK();
4725 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
4726 if (parser()->context.token->emptyTag && !(tagId>HtmlTagType::XML_CmdMask) &&
4729 {
4730 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"HTML tag ('<%s/>') may not use the 'empty tag' XHTML syntax.",
4731 qPrint(tagName));
4732 }
4733 switch (tagId)
4734 {
4736 if (!parser()->context.token->emptyTag)
4737 {
4739 tagHtmlAttribs,DocHtmlList::Unordered);
4740 retval=children().get_last<DocHtmlList>()->parse();
4741 }
4742 break;
4744 if (!parser()->context.token->emptyTag)
4745 {
4747 tagHtmlAttribs,DocHtmlList::Ordered);
4748 retval=children().get_last<DocHtmlList>()->parse();
4749 }
4750 break;
4752 if (parser()->context.token->emptyTag) break;
4754 {
4755 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <li> tag found");
4756 }
4757 else
4758 {
4759 retval = Token::make_RetVal_ListItem();
4760 }
4761 break;
4763 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Bold,tagName,&parser()->context.token->attribs);
4764 break;
4766 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::S,tagName,&parser()->context.token->attribs);
4767 break;
4769 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Strike,tagName,&parser()->context.token->attribs);
4770 break;
4772 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Del,tagName,&parser()->context.token->attribs);
4773 break;
4775 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Underline,tagName,&parser()->context.token->attribs);
4776 break;
4778 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Ins,tagName,&parser()->context.token->attribs);
4779 break;
4781 if (parser()->context.token->emptyTag) break;
4782 if (parser()->context.xmlComment)
4783 // for C# source or inside a <summary> or <remark> section we
4784 // treat <code> as an XML tag (so similar to @code)
4785 {
4787 retval = handleStartCode();
4788 }
4789 else // normal HTML markup
4790 {
4791 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4792 }
4793 break;
4795 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Kbd,tagName,&parser()->context.token->attribs);
4796 break;
4798 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Italic,tagName,&parser()->context.token->attribs);
4799 break;
4801 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Div,tagName,&parser()->context.token->attribs);
4802 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Div,tagName);
4803 break;
4805 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Span,tagName,&parser()->context.token->attribs);
4806 if (parser()->context.token->emptyTag) parser()->handleStyleLeave(thisVariant(),children(),DocStyleChange::Span,tagName);
4807 break;
4809 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Subscript,tagName,&parser()->context.token->attribs);
4810 break;
4812 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Superscript,tagName,&parser()->context.token->attribs);
4813 break;
4815 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Center,tagName,&parser()->context.token->attribs);
4816 break;
4818 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Small,tagName,&parser()->context.token->attribs);
4819 break;
4821 if (!parser()->context.token->emptyTag) parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Cite,tagName,&parser()->context.token->attribs);
4822 break;
4824 if (parser()->context.token->emptyTag) break;
4825 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Preformatted,tagName,&parser()->context.token->attribs);
4828 break;
4830 retval = Token::make_TK_NEWPARA();
4831 break;
4833 if (!parser()->context.token->emptyTag)
4834 {
4835 children().append<DocHtmlDescList>(parser(),thisVariant(),tagHtmlAttribs);
4836 retval=children().get_last<DocHtmlDescList>()->parse();
4837 }
4838 break;
4840 if (insideDL(thisVariant()))
4841 {
4842 retval = Token::make_RetVal_DescTitle();
4843 }
4844 else
4845 {
4846 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dt> found");
4847 }
4848 break;
4850 if (insideDL(thisVariant()))
4851 {
4852 retval = Token::make_RetVal_DescData();
4853 }
4854 else
4855 {
4856 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <dd> found");
4857 }
4858 break;
4860 if (!parser()->context.token->emptyTag)
4861 {
4862 children().append<DocHtmlTable>(parser(),thisVariant(),tagHtmlAttribs);
4863 retval=children().get_last<DocHtmlTable>()->parse();
4864 }
4865 break;
4867 retval = Token::make_RetVal_TableRow();
4868 break;
4870 retval = Token::make_RetVal_TableCell();
4871 break;
4873 retval = Token::make_RetVal_TableHCell();
4874 break;
4878 // for time being ignore </t....> tag
4879 break;
4881 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag <caption> found");
4882 break;
4884 {
4885 children().append<DocLineBreak>(parser(),thisVariant(),tagHtmlAttribs);
4886 }
4887 break;
4889 {
4890 children().append<DocHorRuler>(parser(),thisVariant(),tagHtmlAttribs);
4891 }
4892 break;
4894 retval = parser()->handleAHref(thisVariant(),children(),tagHtmlAttribs);
4895 break;
4897 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,1);
4898 break;
4900 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,2);
4901 break;
4903 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,3);
4904 break;
4906 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,4);
4907 break;
4909 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,5);
4910 break;
4912 if (!parser()->context.token->emptyTag) retval=handleHtmlHeader(tagHtmlAttribs,6);
4913 break;
4915 {
4916 parser()->handleImg(thisVariant(),children(),tagHtmlAttribs);
4917 }
4918 break;
4920 if (!parser()->context.token->emptyTag)
4921 {
4922 children().append<DocHtmlDetails>(parser(),thisVariant(),tagHtmlAttribs);
4923 retval=children().get_last<DocHtmlDetails>()->parse();
4924 }
4925 break;
4927 if (!parser()->context.token->emptyTag)
4928 {
4929 children().append<DocHtmlBlockQuote>(parser(),thisVariant(),tagHtmlAttribs);
4930 retval = children().get_last<DocHtmlBlockQuote>()->parse();
4931 }
4932 break;
4933
4936 {
4937 if (!parser()->context.token->emptyTag)
4938 {
4940 while (n && !std::holds_alternative<DocHtmlDetails>(*n)) n=::parent(n);
4941 DocHtmlDetails *d = std::get_if<DocHtmlDetails>(n);
4942 if (d)
4943 {
4944 if (!d->summary()) // details section does not have a summary yet
4945 {
4946 d->parseSummary(n,parser()->context.token->attribs);
4947 }
4948 else
4949 {
4950 retval = Token::make_TK_NEWPARA();
4951 }
4952 }
4953 }
4954 }
4955 break;
4959 // fall through
4962 if (!children().empty())
4963 {
4964 retval = Token::make_TK_NEWPARA();
4965 }
4966 break;
4968 if (insideTable(thisVariant()))
4969 {
4970 retval = Token::make_RetVal_TableCell();
4971 }
4972 break;
4973 case HtmlTagType::XML_C:
4974 parser()->handleStyleEnter(thisVariant(),children(),DocStyleChange::Code,tagName,&parser()->context.token->attribs);
4975 break;
4978 {
4980 QCString paramName;
4981 if (findAttribute(tagHtmlAttribs,"name",&paramName))
4982 {
4983 if (paramName.isEmpty())
4984 {
4985 if (Config_getBool(WARN_NO_PARAMDOC))
4986 {
4987 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"empty 'name' attribute for <param%s> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
4988 }
4989 }
4990 else
4991 {
4992 retval = handleParamSection(paramName,
4994 TRUE);
4995 }
4996 }
4997 else
4998 {
4999 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param%s> tag.",tagId==HtmlTagType::XML_PARAM?"":"type");
5000 }
5001 }
5002 break;
5005 {
5006 QCString paramName;
5007 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5008 {
5009 //printf("paramName=%s\n",qPrint(paramName));
5011 children().append<DocWord>(parser(),thisVariant(),paramName);
5013 if (!retval.is(TokenRetval::TK_WORD)) children().append<DocWhiteSpace>(parser(),thisVariant()," ");
5014 }
5015 else
5016 {
5017 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'name' attribute from <param%sref> tag.",tagId==HtmlTagType::XML_PARAMREF?"":"type");
5018 }
5019 }
5020 break;
5022 {
5024 QCString exceptName;
5025 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5026 {
5027 unescapeCRef(exceptName);
5028 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5029 }
5030 else
5031 {
5032 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <exception> tag.");
5033 }
5034 }
5035 break;
5038 if (insideTable(thisVariant()))
5039 {
5040 retval = Token::make_RetVal_TableRow();
5041 }
5042 else if (insideUL(thisVariant()) || insideOL(thisVariant()))
5043 {
5044 retval = Token::make_RetVal_ListItem();
5045 }
5046 else
5047 {
5048 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"lonely <item> tag found");
5049 }
5050 break;
5055 break;
5057 if (insideTable(thisVariant()))
5058 {
5059 retval = Token::make_RetVal_TableCell();
5060 }
5061 break;
5063 // I'm not sure if <see> is the same as <seealso> or if it
5064 // should you link a member without producing a section. The
5065 // C# specification is extremely vague about this (but what else
5066 // can we expect from Microsoft...)
5067 {
5068 QCString cref;
5069 //printf("HtmlTagType::XML_SEE: empty tag=%d\n",parser()->context.token->emptyTag);
5070 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5071 {
5072 unescapeCRef(cref);
5073 if (parser()->context.token->emptyTag) // <see cref="..."/> style
5074 {
5075 bool inSeeBlock = parser()->context.inSeeBlock;
5076 parser()->context.token->name = cref;
5079 parser()->context.inSeeBlock = inSeeBlock;
5080 }
5081 else // <see cref="...">...</see> style
5082 {
5083 //DocRef *ref = new DocRef(this,cref);
5084 //children().append(ref);
5085 //ref->parse();
5088 DocLink *lnk = children().get_last<DocLink>();
5089 QCString leftOver = lnk->parse(FALSE,TRUE);
5090 if (!leftOver.isEmpty())
5091 {
5092 children().append<DocWord>(parser(),thisVariant(),leftOver);
5093 }
5094 }
5095 }
5096 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
5097 {
5098 bool inSeeBlock = parser()->context.inSeeBlock;
5099 parser()->context.token->name = cref;
5104 parser()->context.inSeeBlock = inSeeBlock;
5105 }
5106 else
5107 {
5108 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' or 'langword' attribute from <see> tag.");
5109 }
5110 }
5111 break;
5113 {
5115 QCString cref;
5116 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5117 {
5118 unescapeCRef(cref);
5119 // Look for an existing "see" section
5120 DocNodeVariant *vss=nullptr;
5121 for (auto &n : children())
5122 {
5123 DocSimpleSect *candidate = std::get_if<DocSimpleSect>(&n);
5124 if (candidate && candidate->type()==DocSimpleSect::See)
5125 {
5126 vss = &n;
5127 }
5128 }
5129
5130 if (!vss) // start new section
5131 {
5133 vss = &children().back();
5134 }
5135
5136 std::get<DocSimpleSect>(*vss).appendLinkWord(cref);
5137 retval = Token::make_RetVal_OK();
5138 }
5139 else
5140 {
5141 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing 'cref' attribute from <seealso> tag.");
5142 }
5143 }
5144 break;
5146 {
5147 QCString type;
5148 findAttribute(tagHtmlAttribs,"type",&type);
5150 HtmlAttribList emptyList;
5151 if (type=="number")
5152 {
5153 listType=DocHtmlList::Ordered;
5154 }
5155 if (type=="table")
5156 {
5157 children().append<DocHtmlTable>(parser(),thisVariant(),emptyList);
5158 retval=children().get_last<DocHtmlTable>()->parseXml();
5159 }
5160 else
5161 {
5162 children().append<DocHtmlList>(parser(),thisVariant(),emptyList,listType);
5163 retval=children().get_last<DocHtmlList>()->parseXml();
5164 }
5165 }
5166 break;
5169 // These tags are defined in .Net but are currently unsupported
5171 break;
5173 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag <%s> found", qPrint(tagName));
5174 children().append<DocWord>(parser(),thisVariant(), "<"+tagName+parser()->context.token->attribsStr+">");
5175 break;
5178 break;
5179 default:
5180 // we should not get here!
5181 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected start tag %s",qPrint(tagName));
5182 ASSERT(0);
5183 break;
5184 }
5185 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5186 return retval;
5187}
5188
5190{
5191 AUTO_TRACE("tagName={}",tagName);
5192 HtmlTagType tagId = Mappers::htmlTagMapper->map(tagName);
5193 Token retval = Token::make_RetVal_OK();
5194 switch (tagId)
5195 {
5197 if (!insideUL(thisVariant()))
5198 {
5199 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ul> tag without matching <ul>");
5200 }
5201 else
5202 {
5203 retval = Token::make_RetVal_EndList();
5204 }
5205 break;
5207 if (!insideOL(thisVariant()))
5208 {
5209 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </ol> tag without matching <ol>");
5210 }
5211 else
5212 {
5213 retval = Token::make_RetVal_EndList();
5214 }
5215 break;
5217 if (!insideLI(thisVariant()))
5218 {
5219 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </li> tag without matching <li>");
5220 }
5221 else
5222 {
5223 // ignore </li> tags
5224 }
5225 break;
5227 if (!insideDetails(thisVariant()))
5228 {
5229 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </details> tag without matching <details>");
5230 }
5231 else
5232 {
5233 retval = Token::make_RetVal_EndHtmlDetails();
5234 }
5235 break;
5238 {
5239 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"found </blockquote> tag without matching <blockquote>");
5240 }
5241 else
5242 {
5243 retval = Token::make_RetVal_EndBlockQuote();
5244 }
5245 break;
5248 break;
5251 break;
5254 break;
5257 break;
5260 break;
5263 break;
5266 break;
5269 break;
5272 break;
5275 break;
5278 break;
5281 break;
5284 break;
5287 break;
5290 break;
5293 break;
5298 break;
5300 retval = Token::make_TK_NEWPARA();
5301 break;
5303 retval = Token::make_RetVal_EndDesc();
5304 break;
5306 // ignore </dt> tag
5307 break;
5309 // ignore </dd> tag
5310 break;
5312 retval = Token::make_RetVal_EndTable();
5313 break;
5315 // ignore </tr> tag
5316 break;
5318 // ignore </td> tag
5319 break;
5321 // ignore </th> tag
5322 break;
5326 // for time being ignore </t....> tag
5327 break;
5329 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </caption> found");
5330 break;
5332 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </br> tag found");
5333 break;
5335 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h1> found");
5336 break;
5338 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h2> found");
5339 break;
5341 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h3> found");
5342 break;
5344 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h4> found");
5345 break;
5347 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h5> found");
5348 break;
5350 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </h6> found");
5351 break;
5353 break;
5355 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Illegal </hr> tag found");
5356 break;
5358 //warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected tag </a> found");
5359 // ignore </a> tag (can be part of <a name=...></a>
5360 break;
5361
5363 break;
5365 retval = Token::make_TK_NEWPARA();
5366 break;
5379 retval = Token::make_RetVal_CloseXml();
5380 break;
5381 case HtmlTagType::XML_C:
5383 break;
5391 // These tags are defined in .Net but are currently unsupported
5392 break;
5394 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported xml/html tag </%s> found", qPrint(tagName));
5395 children().append<DocWord>(parser(),thisVariant(),"</"+tagName+">");
5396 break;
5397 default:
5398 // we should not get here!
5399 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected end tag %s",qPrint(tagName));
5400 ASSERT(0);
5401 break;
5402 }
5403 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5404 return retval;
5405}
5406
5408{
5409 // expected hierarchy:
5410 // 1. DocAutoListItem <- n
5411 // 2. DocAutoList <- parent(n)
5412 // 3. DocPara <- parent(parent(n))
5413
5414 // step 1
5415 if (!std::get_if<DocAutoListItem>(n)) // not inside a auto list item
5416 {
5417 return false;
5418 }
5419
5420 // step 2
5421 n = parent(n);
5422 int indent = 0;
5423 const auto docAutoList = std::get_if<DocAutoList>(n);
5424 if (docAutoList) // capture indent
5425 {
5426 indent = docAutoList->indent();
5427 }
5428 else
5429 {
5430 return false;
5431 }
5432
5433 // step 3
5434 n = parent(n);
5435 const auto docPara = std::get_if<DocPara>(n);
5436 if (docPara)
5437 {
5438 QCString tagNameLower = QCString(parser->context.token->name).lower();
5439 auto topStyleChange = [](const DocStyleChangeStack &stack) -> const DocStyleChange &
5440 {
5441 return std::get<DocStyleChange>(*stack.top());
5442 };
5443
5444 if (parser->context.styleStack.empty() || // no style change
5445 (topStyleChange(parser->context.styleStack).tagName()==tagNameLower && // correct style change
5446 topStyleChange(parser->context.styleStack).position()!=parser->context.nodeStack.size()) // wrong position, so normal close
5447 )
5448 {
5449 // insert an artificial 'end of autolist' marker and parse again
5450 QCString indentStr;
5451 indentStr.fill(' ',indent);
5452 parser->tokenizer.unputString("\\ilinebr "+indentStr+".\\ilinebr"+indentStr+"</"+parser->context.token->name+">");
5453 return true;
5454 }
5455 }
5456 return false;
5457}
5458
5460{
5461 AUTO_TRACE();
5462 auto ns = AutoNodeStack(parser(),thisVariant());
5463 // handle style commands "inherited" from the previous paragraph
5465 Token tok=parser()->tokenizer.lex();
5466 Token retval = Token::make_TK_NONE();
5467 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5468 {
5469reparsetoken:
5470 AUTO_TRACE_ADD("token '{}' at {}",tok.to_string(),parser()->tokenizer.getLineNr());
5471 if (tok.is_any_of(TokenRetval::TK_WORD,TokenRetval::TK_LNKWORD,TokenRetval::TK_SYMBOL,TokenRetval::TK_URL,
5472 TokenRetval::TK_COMMAND_AT,TokenRetval::TK_COMMAND_BS,TokenRetval::TK_HTMLTAG)
5473 )
5474 {
5475 AUTO_TRACE_ADD("name={}",parser()->context.token->name);
5476 }
5477 switch(tok.value())
5478 {
5479 case TokenRetval::TK_WORD:
5481 break;
5482 case TokenRetval::TK_LNKWORD:
5484 break;
5485 case TokenRetval::TK_URL:
5487 break;
5488 case TokenRetval::TK_WHITESPACE:
5489 {
5490 // prevent leading whitespace and collapse multiple whitespace areas
5491 if (insidePRE(thisVariant()) || // all whitespace is relevant
5492 (
5493 // remove leading whitespace
5494 !children().empty() &&
5495 // and whitespace after certain constructs
5499 )
5500 )
5501 {
5503 }
5504 }
5505 break;
5506 case TokenRetval::TK_LISTITEM:
5507 {
5508 AUTO_TRACE_ADD("found list item at {}",parser()->context.token->indent);
5509 const DocNodeVariant *n=parent();
5510 while (n && !std::holds_alternative<DocAutoList>(*n)) n=::parent(n);
5511 const DocAutoList *al = std::get_if<DocAutoList>(n);
5512 if (al) // we found an auto list up in the hierarchy
5513 {
5514 AUTO_TRACE_ADD("previous list item at {}",al->indent());
5515 if (al->indent()>=parser()->context.token->indent)
5516 // new item at the same or lower indent level
5517 {
5518 retval = Token::make_TK_LISTITEM();
5519 goto endparagraph;
5520 }
5521 }
5522
5523 // determine list depth
5524 int depth = 0;
5525 n=parent();
5526 while (n)
5527 {
5528 al = std::get_if<DocAutoList>(n);
5529 if (al && al->isEnumList()) depth++;
5530 n=::parent(n);
5531 }
5532
5533 // first item or sub list => create new list
5534 do
5535 {
5538 parser()->context.token->isEnumList,depth,
5540 al = children().get_last<DocAutoList>();
5541 retval = children().get_last<DocAutoList>()->parse();
5542 } while (retval.is(TokenRetval::TK_LISTITEM) && // new list
5543 al->indent()==parser()->context.token->indent // at same indent level
5544 );
5545
5546 // check the return value
5547 if (retval.is(TokenRetval::RetVal_SimpleSec)) // auto list ended due to simple section command
5548 {
5549 // Reparse the token that ended the section at this level,
5550 // so a new simple section will be started at this level.
5551 // This is the same as unputting the last read token and continuing.
5553 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5554 {
5557 tok = Token::make_TK_RCSTAG();
5558 }
5559 else // other section
5560 {
5561 tok = Token::make_TK_COMMAND_BS();
5562 }
5563 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5564 goto reparsetoken;
5565 }
5566 else if (retval.is(TokenRetval::TK_ENDLIST))
5567 {
5568 if (al->indent()>parser()->context.token->indent) // end list
5569 {
5570 goto endparagraph;
5571 }
5572 else // continue with current paragraph
5573 {
5574 }
5575 }
5576 else // paragraph ended due to TokenRetval::TK_NEWPARA, TokenRetval::TK_LISTITEM, or EOF
5577 {
5578 goto endparagraph;
5579 }
5580 }
5581 break;
5582 case TokenRetval::TK_ENDLIST:
5583 AUTO_TRACE_ADD("Found end of list inside of paragraph at line {}",parser()->tokenizer.getLineNr());
5584 if (std::get_if<DocAutoListItem>(parent()))
5585 {
5586 const DocAutoList *al = std::get_if<DocAutoList>(::parent(parent()));
5587 if (al && al->indent()>=parser()->context.token->indent)
5588 {
5589 // end of list marker ends this paragraph
5590 retval = Token::make_TK_ENDLIST();
5591 goto endparagraph;
5592 }
5593 else
5594 {
5595 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found "
5596 "has invalid indent level");
5597 }
5598 }
5599 else
5600 {
5601 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"End of list marker found without any preceding "
5602 "list items");
5603 }
5604 break;
5605 case TokenRetval::TK_COMMAND_AT:
5606 // fall through
5607 case TokenRetval::TK_COMMAND_BS:
5608 {
5609 // see if we have to start a simple section
5610 CommandType cmd = Mappers::cmdMapper->map(parser()->context.token->name);
5611 const DocNodeVariant *n=parent();
5612 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5613 !std::holds_alternative<DocParamSect>(*n))
5614 {
5615 n=::parent(n);
5616 }
5618 {
5619 if (n) // already in a simple section
5620 {
5621 // simple section cannot start in this paragraph, need
5622 // to unwind the stack and remember the command.
5624 retval = Token::make_RetVal_SimpleSec();
5625 goto endparagraph;
5626 }
5627 }
5628 // see if we are in a simple list
5629 n=parent();
5630 while (n && !std::holds_alternative<DocSimpleListItem>(*n)) n=::parent(n);
5631 if (n)
5632 {
5633 if (cmd==CommandType::CMD_LI)
5634 {
5635 retval = Token::make_RetVal_ListItem();
5636 goto endparagraph;
5637 }
5638 }
5639
5640 // handle the command
5641 retval=handleCommand(tok.command_to_char(),parser()->context.token->name);
5642 AUTO_TRACE_ADD("handleCommand returns {}",retval.to_string());
5643
5644 // check the return value
5645 if (retval.is(TokenRetval::RetVal_SimpleSec))
5646 {
5647 // Reparse the token that ended the section at this level,
5648 // so a new simple section will be started at this level.
5649 // This is the same as unputting the last read token and continuing.
5651 if (parser()->context.token->name.startsWith("rcs:")) // RCS section
5652 {
5655 tok = Token::make_TK_RCSTAG();
5656 }
5657 else // other section
5658 {
5659 tok = Token::make_TK_COMMAND_BS();
5660 }
5661 AUTO_TRACE_ADD("reparsing command {}",parser()->context.token->name);
5662 goto reparsetoken;
5663 }
5664 else if (retval.value()>TokenRetval::TK_NONE && retval.value()<TokenRetval::RetVal_OK)
5665 {
5666 // the command ended with a new command, reparse this token
5667 tok = retval;
5668 goto reparsetoken;
5669 }
5670 else if (retval.value()!=TokenRetval::RetVal_OK) // end of file, end of paragraph, start or end of section
5671 // or some auto list marker
5672 {
5673 goto endparagraph;
5674 }
5675 }
5676 break;
5677 case TokenRetval::TK_HTMLTAG:
5678 {
5679 if (!parser()->context.token->endTag) // found a start tag
5680 {
5681 retval = handleHtmlStartTag(parser()->context.token->name,parser()->context.token->attribs);
5682 }
5683 else // found an end tag
5684 {
5686 {
5687 break; // new code has been pushed back to the scanner, need to reparse
5688 }
5689 retval = handleHtmlEndTag(parser()->context.token->name);
5690 }
5691 if (!retval.is(TokenRetval::RetVal_OK))
5692 {
5693 goto endparagraph;
5694 }
5695 }
5696 break;
5697 case TokenRetval::TK_SYMBOL:
5698 {
5699 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5701 {
5703 }
5704 else
5705 {
5707 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '%s' found",
5708 qPrint(parser()->context.token->name));
5709 }
5710 break;
5711 }
5712 case TokenRetval::TK_NEWPARA:
5713 retval = Token::make_TK_NEWPARA();
5714 goto endparagraph;
5715 case TokenRetval::TK_RCSTAG:
5716 {
5717 const DocNodeVariant *n=parent();
5718 while (n && !std::holds_alternative<DocSimpleSect>(*n) &&
5719 !std::holds_alternative<DocParamSect>(*n))
5720 {
5721 n=::parent(n);
5722 }
5723 if (n) // already in a simple section
5724 {
5725 // simple section cannot start in this paragraph, need
5726 // to unwind the stack and remember the command.
5729 retval = Token::make_RetVal_SimpleSec();
5730 goto endparagraph;
5731 }
5732
5733 // see if we are in a simple list
5735 children().get_last<DocSimpleSect>()->parseRcs();
5736 }
5737 break;
5738 default:
5739 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5740 "Found unexpected token (id=%s)",tok.to_string());
5741 break;
5742 }
5743 tok=parser()->tokenizer.lex();
5744 }
5745 retval=Token::make_TK_NONE();
5746endparagraph:
5748 DocPara *par = std::get_if<DocPara>(parser()->context.nodeStack.top());
5749 if (!parser()->context.token->endTag && par &&
5750 retval.is(TokenRetval::TK_NEWPARA) && parser()->context.token->name.lower() == "p")
5751 {
5752 par->setAttribs(parser()->context.token->attribs);
5753 }
5754 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::TK_NEWPARA,TokenRetval::TK_LISTITEM,
5755 TokenRetval::TK_ENDLIST,TokenRetval::RetVal_OK)
5756 );
5757
5758 AUTO_TRACE_EXIT("retval={}",retval.to_string());
5759 return retval;
5760}
5761
5762//--------------------------------------------------------------------------
5763
5765{
5766 AUTO_TRACE("start {} level={}", parser()->context.token->sectionId, m_level);
5767 Token retval = Token::make_RetVal_OK();
5768 auto ns = AutoNodeStack(parser(),thisVariant());
5769
5770 if (!m_id.isEmpty())
5771 {
5773 if (sec)
5774 {
5775 m_file = sec->fileName();
5776 m_anchor = sec->label();
5777 QCString titleStr = sec->title();
5778 if (titleStr.isEmpty()) titleStr = sec->label();
5780 DocTitle *title = &std::get<DocTitle>(*m_title);
5781 title->parseFromString(thisVariant(),titleStr);
5782 }
5783 }
5784
5785 // first parse any number of paragraphs
5786 bool isFirst=TRUE;
5787 DocPara *lastPar=nullptr;
5788 do
5789 {
5791 DocPara *par = children().get_last<DocPara>();
5792 if (isFirst) { par->markFirst(); isFirst=FALSE; }
5793 retval=par->parse();
5794 if (!par->isEmpty())
5795 {
5796 if (lastPar) lastPar->markLast(FALSE);
5797 lastPar = par;
5798 }
5799 else
5800 {
5801 children().pop_back();
5802 }
5803 if (retval.is(TokenRetval::TK_LISTITEM))
5804 {
5805 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
5806 }
5807 if (retval.is(TokenRetval::RetVal_Internal))
5808 {
5810 retval = children().get_last<DocInternal>()->parse(m_level+1);
5811 if (retval.is(TokenRetval::RetVal_EndInternal))
5812 {
5813 retval = Token::make_RetVal_OK();
5814 }
5815 }
5816 } while (!retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF, TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
5817 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph,
5818 TokenRetval::RetVal_SubSubParagraph, TokenRetval::RetVal_EndInternal)
5819 );
5820
5821 if (lastPar) lastPar->markLast();
5822
5823 while (true)
5824 {
5825 if (retval.is(TokenRetval::RetVal_Subsection) && m_level<=1)
5826 {
5827 // then parse any number of nested sections
5828 while (retval.is(TokenRetval::RetVal_Subsection)) // more sections follow
5829 {
5831 2,
5833 retval = children().get_last<DocSection>()->parse();
5834 }
5835 break;
5836 }
5837 else if (retval.is(TokenRetval::RetVal_Subsubsection) && m_level<=2)
5838 {
5839 if ((m_level <= 1) &&
5840 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5841 {
5842 warn_doc_error(parser()->context.fileName,
5843 parser()->tokenizer.getLineNr(),
5844 "Unexpected subsubsection command found inside %s!",
5846 }
5847 // then parse any number of nested sections
5848 while (retval.is(TokenRetval::RetVal_Subsubsection)) // more sections follow
5849 {
5851 3,
5853 retval = children().get_last<DocSection>()->parse();
5854 }
5855 if (!(m_level < 2 && retval.is(TokenRetval::RetVal_Subsection))) break;
5856 }
5857 else if (retval.is(TokenRetval::RetVal_Paragraph) && m_level<=3)
5858 {
5859 if ((m_level <= 2) &&
5860 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5861 {
5862 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5863 "Unexpected paragraph command found inside %s!",
5865 }
5866 // then parse any number of nested sections
5867 while (retval.is(TokenRetval::RetVal_Paragraph)) // more sections follow
5868 {
5870 4,
5872 retval = children().get_last<DocSection>()->parse();
5873 }
5874 if (!(m_level<3 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection)))) break;
5875 }
5876 else if (retval.is(TokenRetval::RetVal_SubParagraph) && m_level<=4)
5877 {
5878 if ((m_level <= 3) &&
5879 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5880 {
5881 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5882 "Unexpected subparagraph command found inside %s!",
5884 }
5885 // then parse any number of nested sections
5886 while (retval.is(TokenRetval::RetVal_SubParagraph)) // more sections follow
5887 {
5889 5,
5891 retval = children().get_last<DocSection>()->parse();
5892 }
5893 if (!(m_level<4 && (retval.is_any_of(TokenRetval::RetVal_Subsection,TokenRetval::RetVal_Subsubsection,TokenRetval::RetVal_Paragraph)))) break;
5894 }
5895 else if (retval.is(TokenRetval::RetVal_SubSubParagraph) && m_level<=5)
5896 {
5897 if ((m_level <= 4) &&
5898 !AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
5899 {
5900 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),
5901 "Unexpected subsubparagraph command found inside %s!",
5903 }
5904 // then parse any number of nested sections
5905 while (retval.is(TokenRetval::RetVal_SubSubParagraph)) // more sections follow
5906 {
5908 6,
5910 retval = children().get_last<DocSection>()->parse();
5911 }
5912 if (!(m_level<5 && (retval.is_any_of( TokenRetval::RetVal_Subsection, TokenRetval::RetVal_Subsubsection,
5913 TokenRetval::RetVal_Paragraph, TokenRetval::RetVal_SubParagraph)))) break;
5914 }
5915 else
5916 {
5917 break;
5918 }
5919 }
5920
5921 INTERNAL_ASSERT(retval.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF,
5922 TokenRetval::RetVal_Section, TokenRetval::RetVal_Subsection,
5923 TokenRetval::RetVal_Subsubsection, TokenRetval::RetVal_Paragraph,
5924 TokenRetval::RetVal_SubParagraph, TokenRetval::RetVal_SubSubParagraph,
5925 TokenRetval::RetVal_Internal, TokenRetval::RetVal_EndInternal)
5926 );
5927
5928 AUTO_TRACE_EXIT("retval={}", retval.to_string());
5929 return retval;
5930}
5931
5932//--------------------------------------------------------------------------
5933
5935{
5936 AUTO_TRACE();
5937 auto ns = AutoNodeStack(parser(),thisVariant());
5939
5940 Token tok = parser()->tokenizer.lex();
5941 while (!tok.is_any_of(TokenRetval::TK_NONE, TokenRetval::TK_EOF)) // get the next token
5942 {
5943 switch(tok.value())
5944 {
5945 case TokenRetval::TK_WORD:
5947 break;
5948 case TokenRetval::TK_WHITESPACE:
5950 break;
5951 case TokenRetval::TK_SYMBOL:
5952 {
5953 HtmlEntityMapper::SymType s = DocSymbol::decodeSymbol(parser()->context.token->name);
5955 {
5957 }
5958 else
5959 {
5960 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unsupported symbol '%s' found",
5961 qPrint(parser()->context.token->name));
5962 }
5963 }
5964 break;
5965 case TokenRetval::TK_COMMAND_AT:
5966 // fall through
5967 case TokenRetval::TK_COMMAND_BS:
5968 switch (Mappers::cmdMapper->map(parser()->context.token->name))
5969 {
5972 break;
5975 break;
5978 break;
5981 break;
5984 break;
5987 break;
5990 break;
5993 break;
5996 break;
6000 break;
6005 break;
6008 break;
6011 break;
6014 break;
6017 break;
6020 break;
6023 break;
6026 break;
6027 default:
6028 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected command '%s' found",
6029 qPrint(parser()->context.token->name));
6030 break;
6031 }
6032 break;
6033 default:
6034 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Unexpected token %s",
6035 tok.to_string());
6036 break;
6037 }
6038 tok = parser()->tokenizer.lex();
6039 }
6040
6042
6043}
6044
6045
6046//--------------------------------------------------------------------------
6047
6049{
6050 AUTO_TRACE();
6051 auto ns = AutoNodeStack(parser(),thisVariant());
6053 Token retval = Token::make_TK_NONE();
6054
6055 // first parse any number of paragraphs
6056 bool isFirst=TRUE;
6057 DocPara *lastPar = nullptr;
6058 do
6059 {
6060 {
6062 DocPara *par = children().get_last<DocPara>();
6063 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6064 retval=par->parse();
6065 if (par->isEmpty() && par->attribs().empty())
6066 {
6067 children().pop_back();
6068 }
6069 else
6070 {
6071 lastPar = par;
6072 }
6073 }
6074 auto checkParagraph = [this,&retval](Token t,int level,const char *sectionType,const char *parentSectionType) {
6075 if (retval == t)
6076 {
6077 if (!AnchorGenerator::instance().isGenerated(parser()->context.token->sectionId.str()))
6078 {
6079 warn_doc_error(parser()->context.fileName,
6080 parser()->tokenizer.getLineNr(),
6081 "found %s command (id: '%s') outside of %s context!",
6082 sectionType,qPrint(parser()->context.token->sectionId),parentSectionType);
6083 }
6084 while (retval==t)
6085 {
6086 if (!parser()->context.token->sectionId.isEmpty())
6087 {
6088 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6089 if (sec)
6090 {
6092 level,
6094 retval = children().get_last<DocSection>()->parse();
6095 }
6096 else
6097 {
6098 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid %s id '%s'; ignoring %s",
6099 sectionType,qPrint(parser()->context.token->sectionId),sectionType);
6100 retval = Token::make_TK_NONE();
6101 }
6102 }
6103 else
6104 {
6105 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for %s; ignoring %s",sectionType,sectionType);
6106 retval = Token::make_TK_NONE();
6107 }
6108 }
6109 }
6110 };
6111 checkParagraph(Token::make_RetVal_SubSubParagraph(), 6, "subsubparagraph", "subparagraph" );
6112 checkParagraph(Token::make_RetVal_SubParagraph(), 5, "subparagraph", "paragraph" );
6113 checkParagraph(Token::make_RetVal_Paragraph(), 4, "paragraph", "subsubsection" );
6114 checkParagraph(Token::make_RetVal_Subsubsection(), 3, "subsubsection", "subsection" );
6115 checkParagraph(Token::make_RetVal_Subsection(), 2, "subsection", "section" );
6116
6117 if (retval.is(TokenRetval::TK_LISTITEM))
6118 {
6119 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid list item found");
6120 }
6121 if (retval.is(TokenRetval::RetVal_Internal))
6122 {
6124 retval = children().get_last<DocInternal>()->parse(1);
6125 }
6126 } while (!retval.is_any_of(TokenRetval::TK_NONE,TokenRetval::TK_EOF,TokenRetval::RetVal_Section));
6127 if (lastPar) lastPar->markLast();
6128
6129 //printf("DocRoot::parse() retval=%d %d\n",retval,TokenRetval::RetVal_Section);
6130 // then parse any number of level1 sections
6131 while (retval.is(TokenRetval::RetVal_Section))
6132 {
6133 if (!parser()->context.token->sectionId.isEmpty())
6134 {
6135 const SectionInfo *sec=SectionManager::instance().find(parser()->context.token->sectionId);
6136 if (sec)
6137 {
6139 1,
6141 retval = children().get_last<DocSection>()->parse();
6142 }
6143 else
6144 {
6145 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Invalid section id '%s'; ignoring section",qPrint(parser()->context.token->sectionId));
6146 retval = Token::make_TK_NONE();
6147 }
6148 }
6149 else
6150 {
6151 warn_doc_error(parser()->context.fileName,parser()->tokenizer.getLineNr(),"Missing id for section; ignoring section");
6152 retval = Token::make_TK_NONE();
6153 }
6154 }
6155
6157}
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:40
QCString anchorPrefix() const
Definition cite.cpp:122
const CiteInfo * find(const QCString &label) const
Return the citation info for a given label.
Definition cite.cpp:96
static CitationManager & instance()
Definition cite.cpp:80
QCString fileName() const
Definition cite.cpp:117
Class representing a Boolean type option.
Definition configimpl.h:254
QCString * valueStringRef()
Definition configimpl.h:264
Class representing an enum type option.
Definition configimpl.h:156
QCString * valueRef()
Definition configimpl.h:168
static ConfigImpl * instance()
Definition configimpl.h:350
ConfigOption * get(const QCString &name) const
Definition configimpl.h:399
Class representing an integer type option.
Definition configimpl.h:219
QCString * valueStringRef()
Definition configimpl.h:231
Class representing a list type option.
Definition configimpl.h:124
Abstract base class for any configuration option.
Definition configimpl.h:38
@ O_Disabled
Disabled compile time option.
Definition configimpl.h:54
@ O_List
A list of items.
Definition configimpl.h:48
@ O_Enum
A fixed set of items.
Definition configimpl.h:49
@ O_Bool
A boolean value.
Definition configimpl.h:52
@ O_String
A single item.
Definition configimpl.h:50
@ O_Obsolete
An obsolete option.
Definition configimpl.h:53
@ O_Int
An integer value.
Definition configimpl.h:51
@ O_Info
A section header.
Definition configimpl.h:47
OptionType kind() const
Definition configimpl.h:69
Class representing a string type option.
Definition configimpl.h:187
QCString * valueRef()
Definition configimpl.h:200
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:208
QCString m_anchor
Definition docnode.h:237
QCString m_file
Definition docnode.h:238
Node representing an auto List.
Definition docnode.h:566
int m_depth
Definition docnode.h:585
bool isCheckedList() const
Definition docnode.h:577
bool isEnumList() const
Definition docnode.h:575
int depth() const
Definition docnode.h:578
int m_indent
Definition docnode.h:582
Token parse()
Definition docnode.cpp:2811
bool m_isCheckedList
Definition docnode.h:584
int indent() const
Definition docnode.h:576
DocAutoList(DocParser *parser, DocNodeVariant *parent, int indent, bool isEnumList, int depth, bool isCheckedList)
Definition docnode.cpp:2804
bool m_isEnumList
Definition docnode.h:583
Node representing an item of a auto list.
Definition docnode.h:590
DocAutoListItem(DocParser *parser, DocNodeVariant *parent, int indent, int num)
Definition docnode.cpp:2764
Node representing a citation of some bibliographic reference.
Definition docnode.h:244
QCString m_anchor
Definition docnode.h:257
DocCite(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context)
Definition docnode.cpp:887
QCString m_relPath
Definition docnode.h:255
QCString m_ref
Definition docnode.h:256
QCString m_file
Definition docnode.h:254
QCString m_text
Definition docnode.h:258
DocNodeList & children()
Definition docnode.h:142
DocCompoundNode(DocParser *parser, DocNodeVariant *parent)
Definition docnode.h:140
bool parse()
Definition docnode.cpp:1136
DocDiaFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1129
QCString srcFile() const
Definition docnode.h:685
std::unique_ptr< Private > p
Definition docnode.h:702
int srcLine() const
Definition docnode.h:686
DocDiagramFileBase(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.h:675
QCString context() const
Definition docnode.h:684
QCString name() const
Definition docnode.h:678
bool parse()
Definition docnode.cpp:1058
DocDotFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1051
Node representing an emoji.
Definition docnode.h:336
DocEmoji(DocParser *parser, DocNodeVariant *parent, const QCString &symName)
Definition docnode.cpp:159
int m_index
Definition docnode.h:344
QCString m_symName
Definition docnode.h:343
Node representing an item of a cross-referenced list.
Definition docnode.h:524
QCString m_relPath
Definition docnode.h:541
QCString m_text
Definition docnode.h:540
int id() const
Definition docnode.h:530
QCString m_name
Definition docnode.h:539
DocFormula(DocParser *parser, DocNodeVariant *parent, int id)
Definition docnode.cpp:514
QCString relPath() const
Definition docnode.h:529
Token parse()
Definition docnode.cpp:1450
Node representing a horizontal ruler.
Definition docnode.h:215
Node representing an HTML blockquote.
Definition docnode.h:1285
HtmlAttribList m_attribs
Definition docnode.h:1232
bool m_hasCaptionId
Definition docnode.h:1233
DocHtmlCaption(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs)
Definition docnode.cpp:1657
QCString m_file
Definition docnode.h:1234
const HtmlAttribList & attribs() const
Definition docnode.h:1225
QCString m_anchor
Definition docnode.h:1235
Node representing a HTML table cell.
Definition docnode.h:1187
Valignment valignment() const
Definition docnode.cpp:1861
void setColumnIndex(uint32_t idx)
Definition docnode.h:1211
bool isFirst() const
Definition docnode.h:1195
Token parseXml()
Definition docnode.cpp:1765
void setRowIndex(uint32_t idx)
Definition docnode.h:1210
void markLast(bool v=TRUE)
Definition docnode.h:1198
uint32_t rowSpan() const
Definition docnode.cpp:1799
void markFirst(bool v=TRUE)
Definition docnode.h:1197
Alignment alignment() const
Definition docnode.cpp:1823
bool isHeading() const
Definition docnode.h:1194
const HtmlAttribList & attribs() const
Definition docnode.h:1199
Token parse()
Definition docnode.cpp:1731
uint32_t colSpan() const
Definition docnode.cpp:1811
Node representing a HTML description data.
Definition docnode.h:1175
HtmlAttribList m_attribs
Definition docnode.h:1182
Node representing a Html description list.
Definition docnode.h:895
Node representing a Html description item.
Definition docnode.h:882
Node Html details.
Definition docnode.h:851
const HtmlAttribList & attribs() const
Definition docnode.h:855
void parseSummary(DocNodeVariant *, HtmlAttribList &attribs)
Definition docnode.cpp:1440
const DocNodeVariant * summary() const
Definition docnode.h:858
std::unique_ptr< DocNodeVariant > m_summary
Definition docnode.h:862
Node Html heading.
Definition docnode.h:867
Token parse()
Definition docnode.cpp:1265
Node representing a Html list.
Definition docnode.h:994
Type m_type
Definition docnode.h:1005
Token parseXml()
Definition docnode.cpp:2611
Token parse()
Definition docnode.cpp:2536
Node representing a HTML list item.
Definition docnode.h:1159
Node representing a HTML table row.
Definition docnode.h:1240
Token parseXml(bool header)
Definition docnode.cpp:1963
void setVisibleCells(uint32_t n)
Definition docnode.h:1250
bool isHeading() const
Definition docnode.cpp:1883
void setRowIndex(uint32_t idx)
Definition docnode.h:1255
Token parse()
Definition docnode.cpp:1898
Node Html summary.
Definition docnode.h:838
Node representing a HTML table.
Definition docnode.h:1263
Token parseXml()
Definition docnode.cpp:2121
std::unique_ptr< DocNodeVariant > m_caption
Definition docnode.h:1278
Token parse()
Definition docnode.cpp:2043
void computeTableGrid()
determines the location of all cells in a grid, resolving row and column spans.
Definition docnode.cpp:2178
size_t m_numCols
Definition docnode.h:1280
const DocNodeVariant * caption() const
Definition docnode.cpp:2029
bool hasCaption() const
Definition docnode.cpp:2024
const DocNodeVariant * firstRow() const
Definition docnode.cpp:2034
const HtmlAttribList & attribs() const
Definition docnode.h:650
QCString relPath() const
Definition docnode.h:646
QCString name() const
Definition docnode.h:642
QCString url() const
Definition docnode.h:647
DocImage(DocParser *parser, DocNodeVariant *parent, const HtmlAttribList &attribs, const QCString &name, Type t, const QCString &url=QCString(), bool inlineImage=TRUE)
Definition docnode.cpp:1242
std::unique_ptr< Private > p
Definition docnode.h:669
void parse()
Definition docnode.cpp:1257
bool isSVG() const
Definition docnode.cpp:1248
Node representing a include/dontinclude operator block.
Definition docnode.h:472
bool m_stripCodeComments
Definition docnode.h:516
const char * typeAsString() const
Definition docnode.h:481
QCString m_includeFileName
Definition docnode.h:519
QCString context() const
Definition docnode.h:496
Type type() const
Definition docnode.h:480
QCString m_pattern
Definition docnode.h:512
void markLast(bool v=TRUE)
Definition docnode.h:500
QCString m_text
Definition docnode.h:511
bool m_showLineNo
Definition docnode.h:510
Node representing an included text block from file.
Definition docnode.h:430
void parse()
Definition docnode.cpp:267
QCString m_text
Definition docnode.h:460
Type m_type
Definition docnode.h:461
@ LatexInclude
Definition docnode.h:432
@ SnippetWithLines
Definition docnode.h:433
@ DontIncWithLines
Definition docnode.h:434
@ IncWithLines
Definition docnode.h:433
@ HtmlInclude
Definition docnode.h:432
@ VerbInclude
Definition docnode.h:432
@ DontInclude
Definition docnode.h:432
@ DocbookInclude
Definition docnode.h:434
QCString m_blockId
Definition docnode.h:467
bool m_stripCodeComments
Definition docnode.h:462
QCString context() const
Definition docnode.h:448
QCString m_file
Definition docnode.h:458
Node representing an entry in the index.
Definition docnode.h:547
QCString m_entry
Definition docnode.h:557
Token parse()
Definition docnode.cpp:1560
Node representing an internal section of documentation.
Definition docnode.h:963
Token parse(int)
Definition docnode.cpp:1500
QCString m_file
Definition docnode.h:810
QCString m_anchor
Definition docnode.h:812
DocInternalRef(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:670
QCString relPath() const
Definition docnode.h:806
QCString m_relPath
Definition docnode.h:811
Node representing a line break.
Definition docnode.h:201
QCString m_word
Definition docnode.h:177
QCString m_anchor
Definition docnode.h:181
QCString file() const
Definition docnode.h:170
QCString relPath() const
Definition docnode.h:171
QCString ref() const
Definition docnode.h:172
QCString word() const
Definition docnode.h:169
QCString m_file
Definition docnode.h:179
QCString anchor() const
Definition docnode.h:173
QCString m_ref
Definition docnode.h:178
QCString m_relPath
Definition docnode.h:180
DocLinkedWord(DocParser *parser, DocNodeVariant *parent, const QCString &word, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &tooltip)
Definition docnode.cpp:191
QCString m_tooltip
Definition docnode.h:182
QCString tooltip() const
Definition docnode.h:174
DocMscFile(DocParser *parser, DocNodeVariant *parent, const QCString &name, const QCString &context, const QCString &srcFile, int srcLine)
Definition docnode.cpp:1089
bool parse()
Definition docnode.cpp:1096
DocNode(DocParser *parser, DocNodeVariant *parent)
Definition docnode.h:84
void setInsidePreformatted(bool p)
Definition docnode.h:108
DocNodeVariant * thisVariant()
Definition docnode.h:92
DocParser * parser()
Definition docnode.h:97
DocNodeVariant * parent()
Definition docnode.h:89
@ Unknown
Definition docnode.h:109
@ Table
Definition docnode.h:109
@ Section
Definition docnode.h:109
@ Anchor
Definition docnode.h:109
Node representing an block of paragraphs.
Definition docnode.h:973
Token parse()
Definition docnode.cpp:2705
Node representing a paragraph in the documentation tree.
Definition docnode.h:1074
Token handleSimpleSection(DocSimpleSect::Type t, bool xmlContext=FALSE)
Definition docnode.cpp:3233
void handleLink(const QCString &cmdName, bool isJavaLink)
Definition docnode.cpp:3676
void handleInheritDoc()
Definition docnode.cpp:3934
void handleCite(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3286
DocPara(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:3227
void handleInclude(const QCString &cmdName, DocInclude::Type t)
Definition docnode.cpp:3744
Token handleCommand(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3971
void handleDoxyConfig(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3349
void handleSection(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3849
void handleFile(const QCString &cmdName)
Definition docnode.cpp:3637
void handleIFile(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3553
Token handleParamSection(const QCString &cmdName, DocParamSect::Type t, bool xmlContext, int direction)
Definition docnode.cpp:3263
void markLast(bool v=TRUE)
Definition docnode.h:1080
Token handleHtmlStartTag(const QCString &tagName, const HtmlAttribList &tagHtmlAttribs)
Definition docnode.cpp:4721
void handleEmoji(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3318
void handleIncludeOperator(const QCString &cmdName, DocIncOperator::Type t)
Definition docnode.cpp:3577
bool isFirst() const
Definition docnode.h:1081
void markFirst(bool v=TRUE)
Definition docnode.h:1079
void handleRef(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3717
void handleILine(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3539
void setAttribs(const HtmlAttribList &attribs)
Definition docnode.h:1109
bool m_isFirst
Definition docnode.h:1112
Token parse()
Definition docnode.cpp:5459
void handleVhdlFlow()
Definition docnode.cpp:3669
Token handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs, int level)
Definition docnode.cpp:3880
void handleShowDate(char cmdChar, const QCString &cmdName)
Definition docnode.cpp:3468
bool m_isLast
Definition docnode.h:1113
Token handleXRefItem()
Definition docnode.cpp:3447
Token handleHtmlEndTag(const QCString &tagName)
Definition docnode.cpp:5189
Token handleStartCode()
Definition docnode.cpp:3898
bool injectToken(Token tok, const QCString &tokText)
Definition docnode.cpp:3891
DocNodeList m_paramTypes
Definition docnode.h:1138
DocNodeList m_paragraphs
Definition docnode.h:1136
void markFirst(bool b=TRUE)
Definition docnode.h:1128
Token parseXml(const QCString &paramName)
Definition docnode.cpp:3116
void markLast(bool b=TRUE)
Definition docnode.h:1129
Token parse(const QCString &cmdName)
Definition docnode.cpp:3037
DocParamSect::Type m_type
Definition docnode.h:1139
DocNodeList m_params
Definition docnode.h:1137
Node representing a parameter section.
Definition docnode.h:1047
friend class DocParamList
Definition docnode.h:1048
Token parse(const QCString &cmdName, bool xmlContext, Direction d)
Definition docnode.cpp:3184
bool m_hasInOutSpecifier
Definition docnode.h:1068
Type type() const
Definition docnode.h:1062
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:73
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:59
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:1168
Node representing a reference to some item.
Definition docnode.h:772
QCString anchor() const
Definition docnode.h:779
QCString m_file
Definition docnode.h:792
SectionType m_sectionType
Definition docnode.h:790
QCString m_text
Definition docnode.h:796
void parse()
Definition docnode.cpp:841
QCString m_ref
Definition docnode.h:794
QCString m_relPath
Definition docnode.h:793
DocRef(DocParser *parser, DocNodeVariant *parent, const QCString &target, const QCString &context)
Definition docnode.cpp:705
RefType m_refType
Definition docnode.h:789
QCString m_anchor
Definition docnode.h:795
bool m_isSubPage
Definition docnode.h:791
void parse()
Definition docnode.cpp:6048
Node representing a reference to a section.
Definition docnode.h:929
QCString m_file
Definition docnode.h:945
QCString m_target
Definition docnode.h:942
QCString relPath() const
Definition docnode.h:935
bool m_isSubPage
Definition docnode.h:944
QCString m_anchor
Definition docnode.h:948
QCString target() const
Definition docnode.h:932
QCString m_ref
Definition docnode.h:947
DocSecRefItem(DocParser *parser, DocNodeVariant *parent, const QCString &target)
Definition docnode.cpp:533
QCString m_relPath
Definition docnode.h:946
RefType m_refType
Definition docnode.h:943
Node representing a list of section references.
Definition docnode.h:953
Node representing a normal section.
Definition docnode.h:908
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:922
QCString m_id
Definition docnode.h:921
QCString m_file
Definition docnode.h:924
Token parse()
Definition docnode.cpp:5764
DocSection(DocParser *parser, DocNodeVariant *parent, int level, const QCString &id)
Definition docnode.h:910
const DocNodeVariant * title() const
Definition docnode.h:913
QCString m_anchor
Definition docnode.h:923
int m_level
Definition docnode.h:920
Node representing a simple list.
Definition docnode.h:984
Token parse()
Definition docnode.cpp:2749
Node representing a simple list item.
Definition docnode.h:1147
std::unique_ptr< DocNodeVariant > m_paragraph
Definition docnode.h:1154
DocSimpleListItem(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:2730
Node representing a simple section.
Definition docnode.h:1011
QCString typeString() const
Definition docnode.cpp:3008
Type type() const
Definition docnode.h:1020
Token parse(bool userTitle, bool needsSeparator)
Definition docnode.cpp:2898
Token parseRcs()
Definition docnode.cpp:2935
DocSimpleSect(DocParser *parser, DocNodeVariant *parent, Type t)
Definition docnode.cpp:2888
const DocNodeVariant * title() const
Definition docnode.h:1027
Token parseXml()
Definition docnode.cpp:2952
void appendLinkWord(const QCString &word)
Definition docnode.cpp:2988
bool hasTitle() const
Definition docnode.cpp:2893
std::unique_ptr< DocNodeVariant > m_title
Definition docnode.h:1031
Node representing a separator between two simple sections of the same type.
Definition docnode.h:1038
Node representing a style change.
Definition docnode.h:264
const char * styleString() const
Definition docnode.cpp:125
Style m_style
Definition docnode.h:313
Node representing a special symbol.
Definition docnode.h:323
static HtmlEntityMapper::SymType decodeSymbol(const QCString &symName)
Definition docnode.cpp:152
void parse()
Definition docnode.cpp:5934
Node representing a simple section title.
Definition docnode.h:603
void parse()
Definition docnode.cpp:2857
void parseFromString(DocNodeVariant *, const QCString &title)
Definition docnode.cpp:2875
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:187
Node representing a verbatim, unparsed text fragment.
Definition docnode.h:371
DocVerbatim(DocParser *parser, DocNodeVariant *parent, const QCString &context, const QCString &text, Type t, bool isExample, const QCString &exampleFile, bool isBlock=FALSE, const QCString &lang=QCString())
Definition docnode.cpp:257
std::unique_ptr< Private > p
Definition docnode.h:424
bool isBlock() const
Definition docnode.h:384
bool isExample() const
Definition docnode.h:380
QCString context() const
Definition docnode.h:379
QCString text() const
Definition docnode.h:378
QCString exampleFile() const
Definition docnode.h:381
QCString relPath() const
Definition docnode.h:382
void setEngine(const QCString &e)
Definition docnode.h:397
@ JavaDocLiteral
Definition docnode.h:373
Node representing a VHDL flow chart.
Definition docnode.h:743
DocVhdlFlow(DocParser *parser, DocNodeVariant *parent)
Definition docnode.cpp:1212
void parse()
Definition docnode.cpp:1216
Node representing some amount of white space.
Definition docnode.h:349
Node representing a word.
Definition docnode.h:152
DocWord(DocParser *parser, DocNodeVariant *parent, const QCString &word)
Definition docnode.cpp:179
QCString m_word
Definition docnode.h:158
QCString word() const
Definition docnode.h:155
Node representing an item of a cross-referenced list.
Definition docnode.h:615
QCString m_anchor
Definition docnode.h:629
DocXRefItem(DocParser *parser, DocNodeVariant *parent, int id, const QCString &key)
Definition docnode.cpp:472
QCString key() const
Definition docnode.h:622
QCString relPath() const
Definition docnode.h:621
QCString m_file
Definition docnode.h:628
QCString m_key
Definition docnode.h:627
QCString m_title
Definition docnode.h:630
bool parse()
Definition docnode.cpp:477
QCString m_relPath
Definition docnode.h:631
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
Find an object given the key.
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:175
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
Iterator class to iterator 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:809
#define AUTO_TRACE_EXIT(...)
Definition docnode.cpp:48
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, const char *attrName, QCString *result)
Definition docnode.cpp:4705
std::vector< ActiveRowSpan > RowSpanList
List of ActiveRowSpan classes.
Definition docnode.cpp:2172
static void setParent(DocNodeVariant *n, DocNodeVariant *newParent)
Definition docnode.cpp:118
static bool checkIfHtmlEndTagEndsAutoList(DocParser *parser, const DocNodeVariant *n)
Definition docnode.cpp:5407
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:66
constexpr bool holds_one_of_alternatives(const DocNodeVariant &v)
returns true iff v holds one of types passed as template parameters
Definition docnode.h:1360
DocNodeList * call_method_children(DocNodeVariant *v)
Definition docnode.h:1379
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:1324
std::unique_ptr< DocNodeVariant > createDocNode(Args &&...args)
Definition docnode.h:1485
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:1894
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:59
#define err(fmt,...)
Definition message.h:84
#define warn_doc_error(file, line, fmt,...)
Definition message.h:74
const Mapper< HtmlTagType > * htmlTagMapper
const Mapper< CommandType > * cmdMapper
QCString trunc(const QCString &s, size_t numChars=15)
Definition trace.h:56
Definition trace.h:153
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:2167
uint32_t column
Definition docnode.cpp:2168
ActiveRowSpan(uint32_t rows, uint32_t col)
Definition docnode.cpp:2166
Citation-related data.
Definition cite.h:27
virtual QCString text() const =0
virtual QCString label() const =0
void move_append(DocNodeList &l)
moves the element of list l at the end of this list.
Definition docnode.cpp:800
void append(Args &&... args)
Append a new DocNodeVariant to the list by constructing it with type T and parameters Args.
Definition docnode.h:1393
T * get_last()
Returns a pointer to the last element in the list if that element exists and holds a T,...
Definition docnode.h:1404
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
@ Markdown
Definition types.h:57
QCString linkToText(SrcLangExt lang, const QCString &link, bool isFileName)
Definition util.cpp:3100
SrcLangExt getLanguageFromFileName(const QCString &fileName, SrcLangExt defLang)
Definition util.cpp:5549
bool resolveLink(const QCString &scName, const QCString &lr, bool, const Definition **resContext, QCString &resAnchor, const QCString &prefix)
Definition util.cpp:3126
std::string_view word
Definition util.cpp:980
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition util.cpp:3388
bool found
Definition util.cpp:984
QCString stripScope(const QCString &name)
Definition util.cpp:4133
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition util.cpp:3858
if(strLen >35 &&floatingIndex >30 &&autoBreak)
Definition util.cpp:949
StringVector split(const std::string &s, const std::string &delimiter)
split input string s by string delimiter delimiter.
Definition util.cpp:6946
QCString stripLeadingAndTrailingEmptyLines(const QCString &s, int &docLine)
Special version of QCString::stripWhiteSpace() that only strips completely blank lines.
Definition util.cpp:5368
QCString stripIndentation(const QCString &s)
Definition util.cpp:6282
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition util.cpp:3262
A bunch of utility functions.