diff options
Diffstat (limited to 'src/htmlgen.cpp')
-rw-r--r-- | src/htmlgen.cpp | 302 |
1 files changed, 237 insertions, 65 deletions
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp index 402b4e4..bf52eed 100644 --- a/src/htmlgen.cpp +++ b/src/htmlgen.cpp @@ -49,6 +49,7 @@ #include "bufstr.h" #include "resourcemgr.h" #include "tooltip.h" +#include "growbuf.h" //#define DBG_HTML(x) x; #define DBG_HTML(x) @@ -56,6 +57,7 @@ static QCString g_header; static QCString g_footer; static QCString g_mathjax_code; +static QCString g_latex_macro; static bool DoxyCodeLineOpen = FALSE; @@ -112,6 +114,174 @@ static void writeServerSearchBox(FTextStream &t,const char *relPath,bool highlig } //------------------------------------------------------------------------ +/// Convert a set of LaTeX `\(re)newcommand` to a form readable by MathJax +/// LaTeX syntax: +/// \newcommand{\cmd}{replacement} +/// or +/// \renewcommand{\cmd}{replacement} +/// MathJax syntax: +/// cmd: "{replacement}" +/// +/// LaTeX syntax: +/// \newcommand{\cmd}[nr]{replacement} +/// or +/// \renewcommand{\cmd}[nr]{replacement} +/// MathJax syntax: +/// cmd: ["{replacement}",nr] +static QCString getConvertLatexMacro() +{ + QCString macrofile = Config_getString(FORMULA_MACROFILE); + if (macrofile.isEmpty()) return ""; + QCString s = fileToString(macrofile); + macrofile = QFileInfo(macrofile).absFilePath().utf8(); + int size = s.length(); + GrowBuf out(size); + const char *data = s.data(); + int line = 1; + int cnt = 0; + int i = 0; + QCString nr; + while (i < size) + { + nr = ""; + // skip initial white space, but count lines + while (i < size && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n')) + { + if (data[i] == '\n') line++; + i++; + } + if (i >= size) break; + // check for \newcommand or \renewcommand + if (data[i] != '\\') + { + warn(macrofile,line, "file contains non valid code, expected '\\' got '%c'\n",data[i]); + return ""; + } + i++; + if (!qstrncmp(data + i, "newcommand", strlen("newcommand"))) i += strlen("newcommand"); + else if (!qstrncmp(data + i, "renewcommand", strlen("renewcommand"))) i += strlen("renewcommand"); + else + { + warn(macrofile,line, "file contains non valid code, expected 'newcommand' or 'renewcommand'"); + return ""; + } + // handle {cmd} + if (data[i] != '{') + { + warn(macrofile,line, "file contains non valid code, expected '{' got '%c'\n",data[i]); + return ""; + } + i++; + if (data[i] != '\\') + { + warn(macrofile,line, "file contains non valid code, expected '\\' got '%c'\n",data[i]); + return ""; + } + i++; + // run till }, i.e. cmd + out.addStr(" "); + while (i < size && (data[i] != '}')) out.addChar(data[i++]); + if (i >= size) + { + warn(macrofile,line, "file contains non valid code, no closing '}' for command"); + return ""; + } + out.addChar(':'); + out.addChar(' '); + i++; + + if (data[i] == '[') + { + // handle [nr] + // run till ] + out.addChar('['); + i++; + while (i < size && (data[i] != ']')) nr += data[i++]; + if (i >= size) + { + warn(macrofile,line, "file contains non valid code, no closing ']'"); + return ""; + } + i++; + } + else if (data[i] != '{') + { + warn(macrofile,line, "file contains non valid code, expected '[' or '{' got '%c'\n",data[i]); + return ""; + } + // handle {replacement} + // retest as the '[' part might have advanced so we can have a new '{' + if (data[i] != '{') + { + warn(macrofile,line, "file contains non valid code, expected '{' got '%c'\n",data[i]); + return ""; + } + out.addChar('"'); + out.addChar('{'); + i++; + // run till } + cnt = 1; + while (i < size && cnt) + { + switch(data[i]) + { + case '\\': + out.addChar('\\'); // need to escape it for MathJax js code + out.addChar('\\'); + i++; + if (data[i] == '\\') // we have an escaped backslash + { + out.addChar('\\'); + out.addChar('\\'); + i++; + } + else if (data[i] != '"') out.addChar(data[i++]); // double quote handled separately + break; + case '{': + cnt++; + out.addChar(data[i++]); + break; + case '}': + cnt--; + if (cnt) out.addChar(data[i]); + i++; + break; + case '"': + out.addChar('\\'); // need to escape it for MathJax js code + out.addChar(data[i++]); + break; + case '\n': + line++; + out.addChar(data[i++]); + break; + default: + out.addChar(data[i++]); + break; + } + } + if (i > size) + { + warn(macrofile,line, "file contains non valid code, no closing '}' for replacement"); + return ""; + } + out.addChar('}'); + out.addChar('"'); + if (!nr.isEmpty()) + { + out.addChar(','); + out.addStr(nr); + } + if (!nr.isEmpty()) + { + out.addChar(']'); + } + out.addChar(','); + out.addChar('\n'); + } + out.addChar(0); + return out.get(); +} +//------------------------------------------------------------------------ /// Clear a text block \a s from \a begin to \a end markers QCString clearBlock(const char *s,const char *begin,const char *end) @@ -229,7 +399,7 @@ static QCString substituteHtmlKeywords(const QCString &s, const QCString &relPath, const QCString &navPath=QCString()) { - // Build CSS/Javascript tags depending on treeview, search engine settings + // Build CSS/JavaScript tags depending on treeview, search engine settings QCString cssFile; QStrList extraCssFile; QCString generatedBy; @@ -300,12 +470,7 @@ static QCString substituteHtmlKeywords(const QCString &s, treeViewCssJs = "<link href=\"$relpath^navtree.css\" rel=\"stylesheet\" type=\"text/css\"/>\n" "<script type=\"text/javascript\" src=\"$relpath^resize.js\"></script>\n" "<script type=\"text/javascript\" src=\"$relpath^navtreedata.js\"></script>\n" - "<script type=\"text/javascript\" src=\"$relpath^navtree.js\"></script>\n" - "<script type=\"text/javascript\">\n" - "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n" - " $(document).ready(initResizable);\n" - "/* @license-end */" - "</script>"; + "<script type=\"text/javascript\" src=\"$relpath^navtree.js\"></script>\n"; } if (searchEngine) @@ -381,7 +546,18 @@ static QCString substituteHtmlKeywords(const QCString &s, mathJaxJs += g_mathjax_code; mathJaxJs += "\n"; } - mathJaxJs += "</script>"; + mathJaxJs += "</script>\n"; + if (!g_latex_macro.isEmpty()) + { + mathJaxJs += "<script type=\"text/x-mathjax-config\">\n" + " MathJax.Hub.Config({\n" + " TeX: { Macros: {\n"; + mathJaxJs += g_latex_macro; + mathJaxJs += "\n" + " } }\n" + "});\n" + "</script>\n"; + } mathJaxJs += "<script type=\"text/javascript\" async=\"async\" src=\"" + path + "MathJax.js\"></script>\n"; } @@ -492,7 +668,7 @@ void HtmlCodeGenerator::codify(const char *str) void HtmlCodeGenerator::docify(const char *str) { - m_t << getHtmlDirEmbedingChar(getTextDirByConfig(str)); + m_t << getHtmlDirEmbeddingChar(getTextDirByConfig(str)); if (str && m_streamSet) { @@ -548,6 +724,7 @@ void HtmlCodeGenerator::writeLineNumber(const char *ref,const char *filename, } m_t << "</span>"; m_t << " "; + m_col=0; } void HtmlCodeGenerator::writeCodeLink(const char *ref,const char *f, @@ -575,7 +752,7 @@ void HtmlCodeGenerator::_writeCodeLink(const char *className, } m_t << "href=\""; m_t << externalRef(m_relPath,ref,TRUE); - if (f) m_t << f << Doxygen::htmlFileExtension; + if (f) m_t << addHtmlExtensionIfMissing(f); if (anchor) m_t << "#" << anchor; m_t << "\""; if (tooltip) m_t << " title=\"" << convertToHtml(tooltip) << "\""; @@ -596,7 +773,7 @@ void HtmlCodeGenerator::writeTooltip(const char *id, const DocLinkInfo &docInfo, { m_t << "<a href=\""; m_t << externalRef(m_relPath,docInfo.ref,TRUE); - m_t << docInfo.url << Doxygen::htmlFileExtension; + m_t << addHtmlExtensionIfMissing(docInfo.url); if (!docInfo.anchor.isEmpty()) { m_t << "#" << docInfo.anchor; @@ -628,7 +805,7 @@ void HtmlCodeGenerator::writeTooltip(const char *id, const DocLinkInfo &docInfo, { m_t << "<a href=\""; m_t << externalRef(m_relPath,defInfo.ref,TRUE); - m_t << defInfo.url << Doxygen::htmlFileExtension; + m_t << addHtmlExtensionIfMissing(defInfo.url); if (!defInfo.anchor.isEmpty()) { m_t << "#" << defInfo.anchor; @@ -649,7 +826,7 @@ void HtmlCodeGenerator::writeTooltip(const char *id, const DocLinkInfo &docInfo, { m_t << "<a href=\""; m_t << externalRef(m_relPath,declInfo.ref,TRUE); - m_t << declInfo.url << Doxygen::htmlFileExtension; + m_t << addHtmlExtensionIfMissing(declInfo.url); if (!declInfo.anchor.isEmpty()) { m_t << "#" << declInfo.anchor; @@ -716,7 +893,7 @@ void HtmlCodeGenerator::writeCodeAnchor(const char *anchor) HtmlGenerator::HtmlGenerator() : OutputGenerator() { - dir=Config_getString(HTML_OUTPUT); + m_dir=Config_getString(HTML_OUTPUT); m_emptySection=FALSE; m_sectionCount=0; } @@ -732,8 +909,7 @@ void HtmlGenerator::init() QDir d(dname); if (!d.exists() && !d.mkdir(dname)) { - err("Could not create output directory %s\n",dname.data()); - exit(1); + term("Could not create output directory %s\n",dname.data()); } //writeLogo(dname); if (!Config_getString(HTML_HEADER).isEmpty()) @@ -763,6 +939,8 @@ void HtmlGenerator::init() g_mathjax_code=fileToString(Config_getString(MATHJAX_CODEFILE)); //printf("g_mathjax_code='%s'\n",g_mathjax_code.data()); } + g_latex_macro=getConvertLatexMacro(); + //printf("converted g_latex_macro='%s'\n",g_latex_macro.data()); } createSubDirs(d); @@ -908,21 +1086,17 @@ void HtmlGenerator::startFile(const char *name,const char *, const char *title) { //printf("HtmlGenerator::startFile(%s)\n",name); - QCString fileName=name; - lastTitle=title; - relPath = relativePathToRoot(fileName); + m_relPath = relativePathToRoot(name); + QCString fileName = addHtmlExtensionIfMissing(name); + m_lastTitle=title; - if (fileName.right(Doxygen::htmlFileExtension.length())!=Doxygen::htmlFileExtension) - { - fileName+=Doxygen::htmlFileExtension; - } startPlainFile(fileName); m_codeGen.setTextStream(t); - m_codeGen.setRelativePath(relPath); + m_codeGen.setRelativePath(m_relPath); Doxygen::indexList->addIndexFile(fileName); - lastFile = fileName; - t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),relPath); + m_lastFile = fileName; + t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),m_relPath); t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen " << getVersion() << " -->" << endl; @@ -933,7 +1107,7 @@ void HtmlGenerator::startFile(const char *name,const char *, t << "<script type=\"text/javascript\">\n"; t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n"; t << "var searchBox = new SearchBox(\"searchBox\", \"" - << relPath<< "search\",false,'" << theTranslator->trSearch() << "');\n"; + << m_relPath<< "search\",false,'" << theTranslator->trSearch() << "');\n"; t << "/* @license-end */\n"; t << "</script>\n"; } @@ -941,13 +1115,12 @@ void HtmlGenerator::startFile(const char *name,const char *, m_sectionCount=0; } -void HtmlGenerator::writeSearchInfo(FTextStream &t,const QCString &relPath) +void HtmlGenerator::writeSearchInfo(FTextStream &t,const QCString &) { static bool searchEngine = Config_getBool(SEARCHENGINE); static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH); if (searchEngine && !serverBasedSearch) { - (void)relPath; t << "<!-- window showing the filter options -->\n"; t << "<div id=\"MSearchSelectWindow\"\n"; t << " onmouseover=\"return searchBox.OnSearchSelectShow()\"\n"; @@ -967,7 +1140,7 @@ void HtmlGenerator::writeSearchInfo(FTextStream &t,const QCString &relPath) void HtmlGenerator::writeSearchInfo() { - writeSearchInfo(t,relPath); + writeSearchInfo(t,m_relPath); } @@ -997,7 +1170,7 @@ QCString HtmlGenerator::writeLogoAsString(const char *path) void HtmlGenerator::writeLogo() { - t << writeLogoAsString(relPath); + t << writeLogoAsString(m_relPath); } void HtmlGenerator::writePageFooter(FTextStream &t,const QCString &lastTitle, @@ -1011,7 +1184,7 @@ void HtmlGenerator::writeFooter(const char *navPath) // Currently only tooltips in HTML TooltipManager::instance()->writeTooltips(m_codeGen); - writePageFooter(t,lastTitle,relPath,navPath); + writePageFooter(t,m_lastTitle,m_relPath,navPath); } void HtmlGenerator::endFile() @@ -1148,8 +1321,8 @@ void HtmlGenerator::startIndexItem(const char *ref,const char *f) t << "<a class=\"el\" "; } t << "href=\""; - t << externalRef(relPath,ref,TRUE); - if (f) t << f << Doxygen::htmlFileExtension; + t << externalRef(m_relPath,ref,TRUE); + if (f) t << addHtmlExtensionIfMissing(f); t << "\">"; } else @@ -1176,7 +1349,7 @@ void HtmlGenerator::writeStartAnnoItem(const char *,const char *f, { t << "<li>"; if (path) docify(path); - t << "<a class=\"el\" href=\"" << f << Doxygen::htmlFileExtension << "\">"; + t << "<a class=\"el\" href=\"" << addHtmlExtensionIfMissing(f) << "\">"; docify(name); t << "</a> "; } @@ -1194,8 +1367,8 @@ void HtmlGenerator::writeObjectLink(const char *ref,const char *f, t << "<a class=\"el\" "; } t << "href=\""; - t << externalRef(relPath,ref,TRUE); - if (f) t << f << Doxygen::htmlFileExtension; + t << externalRef(m_relPath,ref,TRUE); + if (f) t << addHtmlExtensionIfMissing(f); if (anchor) t << "#" << anchor; t << "\">"; docify(name); @@ -1205,7 +1378,7 @@ void HtmlGenerator::writeObjectLink(const char *ref,const char *f, void HtmlGenerator::startTextLink(const char *f,const char *anchor) { t << "<a href=\""; - if (f) t << relPath << f << Doxygen::htmlFileExtension; + if (f) t << m_relPath << addHtmlExtensionIfMissing(f); if (anchor) t << "#" << anchor; t << "\">"; } @@ -1408,7 +1581,7 @@ static void endSectionContent(FTextStream &t) void HtmlGenerator::startClassDiagram() { - startSectionHeader(t,relPath,m_sectionCount); + startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endClassDiagram(const ClassDiagram &d, @@ -1421,12 +1594,12 @@ void HtmlGenerator::endClassDiagram(const ClassDiagram &d, startSectionSummary(t,m_sectionCount); endSectionSummary(t); startSectionContent(t,m_sectionCount); - d.writeImage(tt,dir,relPath,fileName); + d.writeImage(tt,m_dir,m_relPath,fileName); if (!result.isEmpty()) { t << " <div class=\"center\">" << endl; t << " <img src=\""; - t << relPath << fileName << ".png\" usemap=\"#" << convertToId(name); + t << m_relPath << fileName << ".png\" usemap=\"#" << convertToId(name); t << "_map\" alt=\"\"/>" << endl; t << " <map id=\"" << convertToId(name); t << "_map\" name=\"" << convertToId(name); @@ -1439,7 +1612,7 @@ void HtmlGenerator::endClassDiagram(const ClassDiagram &d, { t << " <div class=\"center\">" << endl; t << " <img src=\""; - t << relPath << fileName << ".png\" alt=\"\"/>" << endl; + t << m_relPath << fileName << ".png\" alt=\"\"/>" << endl; t << " </div>"; } endSectionContent(t); @@ -1792,7 +1965,7 @@ void HtmlGenerator::endMemberDoc(bool hasArgs) void HtmlGenerator::startDotGraph() { - startSectionHeader(t,relPath,m_sectionCount); + startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endDotGraph(DotClassGraph &g) @@ -1804,11 +1977,11 @@ void HtmlGenerator::endDotGraph(DotClassGraph &g) endSectionSummary(t); startSectionContent(t,m_sectionCount); - g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,TRUE,m_sectionCount); + g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,TRUE,m_sectionCount); if (generateLegend && !umlLook) { t << "<center><span class=\"legend\">["; - startHtmlLink(relPath+"graph_legend"+Doxygen::htmlFileExtension); + startHtmlLink(m_relPath+"graph_legend"+Doxygen::htmlFileExtension); t << theTranslator->trLegend(); endHtmlLink(); t << "]</span></center>"; @@ -1820,7 +1993,7 @@ void HtmlGenerator::endDotGraph(DotClassGraph &g) void HtmlGenerator::startInclDepGraph() { - startSectionHeader(t,relPath,m_sectionCount); + startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endInclDepGraph(DotInclDepGraph &g) @@ -1830,7 +2003,7 @@ void HtmlGenerator::endInclDepGraph(DotInclDepGraph &g) endSectionSummary(t); startSectionContent(t,m_sectionCount); - g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount); + g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; @@ -1838,7 +2011,7 @@ void HtmlGenerator::endInclDepGraph(DotInclDepGraph &g) void HtmlGenerator::startGroupCollaboration() { - startSectionHeader(t,relPath,m_sectionCount); + startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endGroupCollaboration(DotGroupCollaboration &g) @@ -1848,7 +2021,7 @@ void HtmlGenerator::endGroupCollaboration(DotGroupCollaboration &g) endSectionSummary(t); startSectionContent(t,m_sectionCount); - g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount); + g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; @@ -1856,7 +2029,7 @@ void HtmlGenerator::endGroupCollaboration(DotGroupCollaboration &g) void HtmlGenerator::startCallGraph() { - startSectionHeader(t,relPath,m_sectionCount); + startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endCallGraph(DotCallGraph &g) @@ -1866,7 +2039,7 @@ void HtmlGenerator::endCallGraph(DotCallGraph &g) endSectionSummary(t); startSectionContent(t,m_sectionCount); - g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount); + g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; @@ -1874,7 +2047,7 @@ void HtmlGenerator::endCallGraph(DotCallGraph &g) void HtmlGenerator::startDirDepGraph() { - startSectionHeader(t,relPath,m_sectionCount); + startSectionHeader(t,m_relPath,m_sectionCount); } void HtmlGenerator::endDirDepGraph(DotDirDeps &g) @@ -1884,7 +2057,7 @@ void HtmlGenerator::endDirDepGraph(DotDirDeps &g) endSectionSummary(t); startSectionContent(t,m_sectionCount); - g.writeGraph(t,GOF_BITMAP,EOF_Html,dir,fileName,relPath,TRUE,m_sectionCount); + g.writeGraph(t,GOF_BITMAP,EOF_Html,m_dir,m_fileName,m_relPath,TRUE,m_sectionCount); endSectionContent(t); m_sectionCount++; @@ -1892,7 +2065,7 @@ void HtmlGenerator::endDirDepGraph(DotDirDeps &g) void HtmlGenerator::writeGraphicalHierarchy(DotGfxHierarchyTable &g) { - g.writeGraph(t,dir,fileName); + g.writeGraph(t,m_dir,m_fileName); } void HtmlGenerator::startMemberGroupHeader(bool) @@ -2369,9 +2542,9 @@ QCString HtmlGenerator::writeSplitBarAsString(const char *name,const char *relpa "<script type=\"text/javascript\">\n" "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n" "$(document).ready(function(){initNavTree('") + - QCString(name) + Doxygen::htmlFileExtension + + QCString(addHtmlExtensionIfMissing(name)) + QCString("','") + relpath + - QCString("');});\n" + QCString("'); initResizable(); });\n" "/* @license-end */\n" "</script>\n" "<div id=\"doc-content\">\n"); @@ -2381,12 +2554,12 @@ QCString HtmlGenerator::writeSplitBarAsString(const char *name,const char *relpa void HtmlGenerator::writeSplitBar(const char *name) { - t << writeSplitBarAsString(name,relPath); + t << writeSplitBarAsString(name,m_relPath); } void HtmlGenerator::writeNavigationPath(const char *s) { - t << substitute(s,"$relpath^",relPath); + t << substitute(s,"$relpath^",m_relPath); } void HtmlGenerator::startContents() @@ -2411,7 +2584,7 @@ void HtmlGenerator::endPageDoc() void HtmlGenerator::writeQuickLinks(bool compact,HighlightedItem hli,const char *file) { - writeDefaultQuickLinks(t,compact,hli,file,relPath); + writeDefaultQuickLinks(t,compact,hli,file,m_relPath); } // PHP based search script @@ -2800,18 +2973,18 @@ void HtmlGenerator::writeInheritedSectionTitle( { classLink+= externalLinkTarget(); classLink += " href=\""; - classLink+= externalRef(relPath,ref,TRUE); + classLink+= externalRef(m_relPath,ref,TRUE); } else { classLink += "href=\""; - classLink+=relPath; + classLink+=m_relPath; } - classLink+=file+Doxygen::htmlFileExtension+a; + classLink=classLink+addHtmlExtensionIfMissing(file)+a; classLink+=QCString("\">")+convertToHtml(name,FALSE)+"</a>"; t << "<tr class=\"inherit_header " << id << "\">" << "<td colspan=\"2\" onclick=\"javascript:toggleInherit('" << id << "')\">" - << "<img src=\"" << relPath << "closed.png\" alt=\"-\"/> " + << "<img src=\"" << m_relPath << "closed.png\" alt=\"-\"/> " << theTranslator->trInheritedFrom(convertToHtml(title,FALSE),classLink) << "</td></tr>" << endl; } @@ -2829,8 +3002,7 @@ void HtmlGenerator::writeSummaryLink(const char *file,const char *anchor,const c t << "<a href=\""; if (file) { - t << relPath << file; - t << Doxygen::htmlFileExtension; + t << m_relPath << addHtmlExtensionIfMissing(file); } else { |