From 02a0c353a8947290a3191aead59db08dc84766ce Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Thu, 1 Jan 2015 21:04:54 +0100 Subject: Started with generating LaTeX output via the template engine --- src/classdef.cpp | 3 - src/config.l | 5 +- src/context.cpp | 638 +++++++++++++++++++++++++------ src/latexgen.cpp | 441 +++++++++++---------- src/latexgen.h | 88 ++++- src/template.cpp | 241 +++++++++--- src/template.h | 14 + src/util.cpp | 90 ++++- src/util.h | 8 +- templates/html/htmlbase.tpl | 4 +- templates/html/htmltypeconstraints.tpl | 2 +- templates/latex/doxygen.sty | 6 +- templates/latex/latexannotated.tpl | 9 + templates/latex/latexclass.tpl | 114 ++++++ templates/latex/latexfiles.tpl | 0 templates/latex/latexinclude.tpl | 32 ++ templates/latex/latexlayout.tpl | 35 ++ templates/latex/latexmakefile.tpl | 64 ++++ templates/latex/latexmodules.tpl | 0 templates/latex/latexnamespaces.tpl | 0 templates/latex/latexobjlink.tpl | 6 + templates/latex/latexrefman.tpl | 227 +++++++++++ templates/latex/latextypeconstraints.tpl | 12 + 23 files changed, 1629 insertions(+), 410 deletions(-) create mode 100644 templates/latex/latexannotated.tpl create mode 100644 templates/latex/latexclass.tpl create mode 100644 templates/latex/latexfiles.tpl create mode 100644 templates/latex/latexinclude.tpl create mode 100644 templates/latex/latexlayout.tpl create mode 100644 templates/latex/latexmakefile.tpl create mode 100644 templates/latex/latexmodules.tpl create mode 100644 templates/latex/latexnamespaces.tpl create mode 100644 templates/latex/latexobjlink.tpl create mode 100644 templates/latex/latexrefman.tpl create mode 100644 templates/latex/latextypeconstraints.tpl diff --git a/src/classdef.cpp b/src/classdef.cpp index 1584094..fa555ac 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -925,10 +925,7 @@ static void writeTemplateSpec(OutputList &ol,Definition *d, if (a) ol.docify(", "); } ol.docify(">"); - ol.pushGeneratorState(); - ol.disableAllBut(OutputGenerator::Html); ol.lineBreak(); - ol.popGeneratorState(); } ol.docify(type.lower()+" "+name); ol.endSubsubsection(); diff --git a/src/config.l b/src/config.l index b158e5c..63a5b30 100644 --- a/src/config.l +++ b/src/config.l @@ -1119,14 +1119,15 @@ void Config::check() QCString &paperType = Config_getEnum("PAPER_TYPE"); paperType=paperType.lower().stripWhiteSpace(); - if (paperType.isEmpty()) + if (paperType.isEmpty() || paperType=="a4wide") { paperType = "a4"; } - if (paperType!="a4" && paperType!="a4wide" && paperType!="letter" && + if (paperType!="a4" && paperType!="letter" && paperType!="legal" && paperType!="executive") { config_err("Unknown page type specified\n"); + paperType="a4"; } QCString &outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); diff --git a/src/context.cpp b/src/context.cpp index f7e6ae2..c4822e7 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -35,6 +35,8 @@ #include "docparser.h" #include "htmlgen.h" #include "htmldocvisitor.h" +#include "latexgen.h" +#include "latexdocvisitor.h" #include "dot.h" #include "diagram.h" #include "example.h" @@ -50,21 +52,23 @@ #define ADD_PROPERTY(name) addProperty(#name,this,&Private::name); +enum ContextOutputFormat +{ + ContextOutputFormat_Unspecified=0, + ContextOutputFormat_Html, + ContextOutputFormat_Latex, + ContextOutputFormat_Rtf, + ContextOutputFormat_ManPage, + ContextOutputFormat_DocBook, + ContextOutputFormat_Xml, + ContextOutputFormat_TagFile +}; + struct ContextGlobals { - enum OutputFormat - { - Html, - LateX, - Rtf, - ManPage, - DocBook, - Xml, - TagFile - }; - int dynSectionId; - QCString outputDir; - OutputFormat outputFormat; + int dynSectionId; + QCString outputDir; + ContextOutputFormat outputFormat; } g_globals; /** @brief Scoped smart pointer */ @@ -368,7 +372,7 @@ class DoxygenContext::Private : public PropertyMapper } TemplateVariant date() const { - return TemplateVariant(dateToString(TRUE)); + return dateToString(TRUE); } TemplateVariant maxJaxCodeFile() const { @@ -380,7 +384,7 @@ class DoxygenContext::Private : public PropertyMapper addProperty("version",this,&Private::version); //makeProperty(this,&Private::version)); //%% string date addProperty("date", this,&Private::date); - //%% string + //%% string maxJaxCodeFile addProperty("mathJaxCodeFile", this,&Private::maxJaxCodeFile); } private: @@ -593,6 +597,10 @@ class TranslateContext::Private : public PropertyMapper { return theTranslator->trCompoundIndex(); } + TemplateVariant namespaceIndex() const + { + return theTranslator->trNamespaceIndex(); + } TemplateVariant classHierarchy() const { return theTranslator->trClassHierarchy(); @@ -605,6 +613,10 @@ class TranslateContext::Private : public PropertyMapper { return theTranslator->trModules(); } + TemplateVariant moduleIndex() const + { + return theTranslator->trModuleIndex(); + } TemplateVariant namespaces() const { if (m_javaOpt || m_vhdlOpt) @@ -624,6 +636,10 @@ class TranslateContext::Private : public PropertyMapper { return theTranslator->trFile(TRUE,FALSE); } + TemplateVariant fileIndex() const + { + return theTranslator->trFileIndex(); + } TemplateVariant pages() const { return theTranslator->trRelatedPages(); @@ -662,6 +678,14 @@ class TranslateContext::Private : public PropertyMapper return theTranslator->trNamespaceMembers(); } } + TemplateVariant moduleDocumentation() const + { + return theTranslator->trModuleDocumentation(); + } + TemplateVariant fileDocumentation() const + { + return theTranslator->trFileDocumentation(); + } TemplateVariant fileList() const { return theTranslator->trFileList(); @@ -829,6 +853,10 @@ class TranslateContext::Private : public PropertyMapper { return theTranslator->trClassDocumentation(); } + TemplateVariant namespaceDocumentation() const + { + return theTranslator->trNamespaceDocumentation(); + } TemplateVariant compoundMembers() const { return theTranslator->trCompoundMembers(); @@ -916,10 +944,18 @@ class TranslateContext::Private : public PropertyMapper { return theTranslator->trEnumValue(); } + TemplateVariant referenceManual() const + { + return theTranslator->trReferenceManual(); + } + TemplateVariant index() const + { + return theTranslator->trRTFGeneralIndex(); + } Private() { //%% string generatedBy - addProperty("generatedby", this,&Private::generatedBy); + addProperty("generatedBy", this,&Private::generatedBy); //%% string generatedAt addProperty("generatedAt", this,&Private::generatedAt); //%% string search @@ -934,6 +970,8 @@ class TranslateContext::Private : public PropertyMapper addProperty("classListDescription", this,&Private::classListDescription); //%% string classIndex addProperty("classIndex", this,&Private::classIndex); + //%% string namespaceIndex + addProperty("namespaceIndex", this,&Private::namespaceIndex); //%% string classHierarchy addProperty("classHierarchy", this,&Private::classHierarchy); //%% string classMembers @@ -942,8 +980,12 @@ class TranslateContext::Private : public PropertyMapper addProperty("classMembersDescription",this,&Private::classMembersDescription); //%% string modules addProperty("modules", this,&Private::modules); + //%% string moduleIndex + addProperty("moduleIndex", this,&Private::moduleIndex); //%% string namespaces addProperty("namespaces", this,&Private::namespaces); + //%% string fileIndex + addProperty("fileIndex", this,&Private::fileIndex); //%% string files addProperty("files", this,&Private::files); //%% string pages @@ -1024,6 +1066,12 @@ class TranslateContext::Private : public PropertyMapper addProperty("constantgroups", this,&Private::constantgroups); //%% string classDocumentation addProperty("classDocumentation", this,&Private::classDocumentation); + //%% string namespaceDocumentation + addProperty("namespaceDocumentation", this,&Private::namespaceDocumentation); + //%% string moduleDocumentation + addProperty("moduleDocumentation",this,&Private::moduleDocumentation); + //%% string fileDocumentation + addProperty("fileDocumentation", this,&Private::fileDocumentation); //%% string compoundMembers addProperty("compoundMembers", this,&Private::compoundMembers); //%% string detailLevel @@ -1034,7 +1082,7 @@ class TranslateContext::Private : public PropertyMapper addProperty("namespaceListDescription",this,&Private::namespaceListDescription); //%% string directories addProperty("directories", this,&Private::directories); - //%% string moduleDescript + //%% string moduleDescription addProperty("modulesDescription", this,&Private::modulesDescription); //%% string all addProperty("all", this,&Private::all); @@ -1074,6 +1122,10 @@ class TranslateContext::Private : public PropertyMapper addProperty("enumValue", this,&Private::enumValue); //%% string enumName addProperty("enumName", this,&Private::enumName); + //%% string referenceManual + addProperty("referenceManual", this,&Private::referenceManual); + //%% string index + addProperty("index", this,&Private::index); m_javaOpt = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); m_fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN"); @@ -1109,10 +1161,27 @@ static TemplateVariant parseDoc(Definition *def,const QCString &file,int line, QGString docs; { FTextStream ts(&docs); - // TODO: support other generators - HtmlCodeGenerator codeGen(ts,relPath); - HtmlDocVisitor visitor(ts,codeGen,def); - root->accept(&visitor); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + HtmlCodeGenerator codeGen(ts,relPath); + HtmlDocVisitor visitor(ts,codeGen,def); + root->accept(&visitor); + } + break; + case ContextOutputFormat_Latex: + { + LatexCodeGenerator codeGen(ts,relPath,file); + LatexDocVisitor visitor(ts,codeGen,def->getDefFileExtension(),FALSE); + root->accept(&visitor); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } bool isEmpty = root->isEmpty(); if (isEmpty) @@ -1130,9 +1199,27 @@ static TemplateVariant parseCode(MemberDef *md,const QCString &scopeName,const Q pIntf->resetCodeParserState(); QGString s; FTextStream t(&s); - HtmlCodeGenerator codeGen(t,relPath); - pIntf->parseCode(codeGen,scopeName,code,md->getLanguage(),FALSE,0,md->getBodyDef(), - startLine,endLine,TRUE,md,showLineNumbers,md); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + HtmlCodeGenerator codeGen(t,relPath); + pIntf->parseCode(codeGen,scopeName,code,md->getLanguage(),FALSE,0,md->getBodyDef(), + startLine,endLine,TRUE,md,showLineNumbers,md); + } + break; + case ContextOutputFormat_Latex: + { + LatexCodeGenerator codeGen(t,relPath,md->docFile()); + pIntf->parseCode(codeGen,scopeName,code,md->getLanguage(),FALSE,0,md->getBodyDef(), + startLine,endLine,TRUE,md,showLineNumbers,md); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } return TemplateVariant(s.data(),TRUE); } @@ -1143,21 +1230,51 @@ static TemplateVariant parseCode(FileDef *fd,const QCString &relPath) pIntf->resetCodeParserState(); QGString s; FTextStream t(&s); - HtmlCodeGenerator codeGen(t,relPath); - pIntf->parseCode(codeGen,0, - fileToString(fd->absFilePath(),filterSourceFiles,TRUE), // the sources - fd->getLanguage(), // lang - FALSE, // isExampleBlock - 0, // exampleName - fd, // fileDef - -1, // startLine - -1, // endLine - FALSE, // inlineFragment - 0, // memberDef - TRUE, // showLineNumbers - 0, // searchCtx - TRUE // collectXRefs, TODO: should become FALSE - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + HtmlCodeGenerator codeGen(t,relPath); + pIntf->parseCode(codeGen,0, + fileToString(fd->absFilePath(),filterSourceFiles,TRUE), // the sources + fd->getLanguage(), // lang + FALSE, // isExampleBlock + 0, // exampleName + fd, // fileDef + -1, // startLine + -1, // endLine + FALSE, // inlineFragment + 0, // memberDef + TRUE, // showLineNumbers + 0, // searchCtx + TRUE // collectXRefs, TODO: should become FALSE + ); + } + break; + case ContextOutputFormat_Latex: + { + LatexCodeGenerator codeGen(t,relPath,fd->docFile()); + pIntf->parseCode(codeGen,0, + fileToString(fd->absFilePath(),filterSourceFiles,TRUE), // the sources + fd->getLanguage(), // lang + FALSE, // isExampleBlock + 0, // exampleName + fd, // fileDef + -1, // startLine + -1, // endLine + FALSE, // inlineFragment + 0, // memberDef + TRUE, // showLineNumbers + 0, // searchCtx + TRUE // collectXRefs, TODO: should become FALSE + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } return TemplateVariant(s.data(),TRUE); } @@ -1271,21 +1388,23 @@ class DefinitionContext : public PropertyMapper } TemplateVariant details() const { - if (!m_cache.details) + if (!m_cache.details || g_globals.outputFormat!=m_cache.detailsOutputFormat) { m_cache.details.reset(new TemplateVariant(parseDoc(m_def,m_def->docFile(),m_def->docLine(), relPathAsString(),m_def->documentation(),FALSE))); + m_cache.detailsOutputFormat = g_globals.outputFormat; } return *m_cache.details; } TemplateVariant brief() const { - if (!m_cache.brief) + if (!m_cache.brief || g_globals.outputFormat!=m_cache.briefOutputFormat) { if (m_def->hasBriefDescription()) { m_cache.brief.reset(new TemplateVariant(parseDoc(m_def,m_def->briefFile(),m_def->briefLine(), relPathAsString(),m_def->briefDescription(),TRUE))); + m_cache.briefOutputFormat = g_globals.outputFormat; } else { @@ -1296,12 +1415,13 @@ class DefinitionContext : public PropertyMapper } TemplateVariant inbodyDocs() const { - if (!m_cache.inbodyDocs) + if (!m_cache.inbodyDocs || g_globals.outputFormat!=m_cache.inbodyDocsOutputFormat) { if (!m_def->inbodyDocumentation().isEmpty()) { m_cache.inbodyDocs.reset(new TemplateVariant(parseDoc(m_def,m_def->inbodyFile(),m_def->inbodyLine(), relPathAsString(),m_def->inbodyDocumentation(),FALSE))); + m_cache.inbodyDocsOutputFormat = g_globals.outputFormat; } else { @@ -1387,8 +1507,11 @@ class DefinitionContext : public PropertyMapper { Cachable() { } ScopedPtr details; + ContextOutputFormat detailsOutputFormat; ScopedPtr brief; + ContextOutputFormat briefOutputFormat; ScopedPtr inbodyDocs; + ContextOutputFormat inbodyDocsOutputFormat; SharedPtr navPath; SharedPtr sourceDef; SharedPtr fileLink; @@ -1659,26 +1782,62 @@ class ClassContext::Private : public DefinitionContext { DotClassGraph *cg = getClassGraph(); FTextStream t(&result); - cg->writeGraph(t,GOF_BITMAP,EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_classDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(),TRUE,TRUE,g_globals.dynSectionId - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + cg->writeGraph(t,GOF_BITMAP,EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_classDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(),TRUE,TRUE,g_globals.dynSectionId + ); + } + break; + case ContextOutputFormat_Latex: + { + cg->writeGraph(t,GOF_EPS,EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_classDef->getOutputFileBase()+".tex", + relPathAsString(),TRUE,TRUE,g_globals.dynSectionId + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } else if (classDiagrams) { ClassDiagram d(m_classDef); FTextStream t(&result); - QCString name = convertToHtml(m_classDef->displayName()); - t << "
" << endl; - t << "getOutputFileBase(); - t << ".png\" usemap=\"#" << name << "_map\" alt=\"\"/>" << endl; - t << "" << endl; - d.writeImage(t,g_globals.outputDir, - relPathAsString(), - m_classDef->getOutputFileBase()); - t << "
"; + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + QCString name = convertToHtml(m_classDef->displayName()); + t << "
" << endl; + t << "getOutputFileBase(); + t << ".png\" usemap=\"#" << name << "_map\" alt=\"\"/>" << endl; + t << "" << endl; + d.writeImage(t,g_globals.outputDir, + relPathAsString(), + m_classDef->getOutputFileBase()); + t << "
"; + } + break; + case ContextOutputFormat_Latex: + { + d.writeFigure(t,g_globals.outputDir,m_classDef->getOutputFileBase()); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); @@ -1704,11 +1863,31 @@ class ClassContext::Private : public DefinitionContext { DotClassGraph *cg = getCollaborationGraph(); FTextStream t(&result); - cg->writeGraph(t,GOF_BITMAP,EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_classDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(),TRUE,TRUE,g_globals.dynSectionId - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + cg->writeGraph(t,GOF_BITMAP,EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_classDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(),TRUE,TRUE,g_globals.dynSectionId + ); + } + break; + case ContextOutputFormat_Latex: + { + cg->writeGraph(t,GOF_EPS,EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_classDef->getOutputFileBase()+".tex", + relPathAsString(),TRUE,TRUE,g_globals.dynSectionId + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); @@ -2002,15 +2181,15 @@ class ClassContext::Private : public DefinitionContext } TemplateVariant typeConstraints() const { - if (!m_cache.typeConstraints && m_classDef->typeConstraints()) + if (m_classDef->typeConstraints()) { - m_cache.typeConstraints.reset(ArgumentListContext::alloc(m_classDef->typeConstraints(),m_classDef,relPathAsString())); - } - else - { - m_cache.typeConstraints.reset(ArgumentListContext::alloc()); + if (!m_cache.typeConstraints && m_classDef->typeConstraints()) + { + m_cache.typeConstraints.reset(ArgumentListContext::alloc(m_classDef->typeConstraints(),m_classDef,relPathAsString())); + } + return m_cache.typeConstraints.get(); } - return m_cache.typeConstraints.get(); + return FALSE; } TemplateVariant examples() const { @@ -2578,11 +2757,31 @@ class FileContext::Private : public DefinitionContext { DotInclDepGraph *cg = getIncludeGraph(); FTextStream t(&result); - cg->writeGraph(t,GOF_BITMAP,EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_fileDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(),TRUE,g_globals.dynSectionId - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + cg->writeGraph(t,GOF_BITMAP,EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_fileDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + case ContextOutputFormat_Latex: + { + cg->writeGraph(t,GOF_EPS,EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_fileDef->getOutputFileBase()+".tex", + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); @@ -2609,11 +2808,31 @@ class FileContext::Private : public DefinitionContext { DotInclDepGraph *cg = getIncludedByGraph(); FTextStream t(&result); - cg->writeGraph(t,GOF_BITMAP,EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_fileDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(),TRUE,g_globals.dynSectionId - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + cg->writeGraph(t,GOF_BITMAP,EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_fileDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + case ContextOutputFormat_Latex: + { + cg->writeGraph(t,GOF_EPS,EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_fileDef->getOutputFileBase()+".tex", + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); @@ -3063,7 +3282,6 @@ class TextGeneratorHtml : public TextGeneratorIntf void writeString(const char *s,bool keepSpaces) const { if (s==0) return; - //printf("TextGeneratorOlImpl::writeString('%s',%d)\n",s,keepSpaces); if (keepSpaces) { const char *p=s; @@ -3123,6 +3341,54 @@ class TextGeneratorHtml : public TextGeneratorIntf QCString m_relPath; }; +//------------------------------------------------------------------------ + +class TextGeneratorLatex : public TextGeneratorIntf +{ + public: + TextGeneratorLatex(FTextStream &ts) : m_ts(ts) {} + void writeString(const char *s,bool keepSpaces) const + { + if (s==0) return; + m_ts << convertToLaTeX(s,FALSE,keepSpaces); + } + void writeBreak(int indent) const + { + m_ts << "\\\\*\n"; + for (int i=0;i DotCallGraph *cg = getCallGraph(); QGString result; FTextStream t(&result); - cg->writeGraph(t,GOF_BITMAP,EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_memberDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(),TRUE,g_globals.dynSectionId - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + cg->writeGraph(t,GOF_BITMAP,EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_memberDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + case ContextOutputFormat_Latex: + { + cg->writeGraph(t,GOF_EPS,EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_memberDef->getOutputFileBase()+".tex", + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); } @@ -4171,11 +4458,31 @@ class MemberContext::Private : public DefinitionContext DotCallGraph *cg = getCallerGraph(); QGString result; FTextStream t(&result); - cg->writeGraph(t,GOF_BITMAP,EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_memberDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(),TRUE,g_globals.dynSectionId - ); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + cg->writeGraph(t,GOF_BITMAP,EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_memberDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + case ContextOutputFormat_Latex: + { + cg->writeGraph(t,GOF_EPS,EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_memberDef->getOutputFileBase()+".tex", + relPathAsString(),TRUE,g_globals.dynSectionId + ); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); } @@ -4339,13 +4646,35 @@ class ModuleContext::Private : public DefinitionContext { DotGroupCollaboration *graph = getGroupGraph(); FTextStream t(&result); - graph->writeGraph(t,GOF_BITMAP, - EOF_Html, - g_globals.outputDir, - g_globals.outputDir+portable_pathSeparator()+m_groupDef->getOutputFileBase()+Doxygen::htmlFileExtension, - relPathAsString(), - TRUE, - g_globals.dynSectionId); + switch (g_globals.outputFormat) + { + case ContextOutputFormat_Html: + { + graph->writeGraph(t,GOF_BITMAP, + EOF_Html, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_groupDef->getOutputFileBase()+Doxygen::htmlFileExtension, + relPathAsString(), + TRUE, + g_globals.dynSectionId); + } + break; + case ContextOutputFormat_Latex: + { + graph->writeGraph(t,GOF_EPS, + EOF_LaTeX, + g_globals.outputDir, + g_globals.outputDir+portable_pathSeparator()+m_groupDef->getOutputFileBase()+".tex", + relPathAsString(), + TRUE, + g_globals.dynSectionId); + } + break; + // TODO: support other generators + default: + err("context.cpp: output format not yet supported"); + break; + } } g_globals.dynSectionId++; return TemplateVariant(result.data(),TRUE); @@ -8619,6 +8948,36 @@ class HtmlEscaper : public TemplateEscapeIntf { return convertToHtml(s,TRUE); } + void enableTabbing(bool) {} +}; + +//------------------------------------------------------------------------ + +class LatexSpaceless : public TemplateSpacelessIntf +{ + public: + LatexSpaceless() { reset(); } + void reset() { } + QCString remove(const QCString &s) + { + QGString result; + const char *p = s.data(); + char c; + while ((c=*p++)) + { + switch(c) + { + case '\t': case ' ': case '\n': + break; + default: + result+=c; + break; + } + } + result+='\0'; + return result.data(); + } + private: }; //------------------------------------------------------------------------ @@ -8698,6 +9057,22 @@ class HtmlSpaceless : public TemplateSpacelessIntf //------------------------------------------------------------------------ +class LatexEscaper : public TemplateEscapeIntf +{ + public: + LatexEscaper() : m_tabbing(FALSE) {} + QCString escape(const QCString &s) + { + return convertToLaTeX(s,m_tabbing); + } + void enableTabbing(bool b) { m_tabbing=b; } + private: + bool m_tabbing; +}; + + +//------------------------------------------------------------------------ + #if DEBUG_REF int RefCountedContext::s_totalCount; #endif @@ -8787,27 +9162,52 @@ void generateOutputViaTemplate() ctx->set("namespaceMembersIndex",namespaceMembersIndex.get()); //%% SearchIndicaes searchindicaes ctx->set("searchIndices",searchIndices.get()); + //%% string space + ctx->set("space"," "); + + if (Config_getBool("GENERATE_HTML")) + { // render HTML output + Template *tpl = e.loadByName("htmllayout.tpl",1); + if (tpl) + { + g_globals.outputFormat = ContextOutputFormat_Html; + g_globals.dynSectionId = 0; + g_globals.outputDir = Config_getString("HTML_OUTPUT"); + QDir dir(g_globals.outputDir); + createSubDirs(dir); + HtmlEscaper htmlEsc; + ctx->setEscapeIntf(Config_getString("HTML_FILE_EXTENSION"),&htmlEsc); + HtmlSpaceless spl; + ctx->setSpacelessIntf(&spl); + ctx->setOutputDirectory(g_globals.outputDir); + FTextStream ts; + tpl->render(ts,ctx); + e.unload(tpl); + } + } + + // TODO: clean index before each run... - // render HTML output - Template *tpl = e.loadByName("htmllayout.tpl",1); - if (tpl) - { - g_globals.outputFormat = ContextGlobals::Html; - g_globals.dynSectionId = 0; - g_globals.outputDir = Config_getString("HTML_OUTPUT"); - QDir dir(g_globals.outputDir); - createSubDirs(dir); - HtmlEscaper htmlEsc; - ctx->setEscapeIntf(Config_getString("HTML_FILE_EXTENSION"),&htmlEsc); - HtmlSpaceless spl; - ctx->setSpacelessIntf(&spl); - ctx->setOutputDirectory(g_globals.outputDir); - FTextStream ts; - tpl->render(ts,ctx); - e.unload(tpl); - } - - // TODO: render other outputs + if (Config_getBool("GENERATE_LATEX")) + { // render LaTeX output + Template *tpl = e.loadByName("latexlayout.tpl",1); + if (tpl) + { + g_globals.outputFormat = ContextOutputFormat_Latex; + g_globals.dynSectionId = 0; + g_globals.outputDir = Config_getString("LATEX_OUTPUT"); + QDir dir(g_globals.outputDir); + createSubDirs(dir); + LatexEscaper latexEsc; + ctx->setEscapeIntf(".tex",&latexEsc); + LatexSpaceless spl; + ctx->setSpacelessIntf(&spl); + ctx->setOutputDirectory(g_globals.outputDir); + FTextStream ts; + tpl->render(ts,ctx); + e.unload(tpl); + } + } e.destroyContext(ctx); } diff --git a/src/latexgen.cpp b/src/latexgen.cpp index 2ed30e9..c524d2e 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -38,11 +38,214 @@ #include "filename.h" #include "resourcemgr.h" +//------------------------------- + +LatexCodeGenerator::LatexCodeGenerator(FTextStream &t,const QCString &relPath,const QCString &sourceFileName) + : m_relPath(relPath), m_sourceFileName(sourceFileName), m_col(0) +{ + m_prettyCode=Config_getBool("LATEX_SOURCE_CODE"); + setTextStream(t); +} + +LatexCodeGenerator::LatexCodeGenerator() : m_col(0) +{ + m_prettyCode=Config_getBool("LATEX_SOURCE_CODE"); +} + +void LatexCodeGenerator::setTextStream(FTextStream &t) +{ + m_streamSet = t.device()!=0; + m_t.setDevice(t.device()); +} + +void LatexCodeGenerator::setRelativePath(const QCString &path) +{ + m_relPath = path; +} + +void LatexCodeGenerator::setSourceFileName(const QCString &name) +{ + m_sourceFileName = name; +} + +void LatexCodeGenerator::codify(const char *str) +{ + if (str) + { + const char *p=str; + char c; + //char cs[5]; + int spacesToNextTabStop; + static int tabSize = Config_getInt("TAB_SIZE"); + const int maxLineLen = 108; + QCString result(4*maxLineLen+1); // worst case for 1 line of 4-byte chars + int i; + while ((c=*p)) + { + switch(c) + { + case 0x0c: p++; // remove ^L + break; + case '\t': spacesToNextTabStop = + tabSize - (m_col%tabSize); + m_t << Doxygen::spaces.left(spacesToNextTabStop); + m_col+=spacesToNextTabStop; + p++; + break; + case '\n': m_t << '\n'; m_col=0; p++; + break; + default: + i=0; + +#undef COPYCHAR +// helper macro to copy a single utf8 character, dealing with multibyte chars. +#define COPYCHAR() do { \ + result[i++]=c; p++; \ + if (c<0) /* multibyte utf-8 character */ \ + { \ + /* 1xxx.xxxx: >=2 byte character */ \ + result[i++]=*p++; \ + if (((uchar)c&0xE0)==0xE0) \ + { \ + /* 111x.xxxx: >=3 byte character */ \ + result[i++]=*p++; \ + } \ + if (((uchar)c&0xF0)==0xF0) \ + { \ + /* 1111.xxxx: 4 byte character */ \ + result[i++]=*p++; \ + } \ + } \ + m_col++; \ + } while(0) + + // gather characters until we find whitespace or are at + // the end of a line + COPYCHAR(); + if (m_col>=maxLineLen) // force line break + { + m_t << "\n "; + m_col=0; + } + else // copy more characters + { + while (m_col=maxLineLen) // force line break + { + m_t << "\n "; + m_col=0; + } + } + result[i]=0; // add terminator + //if (m_prettyCode) + //{ + filterLatexString(m_t,result,FALSE,TRUE); + //} + //else + //{ + // t << result; + //} + break; + } + } + } +} + + +void LatexCodeGenerator::writeCodeLink(const char *ref,const char *f, + const char *anchor,const char *name, + const char *) +{ + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + int l = qstrlen(name); + if (m_col+l>80) + { + m_t << "\n "; + m_col=0; + } + if (!ref && usePDFLatex && pdfHyperlinks) + { + m_t << "\\hyperlink{"; + if (f) m_t << stripPath(f); + if (f && anchor) m_t << "_"; + if (anchor) m_t << anchor; + m_t << "}{"; + codify(name); + m_t << "}"; + } + else + { + m_t << name; + } + m_col+=l; +} + +void LatexCodeGenerator::writeLineNumber(const char *ref,const char *fileName,const char *anchor,int l) +{ + static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + if (m_prettyCode) + { + QCString lineNumber; + lineNumber.sprintf("%05d",l); + + if (fileName && !m_sourceFileName.isEmpty()) + { + QCString lineAnchor; + lineAnchor.sprintf("_l%05d",l); + lineAnchor.prepend(m_sourceFileName); + //if (!m_prettyCode) return; + if (usePDFLatex && pdfHyperlinks) + { + m_t << "\\hypertarget{" << stripPath(lineAnchor) << "}{}"; + } + writeCodeLink(ref,fileName,anchor,lineNumber,0); + } + else + { + codify(lineNumber); + } + m_t << " "; + } + else + { + m_t << l << " "; + } +} + + +void LatexCodeGenerator::startCodeLine(bool) +{ + m_col=0; +} + +void LatexCodeGenerator::endCodeLine() +{ + codify("\n"); +} + +void LatexCodeGenerator::startFontClass(const char *name) +{ + m_t << "\\textcolor{" << name << "}{"; +} + +void LatexCodeGenerator::endFontClass() +{ + m_t << "}"; +} + + +//------------------------------- LatexGenerator::LatexGenerator() : OutputGenerator() { dir=Config_getString("LATEX_OUTPUT"); - col=0; //printf("LatexGenerator::LatexGenerator() insideTabbing=FALSE\n"); insideTabbing=FALSE; firstDescItem=TRUE; @@ -332,13 +535,8 @@ static void writeDefaultHeaderPart1(FTextStream &t) "\n"; // Define page & text layout - QCString paperName; - QCString &paperType=Config_getEnum("PAPER_TYPE"); + QCString paperName=Config_getEnum("PAPER_TYPE"); // "a4wide" package is obsolete (see bug 563698) - if (paperType=="a4wide") - paperName="a4"; - else - paperName=paperType; t << "% Page & text layout\n" "\\usepackage{geometry}\n" "\\geometry{%\n" @@ -593,7 +791,7 @@ void LatexGenerator::startFile(const char *name,const char *,const char *) #endif QCString fileName=name; relPath = relativePathToRoot(fileName); - sourceFileName = stripPath(fileName); + m_codeGen.setSourceFileName(stripPath(fileName)); if (fileName.right(4)!=".tex" && fileName.right(4)!=".sty") fileName+=".tex"; startPlainFile(fileName); } @@ -601,7 +799,7 @@ void LatexGenerator::startFile(const char *name,const char *,const char *) void LatexGenerator::endFile() { endPlainFile(); - sourceFileName.resize(0); + m_codeGen.setSourceFileName(""); } //void LatexGenerator::writeIndex() @@ -614,14 +812,6 @@ void LatexGenerator::startProjectNumber() t << "\\\\[1ex]\\large "; } -static QCString convertToLaTeX(const QCString &s) -{ - QGString result; - FTextStream t(&result); - filterLatexString(t,s,FALSE,FALSE,FALSE); - return result.data(); -} - void LatexGenerator::startIndexSection(IndexSections is) { bool &compactLatex = Config_getBool("COMPACT_LATEX"); @@ -1204,7 +1394,8 @@ void LatexGenerator::endTextLink() void LatexGenerator::writeObjectLink(const char *ref, const char *f, const char *anchor, const char *text) { - if (!disableLinks && !ref && Config_getBool("PDF_HYPERLINKS")) + static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); + if (!disableLinks && !ref && pdfHyperlinks) { t << "\\hyperlink{"; if (f) t << stripPath(f); @@ -1235,34 +1426,6 @@ void LatexGenerator::endPageRef(const char *clname, const char *anchor) t << "}"; } -void LatexGenerator::writeCodeLink(const char *ref,const char *f, - const char *anchor,const char *name, - const char *) -{ - static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); - static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); - int l = qstrlen(name); - if (col+l>80) - { - t << "\n "; - col=0; - } - if (/*m_prettyCode &&*/ !disableLinks && !ref && usePDFLatex && pdfHyperlinks) - { - t << "\\hyperlink{"; - if (f) t << stripPath(f); - if (f && anchor) t << "_"; - if (anchor) t << anchor; - t << "}{"; - codify(name); - t << "}"; - } - else - { - t << name; - } - col+=l; -} void LatexGenerator::startTitleHead(const char *fileName) { @@ -1288,9 +1451,9 @@ void LatexGenerator::endTitleHead(const char *fileName,const char *name) if (name) { t << "\\label{" << stripPath(fileName) << "}\\index{"; - escapeLabelName(name); + t << latexEscapeLabelName(name,insideTabbing); t << "@{"; - escapeMakeIndexChars(name); + t << latexEscapeIndexChars(name,insideTabbing); t << "}}" << endl; } } @@ -1369,27 +1532,27 @@ void LatexGenerator::startMemberDoc(const char *clname, t << "\\index{"; if (clname) { - escapeLabelName(clname); + t << latexEscapeLabelName(clname,insideTabbing); t << "@{"; - escapeMakeIndexChars(clname); + t << latexEscapeIndexChars(clname,insideTabbing); t << "}!"; } - escapeLabelName(memname); + t << latexEscapeLabelName(memname,insideTabbing); t << "@{"; - escapeMakeIndexChars(memname); + t << latexEscapeIndexChars(memname,insideTabbing); t << "}}" << endl; t << "\\index{"; - escapeLabelName(memname); + t << latexEscapeLabelName(memname,insideTabbing); t << "@{"; - escapeMakeIndexChars(memname); + t << latexEscapeIndexChars(memname,insideTabbing); t << "}"; if (clname) { t << "!"; - escapeLabelName(clname); + t << latexEscapeLabelName(clname,insideTabbing); t << "@{"; - escapeMakeIndexChars(clname); + t << latexEscapeIndexChars(clname,insideTabbing); t << "}"; } t << "}" << endl; @@ -1401,21 +1564,15 @@ void LatexGenerator::startMemberDoc(const char *clname, if (compactLatex) level++; t << "\\" << levelLab[level]; - //if (Config_getBool("PDF_HYPERLINKS") && memname) - //{ - // t << "["; - // escapeMakeIndexChars(this,t,memname); - // t << "]"; - //} t << "[{"; - escapeMakeIndexChars(title); + t << latexEscapeIndexChars(title,insideTabbing); t << "}]"; t << "{\\setlength{\\rightskip}{0pt plus 5cm}"; disableLinks=TRUE; } -void LatexGenerator::endMemberDoc(bool) -{ +void LatexGenerator::endMemberDoc(bool) +{ disableLinks=FALSE; t << "}"; //if (Config_getBool("COMPACT_LATEX")) t << "\\hfill"; @@ -1474,16 +1631,16 @@ void LatexGenerator::addIndexItem(const char *s1,const char *s2) if (s1) { t << "\\index{"; - escapeLabelName(s1); + t << latexEscapeLabelName(s1,insideTabbing); t << "@{"; - escapeMakeIndexChars(s1); + t << latexEscapeIndexChars(s1,insideTabbing); t << "}"; if (s2) { t << "!"; - escapeLabelName(s2); + t << latexEscapeLabelName(s2,insideTabbing); t << "@{"; - escapeMakeIndexChars(s2); + t << latexEscapeIndexChars(s2,insideTabbing); t << "}"; } t << "}"; @@ -1539,94 +1696,6 @@ void LatexGenerator::docify(const char *str) filterLatexString(t,str,insideTabbing,FALSE,FALSE); } -void LatexGenerator::codify(const char *str) -{ - if (str) - { - const char *p=str; - char c; - //char cs[5]; - int spacesToNextTabStop; - static int tabSize = Config_getInt("TAB_SIZE"); - const int maxLineLen = 108; - QCString result(4*maxLineLen+1); // worst case for 1 line of 4-byte chars - int i; - while ((c=*p)) - { - switch(c) - { - case 0x0c: p++; // remove ^L - break; - case '\t': spacesToNextTabStop = - tabSize - (col%tabSize); - t << Doxygen::spaces.left(spacesToNextTabStop); - col+=spacesToNextTabStop; - p++; - break; - case '\n': t << '\n'; col=0; p++; - break; - default: - i=0; - -#undef COPYCHAR -// helper macro to copy a single utf8 character, dealing with multibyte chars. -#define COPYCHAR() do { \ - result[i++]=c; p++; \ - if (c<0) /* multibyte utf-8 character */ \ - { \ - /* 1xxx.xxxx: >=2 byte character */ \ - result[i++]=*p++; \ - if (((uchar)c&0xE0)==0xE0) \ - { \ - /* 111x.xxxx: >=3 byte character */ \ - result[i++]=*p++; \ - } \ - if (((uchar)c&0xF0)==0xF0) \ - { \ - /* 1111.xxxx: 4 byte character */ \ - result[i++]=*p++; \ - } \ - } \ - col++; \ - } while(0) - - // gather characters until we find whitespace or are at - // the end of a line - COPYCHAR(); - if (col>=maxLineLen) // force line break - { - t << "\n "; - col=0; - } - else // copy more characters - { - while (col=maxLineLen) // force line break - { - t << "\n "; - col=0; - } - } - result[i]=0; // add terminator - //if (m_prettyCode) - //{ - filterLatexString(t,result,insideTabbing,TRUE); - //} - //else - //{ - // t << result; - //} - break; - } - } - } -} - void LatexGenerator::writeChar(char c) { char cs[2]; @@ -2009,6 +2078,7 @@ void LatexGenerator::endConstraintList() t << "\\end{Desc}" << endl; } +#if 0 void LatexGenerator::escapeLabelName(const char *s) { if (s==0) return; @@ -2078,6 +2148,7 @@ void LatexGenerator::escapeMakeIndexChars(const char *s) } } } +#endif void LatexGenerator::startCodeFragment() { @@ -2089,61 +2160,6 @@ void LatexGenerator::endCodeFragment() t << "\\end{DoxyCode}\n"; } -void LatexGenerator::writeLineNumber(const char *ref,const char *fileName,const char *anchor,int l) -{ - static bool usePDFLatex = Config_getBool("USE_PDFLATEX"); - static bool pdfHyperlinks = Config_getBool("PDF_HYPERLINKS"); - if (m_prettyCode) - { - QCString lineNumber; - lineNumber.sprintf("%05d",l); - - if (fileName && !sourceFileName.isEmpty()) - { - QCString lineAnchor; - lineAnchor.sprintf("_l%05d",l); - lineAnchor.prepend(sourceFileName); - //if (!m_prettyCode) return; - if (usePDFLatex && pdfHyperlinks) - { - t << "\\hypertarget{" << stripPath(lineAnchor) << "}{}"; - } - writeCodeLink(ref,fileName,anchor,lineNumber,0); - } - else - { - codify(lineNumber); - } - t << " "; - } - else - { - t << l << " "; - } -} - -void LatexGenerator::startCodeLine(bool) -{ - col=0; -} - -void LatexGenerator::endCodeLine() -{ - codify("\n"); -} - -void LatexGenerator::startFontClass(const char *name) -{ - //if (!m_prettyCode) return; - t << "\\textcolor{" << name << "}{"; -} - -void LatexGenerator::endFontClass() -{ - //if (!m_prettyCode) return; - t << "}"; -} - void LatexGenerator::startInlineHeader() { if (Config_getBool("COMPACT_LATEX")) @@ -2227,3 +2243,4 @@ void LatexGenerator::endLabels() { } + diff --git a/src/latexgen.h b/src/latexgen.h index ee67803..84382a7 100644 --- a/src/latexgen.h +++ b/src/latexgen.h @@ -24,6 +24,48 @@ class QFile; static const char *latexStyleExtension = ".sty"; +class LatexCodeGenerator : public CodeOutputInterface +{ + public: + LatexCodeGenerator(FTextStream &t,const QCString &relPath,const QCString &sourceFile); + LatexCodeGenerator(); + void setTextStream(FTextStream &t); + void setRelativePath(const QCString &path); + void setSourceFileName(const QCString &sourceFileName); + void codify(const char *text); + void writeCodeLink(const char *ref,const char *file, + const char *anchor,const char *name, + const char *tooltip); + void writeTooltip(const char *, + const DocLinkInfo &, + const char *, + const char *, + const SourceLinkInfo &, + const SourceLinkInfo & + ) {} + void writeLineNumber(const char *,const char *,const char *,int); + void startCodeLine(bool); + void endCodeLine(); + void startFontClass(const char *); + void endFontClass(); + void writeCodeAnchor(const char *) {} + void setCurrentDoc(Definition *,const char *,bool) {} + void addWord(const char *,bool) {} + + private: + void _writeCodeLink(const char *className, + const char *ref,const char *file, + const char *anchor,const char *name, + const char *tooltip); + void docify(const char *str); + bool m_streamSet; + FTextStream m_t; + QCString m_relPath; + QCString m_sourceFileName; + int m_col; + bool m_prettyCode; +}; + /** Generator for LaTeX output. */ class LatexGenerator : public OutputGenerator { @@ -47,6 +89,32 @@ class LatexGenerator : public OutputGenerator bool isEnabled(OutputType o) { return (o==Latex && active); } OutputGenerator *get(OutputType o) { return (o==Latex) ? this : 0; } + // --- CodeOutputInterface + void codify(const char *text) + { m_codeGen.codify(text); } + void writeCodeLink(const char *ref, const char *file, + const char *anchor,const char *name, + const char *tooltip) + { m_codeGen.writeCodeLink(ref,file,anchor,name,tooltip); } + void writeLineNumber(const char *ref,const char *file,const char *anchor,int lineNumber) + { m_codeGen.writeLineNumber(ref,file,anchor,lineNumber); } + void writeTooltip(const char *id, const DocLinkInfo &docInfo, const char *decl, + const char *desc, const SourceLinkInfo &defInfo, const SourceLinkInfo &declInfo + ) + { m_codeGen.writeTooltip(id,docInfo,decl,desc,defInfo,declInfo); } + void startCodeLine(bool hasLineNumbers) + { m_codeGen.startCodeLine(hasLineNumbers); } + void endCodeLine() + { m_codeGen.endCodeLine(); } + void startFontClass(const char *s) + { m_codeGen.startFontClass(s); } + void endFontClass() + { m_codeGen.endFontClass(); } + void writeCodeAnchor(const char *anchor) + { m_codeGen.writeCodeAnchor(anchor); } + // --------------------------- + + void writeDoc(DocNode *,Definition *ctx,MemberDef *); void startFile(const char *name,const char *manName,const char *title); @@ -83,15 +151,9 @@ class LatexGenerator : public OutputGenerator void startIndexItem(const char *ref,const char *file); void endIndexItem(const char *ref,const char *file); void docify(const char *text); - void codify(const char *text); void writeObjectLink(const char *ref,const char *file, const char *anchor,const char *name); - void writeCodeLink(const char *ref, const char *file, - const char *anchor,const char *name, - const char *tooltip); - void writeTooltip(const char *, const DocLinkInfo &, const char *, - const char *, const SourceLinkInfo &, const SourceLinkInfo & - ) {} + void startTextLink(const char *,const char *); void endTextLink(); void startHtmlLink(const char *url); @@ -137,9 +199,6 @@ class LatexGenerator : public OutputGenerator void writeAnchor(const char *fileName,const char *name); void startCodeFragment(); void endCodeFragment(); - void writeLineNumber(const char *,const char *,const char *,int l); - void startCodeLine(bool hasLineNumbers); - void endCodeLine(); void startEmphasis() { t << "{\\em "; } void endEmphasis() { t << "}"; } void startBold() { t << "{\\bfseries "; } @@ -267,10 +326,6 @@ class LatexGenerator : public OutputGenerator void writeLabel(const char *l,bool isLast); void endLabels(); - void startFontClass(const char *); // {} - void endFontClass(); // {} - - void writeCodeAnchor(const char *) {} void setCurrentDoc(Definition *,const char *,bool) {} void addWord(const char *,bool) {} @@ -278,17 +333,14 @@ class LatexGenerator : public OutputGenerator private: LatexGenerator(const LatexGenerator &); LatexGenerator &operator=(const LatexGenerator &); - void escapeLabelName(const char *s); - void escapeMakeIndexChars(const char *s); - int col; bool insideTabbing; bool firstDescItem; bool disableLinks; QCString relPath; - QCString sourceFileName; int m_indent; bool templateMemberItem; bool m_prettyCode; + LatexCodeGenerator m_codeGen; }; #endif diff --git a/src/template.cpp b/src/template.cpp index e81ed17..f75d13e 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -101,10 +101,11 @@ static QValueList split(const QCString &str,const QCString &sep, /** Strips spaces surrounding `=` from string \a in, so * `foo = 10 bar=5 baz= 'hello'` will become `foo=10 bar=5 baz='hello'` */ -static void removeSpacesAroundEquals(QCString &in) +static QCString removeSpacesAroundEquals(const char *s) { - const char *p=in.data(); - char *q = in.data(); + QCString result(s); + const char *p=result.data(); + char *q = result.rawData(); char c; while ((c=*p++)) { @@ -121,7 +122,8 @@ static void removeSpacesAroundEquals(QCString &in) } *q++=c; } - if (qenableTabbing(b); + } + bool tabbingEnabled() const { return m_tabbingEnabled; } void warn(const char *fileName,int line,const char *fmt,...) const; // index related functions @@ -745,6 +751,7 @@ class TemplateContextImpl : public TemplateContext TemplateEscapeIntf *m_activeEscapeIntf; TemplateSpacelessIntf *m_spacelessIntf; bool m_spacelessEnabled; + bool m_tabbingEnabled; TemplateAutoRef m_indices; QDict< QStack > m_indexStacks; }; @@ -811,6 +818,62 @@ class FilterGet } }; +//----------------------------------------------------------------------------- + +/** @brief The implementation of the "raw" filter */ +class FilterRaw +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid() && (v.type()==TemplateVariant::String || v.type()==TemplateVariant::Integer)) + { + return TemplateVariant(v.toString(),TRUE); + } + else + { + return v; + } + } +}; + +//----------------------------------------------------------------------------- + +/** @brief The implementation of the "texlabel" filter */ +class FilterTexLabel +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid() && (v.type()==TemplateVariant::String)) + { + return TemplateVariant(latexEscapeLabelName(v.toString(),FALSE),TRUE); + } + else + { + return v; + } + } +}; + +//----------------------------------------------------------------------------- + +/** @brief The implementation of the "texindex" filter */ +class FilterTexIndex +{ + public: + static TemplateVariant apply(const TemplateVariant &v,const TemplateVariant &) + { + if (v.isValid() && (v.type()==TemplateVariant::String)) + { + return TemplateVariant(latexEscapeIndexChars(v.toString(),FALSE),TRUE); + } + else + { + return v; + } + } +}; //----------------------------------------------------------------------------- @@ -1428,6 +1491,7 @@ class TemplateFilterFactory // register a handlers for each filter we support static TemplateFilterFactory::AutoRegister fAdd("add"); static TemplateFilterFactory::AutoRegister fGet("get"); +static TemplateFilterFactory::AutoRegister fRaw("raw"); static TemplateFilterFactory::AutoRegister fAppend("append"); static TemplateFilterFactory::AutoRegister fLength("length"); static TemplateFilterFactory::AutoRegister fNoWrap("nowrap"); @@ -1437,6 +1501,8 @@ static TemplateFilterFactory::AutoRegister fPrepend("prepend" static TemplateFilterFactory::AutoRegister fGroupBy("groupBy"); static TemplateFilterFactory::AutoRegister fRelative("relative"); static TemplateFilterFactory::AutoRegister fListSort("listsort"); +static TemplateFilterFactory::AutoRegister fTexLabel("texLabel"); +static TemplateFilterFactory::AutoRegister fTexIndex("texIndex"); static TemplateFilterFactory::AutoRegister fPaginate("paginate"); static TemplateFilterFactory::AutoRegister fStripPath("stripPath"); static TemplateFilterFactory::AutoRegister fAlphaIndex("alphaIndex"); @@ -2344,7 +2410,8 @@ class TemplateNodeList : public QList class TemplateImpl : public TemplateNode, public Template { public: - TemplateImpl(TemplateEngine *e,const QCString &name,const char *data,int size); + TemplateImpl(TemplateEngine *e,const QCString &name,const char *data,int size, + const QCString &extension); void render(FTextStream &ts, TemplateContext *c); TemplateEngine *engine() const { return m_engine; } @@ -2698,7 +2765,6 @@ class TemplateNodeVariable : public TemplateNode { v = v.call(QValueList()); } - //printf("TemplateNodeVariable::render(%s) raw=%d\n",value.data(),v.raw()); if (ci->escapeIntf() && !v.raw()) { ts << ci->escapeIntf()->escape(v.toString()); @@ -3519,6 +3585,24 @@ class TemplateNodeInclude : public TemplateNodeCreator //---------------------------------------------------------- +static void stripLeadingWhiteSpace(QGString &s) +{ + const char *src = s.data(); + if (src) + { + char *dst = s.data(); + char c; + bool skipSpaces=TRUE; + while ((c=*src++)) + { + if (c=='\n') { *dst++=c; skipSpaces=TRUE; } + else if (c==' ' && skipSpaces) {} + else { *dst++=c; skipSpaces=FALSE; } + } + *dst='\0'; + } +} + /** @brief Class representing an 'create' tag in a template */ class TemplateNodeCreate : public TemplateNodeCreator { @@ -3582,17 +3666,18 @@ class TemplateNodeCreate : public TemplateNodeCreator TemplateImpl *t = getTemplate(); if (t) { + QCString extension=outputFile; + int i=extension.findRev('.'); + if (i!=-1) + { + extension=extension.right(extension.length()-i-1); + } + t->engine()->setOutputExtension(extension); Template *ct = t->engine()->loadByName(templateFile,m_line); TemplateImpl *createTemplate = ct ? dynamic_cast(ct) : 0; if (createTemplate) { mkpath(ci,outputFile); - QCString extension=outputFile; - int i=extension.findRev('.'); - if (i!=-1) - { - extension=extension.right(extension.length()-i-1); - } if (!ci->outputDirectory().isEmpty()) { outputFile.prepend(ci->outputDirectory()+"/"); @@ -3604,7 +3689,11 @@ class TemplateNodeCreate : public TemplateNodeCreator TemplateEscapeIntf *escIntf = ci->escapeIntf(); ci->selectEscapeIntf(extension); FTextStream ts(&f); - createTemplate->render(ts,c); + QGString out; + FTextStream os(&out); + createTemplate->render(os,c); + stripLeadingWhiteSpace(out); + ts << out; t->engine()->unload(t); ci->setActiveEscapeIntf(escIntf); } @@ -3617,6 +3706,7 @@ class TemplateNodeCreate : public TemplateNodeCreator { ci->warn(m_templateName,m_line,"failed to load template '%s' for include",templateFile.data()); } + t->engine()->setOutputExtension(""); } } } @@ -3905,8 +3995,7 @@ class TemplateNodeWith : public TemplateNodeCreator TRACE(("{TemplateNodeWith(%s)\n",data.data())); m_args.setAutoDelete(TRUE); ExpressionParser expParser(parser,line); - QCString filteredData = data; - removeSpacesAroundEquals(filteredData); + QCString filteredData = removeSpacesAroundEquals(data); QValueList args = split(filteredData," "); QValueListIterator it = args.begin(); while (it!=args.end()) @@ -3959,7 +4048,7 @@ class TemplateNodeWith : public TemplateNodeCreator //---------------------------------------------------------- -/** @brief Class representing an 'set' tag in a template */ +/** @brief Class representing an 'cycle' tag in a template */ class TemplateNodeCycle : public TemplateNodeCreator { public: @@ -4194,6 +4283,36 @@ class TemplateNodeMarkers : public TemplateNodeCreator //---------------------------------------------------------- +/** @brief Class representing an 'tabbing' tag in a template */ +class TemplateNodeTabbing : public TemplateNodeCreator +{ + public: + TemplateNodeTabbing(TemplateParser *parser,TemplateNode *parent,int line,const QCString &) + : TemplateNodeCreator(parser,parent,line) + { + TRACE(("{TemplateNodeTabbing()\n")); + QStrList stopAt; + stopAt.append("endtabbing"); + parser->parse(this,line,stopAt,m_nodes); + parser->removeNextToken(); // skip over endtabbing + TRACE(("}TemplateNodeTabbing()\n")); + } + void render(FTextStream &ts, TemplateContext *c) + { + TemplateContextImpl *ci = dynamic_cast(c); + if (ci==0) return; // should not happen + ci->setLocation(m_templateName,m_line); + bool wasTabbing = ci->tabbingEnabled(); + ci->enableTabbing(TRUE); + m_nodes.render(ts,c); + ci->enableTabbing(wasTabbing); + } + private: + TemplateNodeList m_nodes; +}; + +//---------------------------------------------------------- + /** @brief Class representing an 'markers' tag in a template */ class TemplateNodeResource : public TemplateNodeCreator { @@ -4329,6 +4448,7 @@ static TemplateNodeFactory::AutoRegister autoRefCreat static TemplateNodeFactory::AutoRegister autoRefRepeat("repeat"); static TemplateNodeFactory::AutoRegister autoRefInclude("include"); static TemplateNodeFactory::AutoRegister autoRefMarkers("markers"); +static TemplateNodeFactory::AutoRegister autoRefTabbing("tabbing"); static TemplateNodeFactory::AutoRegister autoRefResource("resource"); static TemplateNodeFactory::AutoRegister autoRefSpaceless("spaceless"); static TemplateNodeFactory::AutoRegister autoRefIndexEntry("indexentry"); @@ -4419,6 +4539,8 @@ class TemplateLexer public: TemplateLexer(const TemplateEngine *engine,const QCString &fileName,const char *data,int size); void tokenize(QList &tokens); + void setOpenCloseCharacters(char openChar,char closeChar) + { m_openChar=openChar; m_closeChar=closeChar; } private: void addToken(QList &tokens, const char *data,int line,int startPos,int endPos, @@ -4427,6 +4549,8 @@ class TemplateLexer const TemplateEngine *m_engine; QCString m_fileName; QCString m_data; + char m_openChar; + char m_closeChar; }; TemplateLexer::TemplateLexer(const TemplateEngine *engine,const QCString &fileName,const char *data,int size) : @@ -4435,6 +4559,8 @@ TemplateLexer::TemplateLexer(const TemplateEngine *engine,const QCString &fileNa m_data.resize(size+1); memcpy(m_data.rawData(),data,size); m_data[size]=0; + m_openChar='{'; + m_closeChar='}'; } void TemplateLexer::tokenize(QList &tokens) @@ -4453,6 +4579,7 @@ void TemplateLexer::tokenize(QList &tokens) }; const char *p=m_data.data(); + if (p==0) return; int state=StateText; int pos=0; int lastTokenPos=0; @@ -4466,7 +4593,7 @@ void TemplateLexer::tokenize(QList &tokens) switch (state) { case StateText: - if (c=='{') // {{ or {% or {# or something else + if (c==m_openChar) // {{ or {% or {# or something else { state=StateBeginTemplate; } @@ -4487,7 +4614,14 @@ void TemplateLexer::tokenize(QList &tokens) markStartPos=pos-1; break; case '{': // {{ - state=StateMaybeVar; + if (m_openChar=='{') + { + state=StateMaybeVar; + } + else + { + state=StateVariable; + } markStartPos=pos-1; break; default: @@ -4499,7 +4633,7 @@ void TemplateLexer::tokenize(QList &tokens) case StateTag: if (c=='\n') { - warn(m_fileName,line,"unexpected new line inside {%%...%%} block"); + warn(m_fileName,line,"unexpected new line inside %c%%...%%%c block",m_openChar,m_closeChar); m_engine->printIncludeContext(m_fileName,line); } else if (c=='%') // %} or something else @@ -4508,7 +4642,7 @@ void TemplateLexer::tokenize(QList &tokens) } break; case StateEndTag: - if (c=='}') // %} + if (c==m_closeChar) // %} { // found tag! state=StateText; @@ -4523,7 +4657,7 @@ void TemplateLexer::tokenize(QList &tokens) { if (c=='\n') { - warn(m_fileName,line,"unexpected new line inside {%%...%%} block"); + warn(m_fileName,line,"unexpected new line inside %c%%...%%%c block",m_openChar,m_closeChar); m_engine->printIncludeContext(m_fileName,line); } state=StateTag; @@ -4532,7 +4666,7 @@ void TemplateLexer::tokenize(QList &tokens) case StateComment: if (c=='\n') { - warn(m_fileName,line,"unexpected new line inside {#...#} block"); + warn(m_fileName,line,"unexpected new line inside %c#...#%c block",m_openChar,m_closeChar); m_engine->printIncludeContext(m_fileName,line); } else if (c=='#') // #} or something else @@ -4541,7 +4675,7 @@ void TemplateLexer::tokenize(QList &tokens) } break; case StateEndComment: - if (c=='}') // #} + if (c==m_closeChar) // #} { // found comment tag! state=StateText; @@ -4554,7 +4688,7 @@ void TemplateLexer::tokenize(QList &tokens) { if (c=='\n') { - warn(m_fileName,line,"unexpected new line inside {#...#} block"); + warn(m_fileName,line,"unexpected new line inside %c#...#%c block",m_openChar,m_closeChar); m_engine->printIncludeContext(m_fileName,line); } state=StateComment; @@ -4577,9 +4711,10 @@ void TemplateLexer::tokenize(QList &tokens) } break; case StateVariable: + emptyOutputLine=FALSE; // assume a variable expands to content if (c=='\n') { - warn(m_fileName,line,"unexpected new line inside {{...}} block"); + warn(m_fileName,line,"unexpected new line inside %c{...}%c block",m_openChar,m_closeChar); m_engine->printIncludeContext(m_fileName,line); } else if (c=='}') // }} or something else @@ -4588,7 +4723,7 @@ void TemplateLexer::tokenize(QList &tokens) } break; case StateEndVariable: - if (c=='}') // }} + if (c==m_closeChar) // }} { // found variable tag! state=StateText; @@ -4603,7 +4738,7 @@ void TemplateLexer::tokenize(QList &tokens) { if (c=='\n') { - warn(m_fileName,line,"unexpected new line inside {{...}} block"); + warn(m_fileName,line,"unexpected new line inside %c{...}%c block",m_openChar,m_closeChar); m_engine->printIncludeContext(m_fileName,line); } state=StateVariable; @@ -4705,7 +4840,7 @@ void TemplateParser::parse( command=="endrecursetree" || command=="endspaceless" || command=="endmarkers" || command=="endmsg" || command=="endrepeat" || command=="elif" || - command=="endrange") + command=="endrange" || command=="endtabbing") { warn(m_templateName,tok->line,"Found tag '%s' without matching start tag",command.data()); } @@ -4773,12 +4908,17 @@ void TemplateParser::warn(const char *fileName,int line,const char *fmt,...) con //---------------------------------------------------------- -TemplateImpl::TemplateImpl(TemplateEngine *engine,const QCString &name,const char *data,int size) +TemplateImpl::TemplateImpl(TemplateEngine *engine,const QCString &name,const char *data,int size, + const QCString &extension) : TemplateNode(0) { m_name = name; m_engine = engine; TemplateLexer lexer(engine,name,data,size); + if (extension=="tex") + { + lexer.setOpenCloseCharacters('<','>'); + } QList tokens; tokens.setAutoDelete(TRUE); lexer.tokenize(tokens); @@ -4851,27 +4991,9 @@ class TemplateEngine::Private const Resource *res = ResourceMgr::instance().get(fileName); if (res) { - templ = new TemplateImpl(m_engine,fileName,(const char *)res->data,res->size); + templ = new TemplateImpl(m_engine,fileName,(const char *)res->data,res->size,m_extension); m_templateCache.insert(fileName,templ); } -#if 0 - QFile f(fileName); - if (f.open(IO_ReadOnly)) - { - uint size=f.size(); - char *data = new char[size+1]; - if (data) - { - data[size]=0; - if (f.readBlock(data,f.size())) - { - templ = new TemplateImpl(m_engine,fileName,data); - m_templateCache.insert(fileName,templ); - } - delete[] data; - } - } -#endif else { err("Cound not open template file %s\n",fileName.data()); @@ -4928,11 +5050,22 @@ class TemplateEngine::Private } } + void setOutputExtension(const char *extension) + { + m_extension = extension; + } + + QCString outputExtension() const + { + return m_extension; + } + private: QDict