1 /******************************************************************************
6 * Copyright (C) 1997-2014 by Dimitri van Heesch.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation under the terms of the GNU General Public License is hereby
10 * granted. No representations are made about the suitability of this software
11 * for any purpose. It is provided "as is" without express or implied warranty.
12 * See the GNU General Public License for more details.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
19 #include <qfileinfo.h>
21 #include "xmldocvisitor.h"
22 #include "docparser.h"
25 #include "outputgen.h"
30 #include "parserintf.h"
33 #include "htmlentity.h"
35 XmlDocVisitor::XmlDocVisitor(FTextStream &t,CodeOutputInterface &ci)
36 : DocVisitor(DocVisitor_XML), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE)
40 //--------------------------------------
41 // visitor functions for leaf nodes
42 //--------------------------------------
44 void XmlDocVisitor::visit(DocWord *w)
50 void XmlDocVisitor::visit(DocLinkedWord *w)
53 startLink(w->ref(),w->file(),w->anchor());
58 void XmlDocVisitor::visit(DocWhiteSpace *w)
71 void XmlDocVisitor::visit(DocSymbol *s)
74 const char *res = HtmlEntityMapper::instance()->xml(s->symbol());
81 err("XML: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
85 void XmlDocVisitor::visit(DocURL *u)
88 m_t << "<ulink url=\"";
89 if (u->isEmail()) m_t << "mailto:";
96 void XmlDocVisitor::visit(DocLineBreak *)
99 m_t << "<linebreak/>\n";
102 void XmlDocVisitor::visit(DocHorRuler *)
105 m_t << "<hruler/>\n";
108 void XmlDocVisitor::visit(DocStyleChange *s)
113 case DocStyleChange::Bold:
114 if (s->enable()) m_t << "<bold>"; else m_t << "</bold>";
116 case DocStyleChange::Italic:
117 if (s->enable()) m_t << "<emphasis>"; else m_t << "</emphasis>";
119 case DocStyleChange::Code:
120 if (s->enable()) m_t << "<computeroutput>"; else m_t << "</computeroutput>";
122 case DocStyleChange::Subscript:
123 if (s->enable()) m_t << "<subscript>"; else m_t << "</subscript>";
125 case DocStyleChange::Superscript:
126 if (s->enable()) m_t << "<superscript>"; else m_t << "</superscript>";
128 case DocStyleChange::Center:
129 if (s->enable()) m_t << "<center>"; else m_t << "</center>";
131 case DocStyleChange::Small:
132 if (s->enable()) m_t << "<small>"; else m_t << "</small>";
134 case DocStyleChange::Preformatted:
137 m_t << "<preformatted>";
142 m_t << "</preformatted>";
146 case DocStyleChange::Div: /* HTML only */ break;
147 case DocStyleChange::Span: /* HTML only */ break;
151 void XmlDocVisitor::visit(DocVerbatim *s)
154 QCString lang = m_langExt;
155 if (!s->language().isEmpty()) // explicit language setting
157 lang = s->language();
159 SrcLangExt langExt = getLanguageFromFileName(lang);
162 case DocVerbatim::Code: // fall though
163 m_t << "<programlisting>";
164 Doxygen::parserManager->getParser(lang)
165 ->parseCode(m_ci,s->context(),s->text(),langExt,
166 s->isExample(),s->exampleFile());
167 m_t << "</programlisting>";
169 case DocVerbatim::Verbatim:
172 m_t << "</verbatim>";
174 case DocVerbatim::HtmlOnly:
177 m_t << "</htmlonly>";
179 case DocVerbatim::RtfOnly:
184 case DocVerbatim::ManOnly:
189 case DocVerbatim::LatexOnly:
190 m_t << "<latexonly>";
192 m_t << "</latexonly>";
194 case DocVerbatim::XmlOnly:
197 case DocVerbatim::DocbookOnly:
198 m_t << "<docbookonly>";
200 m_t << "</docbookonly>";
202 case DocVerbatim::Dot:
207 case DocVerbatim::Msc:
212 case DocVerbatim::PlantUML:
215 m_t << "</plantuml>";
220 void XmlDocVisitor::visit(DocAnchor *anc)
223 m_t << "<anchor id=\"" << anc->file() << "_1" << anc->anchor() << "\"/>";
226 void XmlDocVisitor::visit(DocInclude *inc)
229 SrcLangExt langExt = getLanguageFromFileName(inc->extension());
232 case DocInclude::IncWithLines:
234 m_t << "<programlisting>";
235 QFileInfo cfi( inc->file() );
236 FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
237 Doxygen::parserManager->getParser(inc->extension())
238 ->parseCode(m_ci,inc->context(),
242 inc->exampleFile(), &fd);
243 m_t << "</programlisting>";
246 case DocInclude::Include:
247 m_t << "<programlisting>";
248 Doxygen::parserManager->getParser(inc->extension())
249 ->parseCode(m_ci,inc->context(),
254 m_t << "</programlisting>";
256 case DocInclude::DontInclude:
258 case DocInclude::HtmlInclude:
261 m_t << "</htmlonly>";
263 case DocInclude::LatexInclude:
264 m_t << "<latexonly>";
266 m_t << "</latexonly>";
268 case DocInclude::VerbInclude:
271 m_t << "</verbatim>";
273 case DocInclude::Snippet:
274 m_t << "<programlisting>";
275 Doxygen::parserManager->getParser(inc->extension())
278 extractBlock(inc->text(),inc->blockId()),
283 m_t << "</programlisting>";
288 void XmlDocVisitor::visit(DocIncOperator *op)
290 //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
291 // op->type(),op->isFirst(),op->isLast(),op->text().data());
296 m_t << "<programlisting>";
301 SrcLangExt langExt = getLanguageFromFileName(m_langExt);
302 if (op->type()!=DocIncOperator::Skip)
307 Doxygen::parserManager->getParser(m_langExt)
308 ->parseCode(m_ci,op->context(),
309 op->text(),langExt,op->isExample(),
318 if (!m_hide) m_t << "</programlisting>";
322 if (!m_hide) m_t << endl;
326 void XmlDocVisitor::visit(DocFormula *f)
329 m_t << "<formula id=\"" << f->id() << "\">";
334 void XmlDocVisitor::visit(DocIndexEntry *ie)
337 m_t << "<indexentry>"
340 m_t << "</primaryie>"
341 "<secondaryie></secondaryie>"
345 void XmlDocVisitor::visit(DocSimpleSectSep *sep)
347 if (sep->parent() && sep->parent()->kind()==DocNode::Kind_SimpleSect)
349 visitPost((DocSimpleSect*)sep->parent()); // end current section
350 visitPre((DocSimpleSect*)sep->parent()); // start new section
354 void XmlDocVisitor::visit(DocCite *cite)
357 if (!cite->file().isEmpty()) startLink(cite->ref(),cite->file(),cite->anchor());
358 filter(cite->text());
359 if (!cite->file().isEmpty()) endLink();
362 //--------------------------------------
363 // visitor functions for compound nodes
364 //--------------------------------------
366 void XmlDocVisitor::visitPre(DocAutoList *l)
371 m_t << "<orderedlist>\n";
375 m_t << "<itemizedlist>\n";
379 void XmlDocVisitor::visitPost(DocAutoList *l)
384 m_t << "</orderedlist>\n";
388 m_t << "</itemizedlist>\n";
392 void XmlDocVisitor::visitPre(DocAutoListItem *)
398 void XmlDocVisitor::visitPost(DocAutoListItem *)
401 m_t << "</listitem>";
404 void XmlDocVisitor::visitPre(DocPara *)
410 void XmlDocVisitor::visitPost(DocPara *)
416 void XmlDocVisitor::visitPre(DocRoot *)
418 //m_t << "<hr><h4><font color=\"red\">New parser:</font></h4>\n";
421 void XmlDocVisitor::visitPost(DocRoot *)
423 //m_t << "<hr><h4><font color=\"red\">Old parser:</font></h4>\n";
426 void XmlDocVisitor::visitPre(DocSimpleSect *s)
429 m_t << "<simplesect kind=\"";
432 case DocSimpleSect::See:
434 case DocSimpleSect::Return:
435 m_t << "return"; break;
436 case DocSimpleSect::Author:
437 m_t << "author"; break;
438 case DocSimpleSect::Authors:
439 m_t << "authors"; break;
440 case DocSimpleSect::Version:
441 m_t << "version"; break;
442 case DocSimpleSect::Since:
443 m_t << "since"; break;
444 case DocSimpleSect::Date:
445 m_t << "date"; break;
446 case DocSimpleSect::Note:
447 m_t << "note"; break;
448 case DocSimpleSect::Warning:
449 m_t << "warning"; break;
450 case DocSimpleSect::Pre:
452 case DocSimpleSect::Post:
453 m_t << "post"; break;
454 case DocSimpleSect::Copyright:
455 m_t << "copyright"; break;
456 case DocSimpleSect::Invar:
457 m_t << "invariant"; break;
458 case DocSimpleSect::Remark:
459 m_t << "remark"; break;
460 case DocSimpleSect::Attention:
461 m_t << "attention"; break;
462 case DocSimpleSect::User:
464 case DocSimpleSect::Rcs:
466 case DocSimpleSect::Unknown: break;
471 void XmlDocVisitor::visitPost(DocSimpleSect *)
474 m_t << "</simplesect>\n";
477 void XmlDocVisitor::visitPre(DocTitle *)
483 void XmlDocVisitor::visitPost(DocTitle *)
489 void XmlDocVisitor::visitPre(DocSimpleList *)
492 m_t << "<itemizedlist>\n";
495 void XmlDocVisitor::visitPost(DocSimpleList *)
498 m_t << "</itemizedlist>\n";
501 void XmlDocVisitor::visitPre(DocSimpleListItem *)
507 void XmlDocVisitor::visitPost(DocSimpleListItem *)
510 m_t << "</listitem>\n";
513 void XmlDocVisitor::visitPre(DocSection *s)
516 m_t << "<sect" << s->level() << " id=\"" << s->file();
517 if (!s->anchor().isEmpty()) m_t << "_1" << s->anchor();
518 m_t << "\">" << endl;
520 filter(convertCharEntitiesToUTF8(s->title()));
521 m_t << "</title>" << endl;
524 void XmlDocVisitor::visitPost(DocSection *s)
526 m_t << "</sect" << s->level() << ">\n";
529 void XmlDocVisitor::visitPre(DocHtmlList *s)
532 if (s->type()==DocHtmlList::Ordered)
533 m_t << "<orderedlist>\n";
535 m_t << "<itemizedlist>\n";
538 void XmlDocVisitor::visitPost(DocHtmlList *s)
541 if (s->type()==DocHtmlList::Ordered)
542 m_t << "</orderedlist>\n";
544 m_t << "</itemizedlist>\n";
547 void XmlDocVisitor::visitPre(DocHtmlListItem *)
550 m_t << "<listitem>\n";
553 void XmlDocVisitor::visitPost(DocHtmlListItem *)
556 m_t << "</listitem>\n";
559 void XmlDocVisitor::visitPre(DocHtmlDescList *)
562 m_t << "<variablelist>\n";
565 void XmlDocVisitor::visitPost(DocHtmlDescList *)
568 m_t << "</variablelist>\n";
571 void XmlDocVisitor::visitPre(DocHtmlDescTitle *)
574 m_t << "<varlistentry><term>";
577 void XmlDocVisitor::visitPost(DocHtmlDescTitle *)
580 m_t << "</term></varlistentry>\n";
583 void XmlDocVisitor::visitPre(DocHtmlDescData *)
589 void XmlDocVisitor::visitPost(DocHtmlDescData *)
592 m_t << "</listitem>\n";
595 void XmlDocVisitor::visitPre(DocHtmlTable *t)
598 m_t << "<table rows=\"" << t->numRows()
599 << "\" cols=\"" << t->numColumns() << "\">" ;
602 void XmlDocVisitor::visitPost(DocHtmlTable *)
608 void XmlDocVisitor::visitPre(DocHtmlRow *)
614 void XmlDocVisitor::visitPost(DocHtmlRow *)
620 void XmlDocVisitor::visitPre(DocHtmlCell *c)
623 if (c->isHeading()) m_t << "<entry thead=\"yes\">"; else m_t << "<entry thead=\"no\">";
626 void XmlDocVisitor::visitPost(DocHtmlCell *)
632 void XmlDocVisitor::visitPre(DocHtmlCaption *)
638 void XmlDocVisitor::visitPost(DocHtmlCaption *)
641 m_t << "</caption>\n";
644 void XmlDocVisitor::visitPre(DocInternal *)
650 void XmlDocVisitor::visitPost(DocInternal *)
653 m_t << "</internal>" << endl;
656 void XmlDocVisitor::visitPre(DocHRef *href)
659 m_t << "<ulink url=\"";
664 void XmlDocVisitor::visitPost(DocHRef *)
670 void XmlDocVisitor::visitPre(DocHtmlHeader *header)
673 m_t << "<heading level=\"" << header->level() << "\">";
676 void XmlDocVisitor::visitPost(DocHtmlHeader *)
679 m_t << "</heading>\n";
682 void XmlDocVisitor::visitPre(DocImage *img)
685 m_t << "<image type=\"";
688 case DocImage::Html: m_t << "html"; break;
689 case DocImage::Latex: m_t << "latex"; break;
690 case DocImage::Rtf: m_t << "rtf"; break;
691 case DocImage::DocBook: m_t << "docbook"; break;
695 QCString baseName=img->name();
697 if ((i=baseName.findRev('/'))!=-1 || (i=baseName.findRev('\\'))!=-1)
699 baseName=baseName.right(baseName.length()-i-1);
701 m_t << " name=\"" << baseName << "\"";
702 if (!img->width().isEmpty())
705 filter(img->width());
708 else if (!img->height().isEmpty())
711 filter(img->height());
716 // copy the image to the output dir
717 QFile inImage(img->name());
718 QFile outImage(Config_getString("XML_OUTPUT")+"/"+baseName.data());
719 if (inImage.open(IO_ReadOnly))
721 if (outImage.open(IO_WriteOnly))
723 char *buffer = new char[inImage.size()];
724 inImage.readBlock(buffer,inImage.size());
725 outImage.writeBlock(buffer,inImage.size());
732 void XmlDocVisitor::visitPost(DocImage *)
735 m_t << "</image>" << endl;
738 void XmlDocVisitor::visitPre(DocDotFile *df)
741 m_t << "<dotfile name=\"" << df->file() << "\">";
744 void XmlDocVisitor::visitPost(DocDotFile *)
747 m_t << "</dotfile>" << endl;
750 void XmlDocVisitor::visitPre(DocMscFile *df)
753 m_t << "<mscfile name=\"" << df->file() << "\">";
756 void XmlDocVisitor::visitPost(DocMscFile *)
759 m_t << "</mscfile>" << endl;
762 void XmlDocVisitor::visitPre(DocDiaFile *df)
765 m_t << "<diafile name=\"" << df->file() << "\">";
768 void XmlDocVisitor::visitPost(DocDiaFile *)
771 m_t << "</diafile>" << endl;
774 void XmlDocVisitor::visitPre(DocLink *lnk)
777 startLink(lnk->ref(),lnk->file(),lnk->anchor());
780 void XmlDocVisitor::visitPost(DocLink *)
786 void XmlDocVisitor::visitPre(DocRef *ref)
789 if (!ref->file().isEmpty())
791 startLink(ref->ref(),ref->file(),ref->isSubPage() ? QCString() : ref->anchor());
793 if (!ref->hasLinkText()) filter(ref->targetTitle());
796 void XmlDocVisitor::visitPost(DocRef *ref)
799 if (!ref->file().isEmpty()) endLink();
803 void XmlDocVisitor::visitPre(DocSecRefItem *ref)
806 m_t << "<tocitem id=\"" << ref->file() << "_1" << ref->anchor() << "\">";
809 void XmlDocVisitor::visitPost(DocSecRefItem *)
812 m_t << "</tocitem>" << endl;
815 void XmlDocVisitor::visitPre(DocSecRefList *)
818 m_t << "<toclist>" << endl;
821 void XmlDocVisitor::visitPost(DocSecRefList *)
824 m_t << "</toclist>" << endl;
827 //void XmlDocVisitor::visitPre(DocLanguage *l)
829 // if (m_hide) return;
830 // m_t << "<language langid=\"" << l->id() << "\">";
833 //void XmlDocVisitor::visitPost(DocLanguage *)
835 // if (m_hide) return;
836 // m_t << "</language>" << endl;
839 void XmlDocVisitor::visitPre(DocParamSect *s)
842 m_t << "<parameterlist kind=\"";
845 case DocParamSect::Param:
846 m_t << "param"; break;
847 case DocParamSect::RetVal:
848 m_t << "retval"; break;
849 case DocParamSect::Exception:
850 m_t << "exception"; break;
851 case DocParamSect::TemplateParam:
852 m_t << "templateparam"; break;
859 void XmlDocVisitor::visitPost(DocParamSect *)
862 m_t << "</parameterlist>" << endl;
865 void XmlDocVisitor::visitPre(DocParamList *pl)
868 m_t << "<parameteritem>" << endl;
869 m_t << "<parameternamelist>" << endl;
870 //QStrListIterator li(pl->parameters());
872 QListIterator<DocNode> li(pl->parameters());
874 for (li.toFirst();(param=li.current());++li)
876 if (pl->paramTypes().count()>0)
878 QListIterator<DocNode> li(pl->paramTypes());
880 for (li.toFirst();(type=li.current());++li)
882 m_t << "<parametertype>";
883 if (type->kind()==DocNode::Kind_Word)
885 visit((DocWord*)type);
887 else if (type->kind()==DocNode::Kind_LinkedWord)
889 visit((DocLinkedWord*)type);
891 m_t << "</parametertype>" << endl;
894 m_t << "<parametername";
895 if (pl->direction()!=DocParamSect::Unspecified)
897 m_t << " direction=\"";
898 if (pl->direction()==DocParamSect::In)
902 else if (pl->direction()==DocParamSect::Out)
906 else if (pl->direction()==DocParamSect::InOut)
913 if (param->kind()==DocNode::Kind_Word)
915 visit((DocWord*)param);
917 else if (param->kind()==DocNode::Kind_LinkedWord)
919 visit((DocLinkedWord*)param);
921 m_t << "</parametername>" << endl;
923 m_t << "</parameternamelist>" << endl;
924 m_t << "<parameterdescription>" << endl;
927 void XmlDocVisitor::visitPost(DocParamList *)
930 m_t << "</parameterdescription>" << endl;
931 m_t << "</parameteritem>" << endl;
934 void XmlDocVisitor::visitPre(DocXRefItem *x)
937 if (x->title().isEmpty()) return;
938 m_t << "<xrefsect id=\"";
939 m_t << x->file() << "_1" << x->anchor();
941 m_t << "<xreftitle>";
943 m_t << "</xreftitle>";
944 m_t << "<xrefdescription>";
947 void XmlDocVisitor::visitPost(DocXRefItem *x)
950 if (x->title().isEmpty()) return;
951 m_t << "</xrefdescription>";
952 m_t << "</xrefsect>";
955 void XmlDocVisitor::visitPre(DocInternalRef *ref)
958 startLink(0,ref->file(),ref->anchor());
961 void XmlDocVisitor::visitPost(DocInternalRef *)
968 void XmlDocVisitor::visitPre(DocCopy *c)
971 m_t << "<copydoc link=\"" << convertToXML(c->link()) << "\">";
974 void XmlDocVisitor::visitPost(DocCopy *)
977 m_t << "</copydoc>" << endl;
980 void XmlDocVisitor::visitPre(DocText *)
984 void XmlDocVisitor::visitPost(DocText *)
988 void XmlDocVisitor::visitPre(DocHtmlBlockQuote *)
991 m_t << "<blockquote>";
994 void XmlDocVisitor::visitPost(DocHtmlBlockQuote *)
997 m_t << "</blockquote>";
1000 void XmlDocVisitor::visitPre(DocVhdlFlow *)
1004 void XmlDocVisitor::visitPost(DocVhdlFlow *)
1008 void XmlDocVisitor::visitPre(DocParBlock *)
1011 m_t << "<parblock>";
1014 void XmlDocVisitor::visitPost(DocParBlock *)
1017 m_t << "</parblock>";
1021 void XmlDocVisitor::filter(const char *str)
1023 m_t << convertToXML(str);
1026 void XmlDocVisitor::startLink(const QCString &ref,const QCString &file,const QCString &anchor)
1028 //printf("XmlDocVisitor: file=%s anchor=%s\n",file.data(),anchor.data());
1029 m_t << "<ref refid=\"" << file;
1030 if (!anchor.isEmpty()) m_t << "_1" << anchor;
1031 m_t << "\" kindref=\"";
1032 if (!anchor.isEmpty()) m_t << "member"; else m_t << "compound";
1034 if (!ref.isEmpty()) m_t << " external=\"" << ref << "\"";
1038 void XmlDocVisitor::endLink()
1043 void XmlDocVisitor::pushEnabled()
1045 m_enabled.push(new bool(m_hide));
1048 void XmlDocVisitor::popEnabled()
1050 bool *v=m_enabled.pop();