summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml6
-rw-r--r--src/CMakeLists.txt16
-rw-r--r--src/classdef.h23
-rw-r--r--src/configimpl.l8
-rw-r--r--src/dotclassgraph.cpp61
-rw-r--r--src/dotnode.cpp41
-rw-r--r--src/doxygen.cpp13
-rw-r--r--src/fortrancode.l16
-rw-r--r--src/htmlhelp.cpp599
-rw-r--r--src/htmlhelp.h39
-rw-r--r--src/markdown.cpp4
-rwxr-xr-xsrc/res2cc_cmd.py7
-rw-r--r--src/resourcemgr.cpp33
-rw-r--r--src/resourcemgr.h7
-rw-r--r--src/translator.h4
-rw-r--r--src/translator_adapter.h12
-rw-r--r--src/translator_br.h2
-rw-r--r--src/translator_de.h13
-rw-r--r--src/translator_en.h14
-rw-r--r--src/translator_nl.h2
-rw-r--r--src/translator_pt.h2
-rw-r--r--src/translator_sc.h2
-rw-r--r--src/translator_sv.h2
-rw-r--r--src/translator_tr.h2
-rw-r--r--src/translator_za.h4
-rw-r--r--testing/055/md_055_markdown.xml6
-rw-r--r--testing/055_markdown.md4
-rw-r--r--testing/CMakeLists.txt27
-rw-r--r--vhdlparser/VhdlParserTokenManager.cc5
-rwxr-xr-xvhdlparser/vhdlparser.jj2
30 files changed, 512 insertions, 464 deletions
diff --git a/.travis.yml b/.travis.yml
index ced8d26..733e668 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -122,7 +122,9 @@ script:
- cmake --version;
- cmake -G "Unix Makefiles" -Dbuild_doc=ON -Dbuild_wizard=ON ..
- make
- - if [ ! "${TRAVIS_OS_NAME}" == "osx" ]; then
- make tests;
+ - if [ ! "${TRAVIS_OS_NAME}" == "osx" ] && [ ! "${TRAVIS_COMPILER}" == "clang" ]; then
+ make tests docs;
+ fi;
+ - if [ ! "${TRAVIS_OS_NAME}" == "osx" ] && [ "${TRAVIS_COMPILER}" == "clang" ]; then
make docs;
fi;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8b11a2d..cb28911 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,7 +14,11 @@ include_directories(
file(MAKE_DIRECTORY ${GENERATED_SRC})
-file(GLOB LANGUAGE_FILES "${CMAKE_CURRENT_LIST_DIR}/translator_??.h")
+if (${CMAKE_VERSION} VERSION_EQUAL "3.11.0" OR ${CMAKE_VERSION} VERSION_GREATER "3.11.0")
+ file(GLOB LANGUAGE_FILES CONFIGURE_DEPENDS "${CMAKE_CURRENT_LIST_DIR}/translator_??.h")
+else()
+ file(GLOB LANGUAGE_FILES "${CMAKE_CURRENT_LIST_DIR}/translator_??.h")
+endif()
# instead of increasebuffer.py
add_definitions(-DYY_BUF_SIZE=${enlarge_lex_buffers} -DYY_READ_BUF_SIZE=${enlarge_lex_buffers})
@@ -81,13 +85,17 @@ add_custom_command(
set_source_files_properties(${GENERATED_SRC}/lang_cfg.h PROPERTIES GENERATED 1)
# all resource files
-file(GLOB RESOURCES ${CMAKE_SOURCE_DIR}/templates/*/*)
+if (${CMAKE_VERSION} VERSION_EQUAL "3.11.0" OR ${CMAKE_VERSION} VERSION_GREATER "3.11.0")
+ file(GLOB RESOURCES CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/templates/*/*)
+else()
+ file(GLOB RESOURCES ${CMAKE_SOURCE_DIR}/templates/*/*)
+endif()
# resources.cpp
add_custom_command(
COMMENT "Generating ${GENERATED_SRC}/resources.cpp"
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/res2cc_cmd.py ${CMAKE_SOURCE_DIR}/templates ${GENERATED_SRC}/resources.cpp
- DEPENDS ${RESOURCES}
+ DEPENDS ${RESOURCES} ${CMAKE_CURRENT_LIST_DIR}/res2cc_cmd.py
OUTPUT ${GENERATED_SRC}/resources.cpp
)
set_source_files_properties(${GENERATED_SRC}/resources.cpp PROPERTIES GENERATED 1)
@@ -95,7 +103,7 @@ set_source_files_properties(${GENERATED_SRC}/resources.cpp PROPERTIES GENERATED
# layout_default.xml
add_custom_command(
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/to_c_cmd.py < ${CMAKE_CURRENT_LIST_DIR}/layout_default.xml > ${GENERATED_SRC}/layout_default.xml.h
- DEPENDS ${CMAKE_CURRENT_LIST_DIR}/layout_default.xml
+ DEPENDS ${CMAKE_CURRENT_LIST_DIR}/layout_default.xml ${CMAKE_CURRENT_LIST_DIR}/to_c_cmd.py
OUTPUT ${GENERATED_SRC}/layout_default.xml.h
)
set_source_files_properties(${GENERATED_SRC}/layout_default.xml.h PROPERTIES GENERATED 1)
diff --git a/src/classdef.h b/src/classdef.h
index 46a13c1..d413794 100644
--- a/src/classdef.h
+++ b/src/classdef.h
@@ -24,6 +24,7 @@
#include <qdict.h>
#include <qptrdict.h>
+#include "containers.h"
#include "definition.h"
#include "arguments.h"
@@ -433,18 +434,15 @@ struct UsesClassDef
{
UsesClassDef(ClassDef *cd) : classDef(cd)
{
- accessors = new QDict<void>(17);
- containment = TRUE;
}
~UsesClassDef()
{
- delete accessors;
}
void addAccessor(const char *s)
{
- if (accessors->find(s)==0)
+ if (accessors.find(s)==accessors.end())
{
- accessors->insert(s,(void *)666);
+ accessors.insert(s);
}
}
/** Class definition that this relation uses. */
@@ -453,12 +451,12 @@ struct UsesClassDef
/** Dictionary of member variable names that form the edge labels of the
* usage relation.
*/
- QDict<void> *accessors;
+ StringSet accessors;
/** Template arguments used for the base class */
QCString templSpecifiers;
- bool containment;
+ bool containment = true;
};
/** Dictionary of usage relations.
@@ -486,8 +484,7 @@ class UsesClassDictIterator : public QDictIterator<UsesClassDef>
*/
struct BaseClassDef
{
- BaseClassDef(ClassDef *cd,const char *n,Protection p,
- Specifier v,const char *t) :
+ BaseClassDef(ClassDef *cd,const char *n,Protection p, Specifier v,const char *t) :
classDef(cd), usedName(n), prot(p), virt(v), templSpecifiers(t) {}
/** Class definition that this relation inherits from. */
@@ -549,17 +546,15 @@ struct ConstraintClassDef
{
ConstraintClassDef(ClassDef *cd) : classDef(cd)
{
- accessors = new QDict<void>(17);
}
~ConstraintClassDef()
{
- delete accessors;
}
void addAccessor(const char *s)
{
- if (accessors->find(s)==0)
+ if (accessors.find(s)==accessors.end())
{
- accessors->insert(s,(void *)666);
+ accessors.insert(s);
}
}
/** Class definition that this relation uses. */
@@ -568,7 +563,7 @@ struct ConstraintClassDef
/** Dictionary of member types names that form the edge labels of the
* constraint relation.
*/
- QDict<void> *accessors;
+ StringSet accessors;
};
/** Dictionary of constraint relations.
diff --git a/src/configimpl.l b/src/configimpl.l
index 9eda61d..25fa78b 100644
--- a/src/configimpl.l
+++ b/src/configimpl.l
@@ -1577,6 +1577,14 @@ void Config::checkAndCorrect()
}
//------------------------
+ // check if GENERATE_HTMLHELP and HTML_FILE_EXTENSION is not .html
+ if (Config_getString(HTML_FILE_EXTENSION)!=".html" && Config_getBool(GENERATE_HTMLHELP))
+ {
+ err("When enabling GENERATE_HTMLHELP the HTML_FILE_EXTENSION should be \".html\". I'll do it for you.\n");
+ Config_updateString(HTML_FILE_EXTENSION,".html");
+ }
+
+ //------------------------
// check if SEARCHENGINE and GENERATE_HTMLHELP are both enabled
if (Config_getBool(SEARCHENGINE) && Config_getBool(GENERATE_HTMLHELP))
{
diff --git a/src/dotclassgraph.cpp b/src/dotclassgraph.cpp
index 28967f4..84b7962 100644
--- a/src/dotclassgraph.cpp
+++ b/src/dotclassgraph.cpp
@@ -239,6 +239,25 @@ bool DotClassGraph::determineVisibleNodes(DotNode *rootNode,
// left to right order.
}
+static QCString joinLabels(const StringSet &ss)
+{
+ QCString label;
+ int count=1;
+ int maxLabels=10;
+ auto it = std::begin(ss), e = std::end(ss);
+ if (it!=e) // set not empty
+ {
+ label += (*it++).c_str();
+ for (; it!=e && count < maxLabels ; ++it,++count)
+ {
+ label += '\n';
+ label += (*it).c_str();
+ }
+ if (count==maxLabels) label+="\n...";
+ }
+ return label;
+}
+
void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance)
{
//printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n",
@@ -275,27 +294,8 @@ void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int dista
UsesClassDef *ucd;
for (;(ucd=ucdi.current());++ucdi)
{
- QCString label;
- QDictIterator<void> dvi(*ucd->accessors);
- const char *s;
- bool first=TRUE;
- int count=0;
- int maxLabels=10;
- for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
- {
- if (first)
- {
- label=s;
- first=FALSE;
- }
- else
- {
- label+=QCString("\n")+s;
- }
- }
- if (count==maxLabels) label+="\n...";
//printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
- addClass(ucd->classDef,n,EdgeInfo::Purple,label,0,
+ addClass(ucd->classDef,n,EdgeInfo::Purple,joinLabels(ucd->accessors),0,
ucd->templSpecifiers,base,distance);
}
}
@@ -309,27 +309,8 @@ void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int dista
ConstraintClassDef *ccd;
for (;(ccd=ccdi.current());++ccdi)
{
- QCString label;
- QDictIterator<void> dvi(*ccd->accessors);
- const char *s;
- bool first=TRUE;
- int count=0;
- int maxLabels=10;
- for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
- {
- if (first)
- {
- label=s;
- first=FALSE;
- }
- else
- {
- label+=QCString("\n")+s;
- }
- }
- if (count==maxLabels) label+="\n...";
//printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
- addClass(ccd->classDef,n,EdgeInfo::Orange2,label,0,
+ addClass(ccd->classDef,n,EdgeInfo::Orange2,joinLabels(ccd->accessors),0,
0,TRUE,distance);
}
}
diff --git a/src/dotnode.cpp b/src/dotnode.cpp
index 86ae43a..c02827f 100644
--- a/src/dotnode.cpp
+++ b/src/dotnode.cpp
@@ -87,7 +87,7 @@ static const char *umlEdgeStyleMap[] =
"solid" // usage
};
-static EdgeProperties normalEdgeProps =
+static EdgeProperties normalEdgeProps =
{
normalEdgeColorMap, normalArrowStyleMap, normalEdgeStyleMap
};
@@ -117,9 +117,8 @@ static QCString escapeTooltip(const QCString &tooltip)
static void writeBoxMemberList(FTextStream &t,
char prot,MemberList *ml,const ClassDef *scope,
- bool isStatic=FALSE,const QDict<void> *skipNames=0)
+ bool isStatic=FALSE,const StringUnorderedSet *skipNames=nullptr)
{
- (void)isStatic;
if (ml)
{
MemberListIterator mlia(*ml);
@@ -127,8 +126,8 @@ static void writeBoxMemberList(FTextStream &t,
int totalCount=0;
for (mlia.toFirst();(mma = mlia.current());++mlia)
{
- if (mma->getClassDef()==scope &&
- (skipNames==0 || skipNames->find(mma->name())==0))
+ if (mma->getClassDef()==scope &&
+ (skipNames==nullptr || skipNames->find(mma->name().str())==std::end(*skipNames)))
{
totalCount++;
}
@@ -138,7 +137,7 @@ static void writeBoxMemberList(FTextStream &t,
for (mlia.toFirst();(mma = mlia.current());++mlia)
{
if (mma->getClassDef() == scope &&
- (skipNames==0 || skipNames->find(mma->name())==0))
+ (skipNames==nullptr || skipNames->find(mma->name().str())==std::end(*skipNames)))
{
int numFields = Config_getInt(UML_LIMIT_NUM_FIELDS);
if (numFields>0 && (totalCount>numFields*3/2 && count>=numFields))
@@ -150,7 +149,7 @@ static void writeBoxMemberList(FTextStream &t,
{
t << prot << " ";
t << DotNode::convertLabel(mma->name());
- if (!mma->isObjCMethod() &&
+ if (!mma->isObjCMethod() &&
(mma->isFunction() || mma->isSlot() || mma->isSignal())) t << "()";
t << "\\l";
count++;
@@ -218,7 +217,7 @@ QCString DotNode::convertLabel(const QCString &l)
foldLen = (foldLen+sinceLast+1)/2;
sinceLast=1;
}
- else if (charsLeft>1+foldLen/4 && sinceLast>foldLen+foldLen/3 &&
+ else if (charsLeft>1+foldLen/4 && sinceLast>foldLen+foldLen/3 &&
!isupper(c) && isupper(p[idx]))
{
result+=replacement;
@@ -385,9 +384,9 @@ void DotNode::writeBox(FTextStream &t,
if (m_classDef && Config_getBool(UML_LOOK) && (gt==Inheritance || gt==Collaboration))
{
- // add names shown as relations to a dictionary, so we don't show
+ // add names shown as relations to a set, so we don't show
// them as attributes as well
- QDict<void> arrowNames(17);
+ StringUnorderedSet arrowNames;
if (m_edgeInfo)
{
// for each edge
@@ -403,11 +402,11 @@ void DotNode::writeBox(FTextStream &t,
while ((i=ei->label().find('\n',p))!=-1)
{
lab = stripProtectionPrefix(ei->label().mid(p,i-p));
- arrowNames.insert(lab,(void*)0x8);
+ arrowNames.insert(lab.str());
p=i+1;
}
lab = stripProtectionPrefix(ei->label().right(ei->label().length()-p));
- arrowNames.insert(lab,(void*)0x8);
+ arrowNames.insert(lab.str());
}
}
}
@@ -500,7 +499,7 @@ void DotNode::writeBox(FTextStream &t,
{
t << ",tooltip=\" \""; // space in tooltip is required otherwise still something like 'Node0' is used
}
- t << "];" << endl;
+ t << "];" << endl;
}
void DotNode::writeArrow(FTextStream &t,
@@ -536,20 +535,20 @@ void DotNode::writeArrow(FTextStream &t,
t << ",label=\" " << convertLabel(ei->label()) << "\" ";
}
if (Config_getBool(UML_LOOK) &&
- eProps->arrowStyleMap[ei->color()] &&
+ eProps->arrowStyleMap[ei->color()] &&
(gt==Inheritance || gt==Collaboration)
)
{
bool rev = pointBack;
if (umlUseArrow) rev=!rev; // UML use relates has arrow on the start side
- if (rev)
- t << ",arrowtail=\"" << eProps->arrowStyleMap[ei->color()] << "\"";
- else
+ if (rev)
+ t << ",arrowtail=\"" << eProps->arrowStyleMap[ei->color()] << "\"";
+ else
t << ",arrowhead=\"" << eProps->arrowStyleMap[ei->color()] << "\"";
}
if (format==GOF_BITMAP) t << ",fontname=\"" << Config_getString(DOT_FONTNAME) << "\"";
- t << "];" << endl;
+ t << "];" << endl;
}
void DotNode::write(FTextStream &t,
@@ -564,7 +563,7 @@ void DotNode::write(FTextStream &t,
if (!m_visible) return; // node is not visible
writeBox(t,gt,format,m_truncated==Truncated);
m_written=TRUE;
- QList<DotNode> *nl = toChildren ? m_children : m_parents;
+ QList<DotNode> *nl = toChildren ? m_children : m_parents;
if (nl)
{
if (toChildren)
@@ -671,7 +670,7 @@ void DotNode::writeXML(FTextStream &t,bool isClassGraph) const
<< "</edgelabel>" << endl;
}
t << " </childnode>" << endl;
- }
+ }
}
t << " </node>" << endl;
}
@@ -841,7 +840,7 @@ void DotNode::clearWriteFlag()
}
void DotNode::colorConnectedNodes(int curColor)
-{
+{
if (m_children)
{
QListIterator<DotNode> dnlic(*m_children);
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index dab7549..4bbabb2 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -9411,7 +9411,10 @@ static QCString resolveSymlink(QCString path)
return QDir::cleanDirPath(result).data();
}
-static QDict<void> g_pathsVisited(1009);
+#if MULTITHREADED_INPUT
+static std::mutex g_pathsVisitedMutex;
+#endif
+static StringUnorderedSet g_pathsVisited(1009);
//----------------------------------------------------------------------------
// Read all files matching at least one pattern in 'patList' in the
@@ -9441,8 +9444,12 @@ static int readDir(QFileInfo *fi,
{
dirName = resolveSymlink(dirName.data());
if (dirName.isEmpty()) return 0; // recursive symlink
- if (g_pathsVisited.find(dirName)) return 0; // already visited path
- g_pathsVisited.insert(dirName,(void*)0x8);
+
+#if MULTITHREADED_INPUT
+ std::lock_guard<std::mutex> lock(g_pathsVisitedMutex);
+#endif
+ if (g_pathsVisited.find(dirName.str())!=g_pathsVisited.end()) return 0; // already visited path
+ g_pathsVisited.insert(dirName.str());
}
QDir dir(dirName);
dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
diff --git a/src/fortrancode.l b/src/fortrancode.l
index b2e2e7b..4951001 100644
--- a/src/fortrancode.l
+++ b/src/fortrancode.l
@@ -58,6 +58,7 @@
#include "namespacedef.h"
#include "tooltip.h"
#include "fortrancode.h"
+#include "containers.h"
const int fixedCommentAfter = 72;
@@ -114,10 +115,8 @@ class Scope
{
public:
QCStringList useNames; //!< contains names of used modules
- QDict<void> localVars; //!< contains names of local variables
- QDict<void> externalVars; //!< contains names of external entities
-
- Scope() : localVars(7, FALSE /*caseSensitive*/), externalVars(7, FALSE /*caseSensitive*/) {}
+ StringUnorderedSet localVars; //!< contains names of local variables
+ StringUnorderedSet externalVars; //!< contains names of external entities
};
/*===================================================================*/
@@ -447,7 +446,9 @@ static MemberDef *getFortranDefs(const QCString &memberName, const QCString &mod
Scope *scope;
for (it.toLast();(scope=it.current());--it)
{
- if (scope->localVars.find(memberName) && (!scope->externalVars.find(memberName)))
+ std::string lowMemName = memberName.lower().str();
+ if (scope->localVars.find(lowMemName)!=std::end(scope->localVars) && // local var
+ scope->externalVars.find(lowMemName)==std::end(scope->externalVars)) // and not external
{
return nullptr;
}
@@ -665,8 +666,9 @@ static void addLocalVar(const QCString &varName)
{
if (!scopeStack.isEmpty())
{
- scopeStack.getLast()->localVars.insert(varName, (void*)1);
- if (g_isExternal) scopeStack.getLast()->externalVars.insert(varName, (void*)1);
+ std::string lowVarName = varName.lower().str();
+ scopeStack.getLast()->localVars.insert(lowVarName);
+ if (g_isExternal) scopeStack.getLast()->externalVars.insert(lowVarName);
}
}
diff --git a/src/htmlhelp.cpp b/src/htmlhelp.cpp
index 8ef3d19..a1b0deb 100644
--- a/src/htmlhelp.cpp
+++ b/src/htmlhelp.cpp
@@ -1,12 +1,10 @@
/******************************************************************************
*
- *
- *
- * Copyright (C) 1997-2015 by Dimitri van Heesch.
+ * Copyright (C) 1997-2020 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby
- * granted. No representations are made about the suitability of this software
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
@@ -17,15 +15,14 @@
* Harm van der Heijden.
*/
+#include <algorithm>
+
#include <stdio.h>
#include <stdlib.h>
-#include <qlist.h>
-#include <qdict.h>
#include <qregexp.h>
#include <qfile.h>
+#include <qfileinfo.h>
-#include "qtextcodec.h"
-#include "sortdict.h"
#include "htmlhelp.h"
#include "config.h"
#include "message.h"
@@ -36,12 +33,75 @@
#include "memberdef.h"
#include "filedef.h"
#include "util.h"
+#include "linkedmap.h"
+
+//----------------------------------------------------------------------------
+
+/** Helper class to deal with recoding the UTF8 encoded text back to the native encoding
+ * specified by CHM_INDEX_ENCODING.
+ */
+class HtmlHelpRecoder
+{
+ public:
+ HtmlHelpRecoder() {}
+ ~HtmlHelpRecoder() { finalize(); }
+ HtmlHelpRecoder(const HtmlHelpRecoder &) = delete;
+ HtmlHelpRecoder &operator=(const HtmlHelpRecoder &) = delete;
+
+ void initialize()
+ {
+ const char *str = Config_getString(CHM_INDEX_ENCODING);
+ if (!str) str = "CP1250"; // use safe and likely default
+ m_fromUtf8 = portable_iconv_open(str,"UTF-8");
+ if (m_fromUtf8==m_iconv_null)
+ {
+ term("unsupported character conversion for CHM_INDEX_ENCODING: '%s'->'UTF-8'\n", str);
+ }
+ }
+ void finalize()
+ {
+ if (m_fromUtf8!=m_iconv_null)
+ {
+ portable_iconv_close(m_fromUtf8);
+ m_fromUtf8 = m_iconv_null;
+ }
+ }
+
+ QCString recode(const QCString &s)
+ {
+ int iSize = s.length();
+ int oSize = iSize*4+1;
+ QCString output(oSize);
+ size_t iLeft = iSize;
+ size_t oLeft = oSize;
+ char *iPtr = s.rawData();
+ char *oPtr = output.rawData();
+ if (!portable_iconv(m_fromUtf8,&iPtr,&iLeft,&oPtr,&oLeft))
+ {
+ oSize -= (int)oLeft;
+ output.resize(oSize+1);
+ output.at(oSize)='\0';
+ return output;
+ }
+ else
+ {
+ return s;
+ }
+ }
+ private:
+ void *m_iconv_null = (void*)(-1);
+ void *m_fromUtf8 = m_iconv_null;
+
+};
//----------------------------------------------------------------------------
/** Class representing a field in the HTML help index. */
struct IndexField
{
+ IndexField(const char *k,const char *n,const char *u,const char *a,bool l,bool r) :
+ key(k), name(n), url(u), anchor(a), link(l), reversed(r) {}
+ QCString key;
QCString name;
QCString url;
QCString anchor;
@@ -62,37 +122,35 @@ class IndexFieldSDict : public SDict<IndexField>
}
};
-/** A helper class for HtmlHelp that manages a two level index in
+/** A helper class for HtmlHelp that manages a two level index in
* alphabetical order.
*/
class HtmlHelpIndex
{
public:
- HtmlHelpIndex(HtmlHelp *help);
+ HtmlHelpIndex(HtmlHelpRecoder &recoder);
~HtmlHelpIndex();
- void addItem(const char *first,const char *second,
+ void addItem(const char *first,const char *second,
const char *url, const char *anchor,
bool hasLink,bool reversed);
void writeFields(FTextStream &t);
+ size_t size() const { return m_map.size(); }
private:
- IndexFieldSDict *dict;
- HtmlHelp *m_help;
+ LinkedMap<IndexField> m_map;
+ HtmlHelpRecoder &m_recoder;
};
/*! Constructs a new HtmlHelp index */
-HtmlHelpIndex::HtmlHelpIndex(HtmlHelp *help) : m_help(help)
+HtmlHelpIndex::HtmlHelpIndex(HtmlHelpRecoder &recoder) : m_recoder(recoder)
{
- dict = new IndexFieldSDict;
- dict->setAutoDelete(TRUE);
}
/*! Destroys the HtmlHelp index */
HtmlHelpIndex::~HtmlHelpIndex()
{
- delete dict;
}
-/*! Stores an item in the index if it is not already present.
+/*! Stores an item in the index if it is not already present.
* Items are stored in alphabetical order, by sorting on the
* concatenation of \a level1 and \a level2 (if present).
*
@@ -100,7 +158,7 @@ HtmlHelpIndex::~HtmlHelpIndex()
* \param level2 the string at level 2 in the index (or 0 if not applicable).
* \param url the url of the documentation (without .html extension).
* \param anchor the anchor of the documentation within the page.
- * \param hasLink if true, the url (without anchor) can be used in the
+ * \param hasLink if true, the url (without anchor) can be used in the
* level1 item, when writing the header of a list of level2 items.
* \param reversed TRUE if level1 is the member name and level2 the compound
* name.
@@ -109,30 +167,19 @@ void HtmlHelpIndex::addItem(const char *level1,const char *level2,
const char *url,const char *anchor,bool hasLink,
bool reversed)
{
- QCString key = level1;
+ QCString key = level1;
if (level2) key+= (QCString)"?" + level2;
if (key.find(QRegExp("@[0-9]+"))!=-1) // skip anonymous stuff
{
return;
}
- if (dict->find(key+anchor)==0) // new key
- {
- //printf(">>>>>>>>> HtmlHelpIndex::addItem(%s,%s,%s,%s)\n",
- // level1,level2,url,anchor);
- IndexField *f = new IndexField;
- f->name = key;
- f->url = url;
- f->anchor = anchor;
- f->link = hasLink;
- f->reversed = reversed;
- dict->append(key+anchor,f);
- }
+ m_map.add(key+anchor,key,url,anchor,hasLink,reversed);
}
static QCString field2URL(const IndexField *f,bool checkReversed)
{
QCString result = f->url + Doxygen::htmlFileExtension;
- if (!f->anchor.isEmpty() && (!checkReversed || f->reversed))
+ if (!f->anchor.isEmpty() && (!checkReversed || f->reversed))
{
// HTML Help needs colons in link anchors to be escaped in the .hhk file.
result+="#"+substitute(f->anchor,":","%3A");
@@ -163,28 +210,30 @@ static QCString field2URL(const IndexField *f,bool checkReversed)
* b2 -> link to url#anchor
* a3 -> link to url if hasLink==TRUE
* a4 -> link to url if hasLink==TRUE
- * b1 -> link to url#anchor
+ * b1 -> link to url#anchor
* </pre>
*/
void HtmlHelpIndex::writeFields(FTextStream &t)
{
- dict->sort();
- IndexFieldSDict::Iterator ifli(*dict);
- IndexField *f;
+ std::sort(std::begin(m_map),
+ std::end(m_map),
+ [](const auto &e1,const auto &e2) { return e1->name < e2->name; }
+ );
QCString prevLevel1;
bool level2Started=FALSE;
- for (;(f=ifli.current());++ifli)
+ for (auto it = std::begin(m_map); it!=std::end(m_map); ++it)
{
+ auto &f = *it;
QCString level1,level2;
int i;
if ((i=f->name.find('?'))!=-1)
{
level1 = f->name.left(i);
- level2 = f->name.right(f->name.length()-i-1);
+ level2 = f->name.right(f->name.length()-i-1);
}
else
{
- level1 = f->name.copy();
+ level1 = f->name;
}
{ // finish old list at level 2
@@ -199,25 +248,25 @@ void HtmlHelpIndex::writeFields(FTextStream &t)
// a2, b2
// a2, b3
QCString nextLevel1;
- IndexField* fnext = ++ifli;
- if (fnext)
+ auto it_next = std::next(it);
+ if (it_next!=std::end(m_map))
{
+ auto &fnext = *it_next;
nextLevel1 = fnext->name.left(fnext->name.find('?'));
- --ifli;
}
if (!(level1 == prevLevel1 || level1 == nextLevel1))
{
level2 = "";
}
- prevLevel1 = level1.copy();
+ prevLevel1 = level1;
// </Antony>
if (level2.isEmpty())
{
t << " <LI><OBJECT type=\"text/sitemap\">";
- t << "<param name=\"Local\" value=\"" << field2URL(f,FALSE);
+ t << "<param name=\"Local\" value=\"" << field2URL(f.get(),FALSE);
t << "\">";
- t << "<param name=\"Name\" value=\"" << m_help->recode(level1) << "\">"
+ t << "<param name=\"Name\" value=\"" << m_recoder.recode(level1) << "\">"
"</OBJECT>\n";
}
else
@@ -225,16 +274,16 @@ void HtmlHelpIndex::writeFields(FTextStream &t)
if (f->link)
{
t << " <LI><OBJECT type=\"text/sitemap\">";
- t << "<param name=\"Local\" value=\"" << field2URL(f,TRUE);
+ t << "<param name=\"Local\" value=\"" << field2URL(f.get(),TRUE);
t << "\">";
- t << "<param name=\"Name\" value=\"" << m_help->recode(level1) << "\">"
+ t << "<param name=\"Name\" value=\"" << m_recoder.recode(level1) << "\">"
"</OBJECT>\n";
}
else
{
t << " <LI><OBJECT type=\"text/sitemap\">";
- t << "<param name=\"See Also\" value=\"" << m_help->recode(level1) << "\">";
- t << "<param name=\"Name\" value=\"" << m_help->recode(level1) << "\">"
+ t << "<param name=\"See Also\" value=\"" << m_recoder.recode(level1) << "\">";
+ t << "<param name=\"Name\" value=\"" << m_recoder.recode(level1) << "\">"
"</OBJECT>\n";
}
}
@@ -252,194 +301,185 @@ void HtmlHelpIndex::writeFields(FTextStream &t)
if (level2Started)
{
t << " <LI><OBJECT type=\"text/sitemap\">";
- t << "<param name=\"Local\" value=\"" << field2URL(f,FALSE);
+ t << "<param name=\"Local\" value=\"" << field2URL(f.get(),FALSE);
t << "\">";
- t << "<param name=\"Name\" value=\"" << m_help->recode(level2) << "\">"
+ t << "<param name=\"Name\" value=\"" << m_recoder.recode(level2) << "\">"
"</OBJECT>\n";
}
- }
+ }
if (level2Started) t << " </UL>" << endl;
}
//----------------------------------------------------------------------------
+//
+class HtmlHelp::Private
+{
+ public:
+ Private() : index(recoder) {}
+ void createProjectFile();
+ QFile cf;
+ QFile kf;
+ FTextStream cts,kts;
+ bool ctsItemPresent = false;
+ int dc = 0;
+ StringSet indexFiles;
+ StringSet imageFiles;
+ HtmlHelpIndex index;
+ HtmlHelpRecoder recoder;
+};
-HtmlHelp *HtmlHelp::theInstance = 0;
-/*! Constructs an html object.
- * The object has to be \link initialize() initialized\endlink before it can
+/*! Constructs an html object.
+ * The object has to be \link initialize() initialized\endlink before it can
* be used.
*/
-HtmlHelp::HtmlHelp() : indexFileDict(1009)
+HtmlHelp::HtmlHelp() : p(std::make_unique<Private>())
{
- /* initial depth */
- dc = 0;
- cf = kf = 0;
- index = new HtmlHelpIndex(this);
- m_fromUtf8 = (void *)(-1);
}
HtmlHelp::~HtmlHelp()
{
- if (m_fromUtf8!=(void *)(-1)) portable_iconv_close(m_fromUtf8);
- delete index;
}
-#if 0
-/*! return a reference to the one and only instance of this class.
- */
-HtmlHelp *HtmlHelp::getInstance()
-{
- if (theInstance==0) theInstance = new HtmlHelp;
- return theInstance;
-}
-#endif
-static QDict<QCString> s_languageDict;
+/* language codes for Html help
+ 0x405 Czech
+ 0x406 Danish
+ 0x413 Dutch
+ 0xC09 English (Australia)
+ 0x809 English (Britain)
+ 0x1009 English (Canada)
+ 0x1809 English (Ireland)
+ 0x1409 English (New Zealand)
+ 0x1C09 English (South Africa)
+ 0x409 English (United States)
+ 0x40B Finnish
+ 0x40C French
+ 0x407 German
+ 0x408 Greece
+ 0x40E Hungarian
+ 0x410 Italian
+ 0x814 Norwegian
+ 0x415 Polish
+ 0x816 Portuguese(Portugal)
+ 0x416 Portuguese(Brazil)
+ 0x419 Russian
+ 0x80A Spanish(Mexico)
+ 0xC0A Spanish(Modern Sort)
+ 0x40A Spanish(Traditional Sort)
+ 0x41D Swedish
+ 0x41F Turkey
+ 0x411 Japanese
+ 0x412 Korean
+ 0x804 Chinese (PRC)
+ 0x404 Chinese (Taiwan)
+
+ New LCIDs:
+ 0x421 Indonesian
+ 0x41A Croatian
+ 0x418 Romanian
+ 0x424 Slovenian
+ 0x41B Slovak
+ 0x422 Ukrainian
+ 0x81A Serbian (Serbia, Latin)
+ 0x403 Catalan
+ 0x426 Latvian
+ 0x427 Lithuanian
+ 0x436 Afrikaans
+ 0x42A Vietnamese
+ 0x429 Persian (Iran)
+ 0xC01 Arabic (Egypt) - I don't know which version of arabic is used inside translator_ar.h ,
+ so I have chosen Egypt at random
+
+*/
+static StringUnorderedMap s_languageDict =
+{
+ { "czech", "0x405 Czech" },
+ { "danish", "0x406 Danish" },
+ { "dutch", "0x413 Dutch" },
+ { "finnish", "0x40B Finnish" },
+ { "french", "0x40C French" },
+ { "german", "0x407 German" },
+ { "greek", "0x408 Greece" },
+ { "hungarian", "0x40E Hungarian" },
+ { "italian", "0x410 Italian" },
+ { "norwegian", "0x814 Norwegian" },
+ { "polish", "0x415 Polish" },
+ { "portuguese", "0x816 Portuguese(Portugal)" },
+ { "brazilian", "0x416 Portuguese(Brazil)" },
+ { "russian", "0x419 Russian" },
+ { "spanish", "0x40A Spanish(Traditional Sort)" },
+ { "swedish", "0x41D Swedish" },
+ { "turkish", "0x41F Turkey" },
+ { "japanese", "0x411 Japanese" },
+ { "japanese-en", "0x411 Japanese" },
+ { "korean", "0x412 Korean" },
+ { "korean-en", "0x412 Korean" },
+ { "chinese", "0x804 Chinese (PRC)" },
+ { "chinese-traditional", "0x404 Chinese (Taiwan)" },
+ { "indonesian", "0x421 Indonesian" },
+ { "croatian", "0x41A Croatian" },
+ { "romanian", "0x418 Romanian" },
+ { "slovene", "0x424 Slovenian" },
+ { "slovak", "0x41B Slovak" },
+ { "ukrainian", "0x422 Ukrainian" },
+ { "serbian", "0x81A Serbian (Serbia, Latin)" },
+ { "catalan", "0x403 Catalan" },
+ { "lithuanian", "0x427 Lithuanian" },
+ { "afrikaans", "0x436 Afrikaans" },
+ { "vietnamese", "0x42A Vietnamese" },
+ { "persian", "0x429 Persian (Iran)" },
+ { "arabic", "0xC01 Arabic (Egypt)" },
+ { "latvian", "0x426 Latvian" },
+ { "macedonian", "0x042f Macedonian (Former Yugoslav Republic of Macedonia)" },
+ { "armenian", "0x42b Armenian" },
+ //Code for Esperanto should be as shown below but the htmlhelp compiler 1.3 does not support this
+ // (and no newer version is available).
+ //So do a fallback to the default language (see getLanguageString())
+ //{ "esperanto", "0x48f Esperanto" },
+ { "serbian-cyrillic", "0xC1A Serbian (Serbia, Cyrillic)" }
+};
/*! This will create a contents file (index.hhc) and a index file (index.hhk)
- * and write the header of those files.
+ * and write the header of those files.
* It also creates a project file (index.hhp)
* \sa finalize()
*/
void HtmlHelp::initialize()
{
- const char *str = Config_getString(CHM_INDEX_ENCODING);
- if (!str) str = "CP1250"; // use safe and likely default
- m_fromUtf8 = portable_iconv_open(str,"UTF-8");
- if (m_fromUtf8==(void *)(-1))
- {
- term("unsupported character conversion for CHM_INDEX_ENCODING: '%s'->'UTF-8'\n", str);
- }
+ p->recoder.initialize();
/* open the contents file */
QCString fName = Config_getString(HTML_OUTPUT) + "/index.hhc";
- cf = new QFile(fName);
- if (!cf->open(IO_WriteOnly))
+ p->cf.setName(fName);
+ if (!p->cf.open(IO_WriteOnly))
{
term("Could not open file %s for writing\n",fName.data());
}
/* Write the header of the contents file */
- cts.setDevice(cf);
- cts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
+ p->cts.setDevice(&p->cf);
+ p->cts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
"<HTML><HEAD></HEAD><BODY>\n"
"<OBJECT type=\"text/site properties\">\n"
"<param name=\"FrameName\" value=\"right\">\n"
"</OBJECT>\n"
"<UL>\n";
-
+
/* open the contents file */
fName = Config_getString(HTML_OUTPUT) + "/index.hhk";
- kf = new QFile(fName);
- if (!kf->open(IO_WriteOnly))
+ p->kf.setName(fName);
+ if (!p->kf.open(IO_WriteOnly))
{
term("Could not open file %s for writing\n",fName.data());
}
/* Write the header of the contents file */
- kts.setDevice(kf);
- kts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
+ p->kts.setDevice(&p->kf);
+ p->kts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
"<HTML><HEAD></HEAD><BODY>\n"
"<OBJECT type=\"text/site properties\">\n"
"<param name=\"FrameName\" value=\"right\">\n"
"</OBJECT>\n"
"<UL>\n";
- /* language codes for Html help
- 0x405 Czech
- 0x406 Danish
- 0x413 Dutch
- 0xC09 English (Australia)
- 0x809 English (Britain)
- 0x1009 English (Canada)
- 0x1809 English (Ireland)
- 0x1409 English (New Zealand)
- 0x1C09 English (South Africa)
- 0x409 English (United States)
- 0x40B Finnish
- 0x40C French
- 0x407 German
- 0x408 Greece
- 0x40E Hungarian
- 0x410 Italian
- 0x814 Norwegian
- 0x415 Polish
- 0x816 Portuguese(Portugal)
- 0x416 Portuguese(Brazil)
- 0x419 Russian
- 0x80A Spanish(Mexico)
- 0xC0A Spanish(Modern Sort)
- 0x40A Spanish(Traditional Sort)
- 0x41D Swedish
- 0x41F Turkey
- 0x411 Japanese
- 0x412 Korean
- 0x804 Chinese (PRC)
- 0x404 Chinese (Taiwan)
-
- New LCIDs:
- 0x421 Indonesian
- 0x41A Croatian
- 0x418 Romanian
- 0x424 Slovenian
- 0x41B Slovak
- 0x422 Ukrainian
- 0x81A Serbian (Serbia, Latin)
- 0x403 Catalan
- 0x426 Latvian
- 0x427 Lithuanian
- 0x436 Afrikaans
- 0x42A Vietnamese
- 0x429 Persian (Iran)
- 0xC01 Arabic (Egypt) - I don't know which version of arabic is used inside translator_ar.h ,
- so I have chosen Egypt at random
-
- */
- s_languageDict.setAutoDelete(TRUE);
- s_languageDict.clear();
- s_languageDict.insert("czech", new QCString("0x405 Czech"));
- s_languageDict.insert("danish", new QCString("0x406 Danish"));
- s_languageDict.insert("dutch", new QCString("0x413 Dutch"));
- s_languageDict.insert("finnish", new QCString("0x40B Finnish"));
- s_languageDict.insert("french", new QCString("0x40C French"));
- s_languageDict.insert("german", new QCString("0x407 German"));
- s_languageDict.insert("greek", new QCString("0x408 Greece"));
- s_languageDict.insert("hungarian", new QCString("0x40E Hungarian"));
- s_languageDict.insert("italian", new QCString("0x410 Italian"));
- s_languageDict.insert("norwegian", new QCString("0x814 Norwegian"));
- s_languageDict.insert("polish", new QCString("0x415 Polish"));
- s_languageDict.insert("portuguese", new QCString("0x816 Portuguese(Portugal)"));
- s_languageDict.insert("brazilian", new QCString("0x416 Portuguese(Brazil)"));
- s_languageDict.insert("russian", new QCString("0x419 Russian"));
- s_languageDict.insert("spanish", new QCString("0x40A Spanish(Traditional Sort)"));
- s_languageDict.insert("swedish", new QCString("0x41D Swedish"));
- s_languageDict.insert("turkish", new QCString("0x41F Turkey"));
- s_languageDict.insert("japanese", new QCString("0x411 Japanese"));
- s_languageDict.insert("japanese-en", new QCString("0x411 Japanese"));
- s_languageDict.insert("korean", new QCString("0x412 Korean"));
- s_languageDict.insert("korean-en", new QCString("0x412 Korean"));
- s_languageDict.insert("chinese", new QCString("0x804 Chinese (PRC)"));
- s_languageDict.insert("chinese-traditional", new QCString("0x404 Chinese (Taiwan)"));
-
- // new LCIDs
- s_languageDict.insert("indonesian", new QCString("0x421 Indonesian"));
- s_languageDict.insert("croatian", new QCString("0x41A Croatian"));
- s_languageDict.insert("romanian", new QCString("0x418 Romanian"));
- s_languageDict.insert("slovene", new QCString("0x424 Slovenian"));
- s_languageDict.insert("slovak", new QCString("0x41B Slovak"));
- s_languageDict.insert("ukrainian", new QCString("0x422 Ukrainian"));
- s_languageDict.insert("serbian", new QCString("0x81A Serbian (Serbia, Latin)"));
- s_languageDict.insert("catalan", new QCString("0x403 Catalan"));
- s_languageDict.insert("lithuanian", new QCString("0x427 Lithuanian"));
- s_languageDict.insert("afrikaans", new QCString("0x436 Afrikaans"));
- s_languageDict.insert("vietnamese", new QCString("0x42A Vietnamese"));
- s_languageDict.insert("persian", new QCString("0x429 Persian (Iran)"));
- s_languageDict.insert("arabic", new QCString("0xC01 Arabic (Egypt)"));
- s_languageDict.insert("latvian", new QCString("0x426 Latvian"));
- s_languageDict.insert("macedonian", new QCString("0x042f Macedonian (Former Yugoslav Republic of Macedonia)"));
- s_languageDict.insert("armenian", new QCString("0x42b Armenian"));
- //Code for Esperanto should be as shown below but the htmlhelp compiler 1.3 does not support this
- // (and no newer version is available).
- //So do a fallback to the default language (see getLanguageString())
- //s_languageDict.insert("esperanto", new QCString("0x48f Esperanto"));
- s_languageDict.insert("serbian-cyrillic", new QCString("0xC1A Serbian (Serbia, Cyrillic)"));
}
@@ -447,19 +487,19 @@ QCString HtmlHelp::getLanguageString()
{
if (!theTranslator->idLanguage().isEmpty())
{
- QCString *s = s_languageDict[theTranslator->idLanguage()];
- if (s)
+ auto it = s_languageDict.find(theTranslator->idLanguage().str());
+ if (it!=s_languageDict.end())
{
- return *s;
+ return it->second;
}
}
// default language
return "0x409 English (United States)";
}
-
-void HtmlHelp::createProjectFile()
+
+void HtmlHelp::Private::createProjectFile()
{
/* Write the project file */
QCString fName = Config_getString(HTML_OUTPUT) + "/index.hhp";
@@ -467,7 +507,13 @@ void HtmlHelp::createProjectFile()
if (f.open(IO_WriteOnly))
{
FTextStream t(&f);
-
+
+ const char *hhcFile = "\"index.hhc\"";
+ const char *hhkFile = "\"index.hhk\"";
+ bool hhkPresent = index.size()>0;
+ if (!ctsItemPresent) hhcFile = "";
+ if (!hhkPresent) hhkFile = "";
+
QCString indexName="index"+Doxygen::htmlFileExtension;
t << "[OPTIONS]\n";
if (!Config_getString(CHM_FILE).isEmpty())
@@ -475,16 +521,16 @@ void HtmlHelp::createProjectFile()
t << "Compiled file=" << Config_getString(CHM_FILE) << "\n";
}
t << "Compatibility=1.1\n"
- "Full-text search=Yes\n"
- "Contents file=index.hhc\n"
- "Default Window=main\n"
- "Default topic=" << indexName << "\n"
- "Index file=index.hhk\n"
- "Language=" << getLanguageString() << endl;
+ "Full-text search=Yes\n";
+ if (ctsItemPresent) t << "Contents file=index.hhc\n";
+ t << "Default Window=main\n"
+ "Default topic=" << indexName << "\n";
+ if (hhkPresent) t << "Index file=index.hhk\n";
+ t << "Language=" << getLanguageString() << endl;
if (Config_getBool(BINARY_TOC)) t << "Binary TOC=YES\n";
if (Config_getBool(GENERATE_CHI)) t << "Create CHI file=YES\n";
- t << "Title=" << recode(Config_getString(PROJECT_NAME)) << endl << endl;
-
+ t << "Title=" << recoder.recode(Config_getString(PROJECT_NAME)) << endl << endl;
+
t << "[WINDOWS]" << endl;
// NOTE: the 0x10387e number is a set of bits specifying the buttons
@@ -499,28 +545,25 @@ void HtmlHelp::createProjectFile()
// Value has been taken from htmlhelp.h file of the HTML Help Workshop
if (Config_getBool(BINARY_TOC))
{
- t << "main=\"" << recode(Config_getString(PROJECT_NAME)) << "\",\"index.hhc\","
- "\"index.hhk\",\"" << indexName << "\",\"" <<
+ t << "main=\"" << recoder.recode(Config_getString(PROJECT_NAME)) << "\"," << hhcFile << ","
+ << hhkFile << ",\"" << indexName << "\",\"" <<
indexName << "\",,,,,0x23520,,0x70387e,,,,,,,,0" << endl << endl;
}
else
{
- t << "main=\"" << recode(Config_getString(PROJECT_NAME)) << "\",\"index.hhc\","
- "\"index.hhk\",\"" << indexName << "\",\"" <<
+ t << "main=\"" << recoder.recode(Config_getString(PROJECT_NAME)) << "\"," << hhcFile << ","
+ << hhkFile << ",\"" << indexName << "\",\"" <<
indexName << "\",,,,,0x23520,,0x10387e,,,,,,,,0" << endl << endl;
}
-
+
t << "[FILES]" << endl;
- char *s = indexFiles.first();
- while (s)
+ for (auto &s : indexFiles)
{
- t << s << endl;
- s = indexFiles.next();
+ t << s.c_str() << endl;
}
- uint i;
- for (i=0;i<imageFiles.count();i++)
+ for (auto &s : imageFiles)
{
- t << imageFiles.at(i) << endl;
+ t << QFileInfo(s.c_str()).fileName().data() << endl;
}
f.close();
}
@@ -532,11 +575,7 @@ void HtmlHelp::createProjectFile()
void HtmlHelp::addIndexFile(const char *s)
{
- if (indexFileDict.find(s)==0)
- {
- indexFiles.append(s);
- indexFileDict.insert(s,(void *)0x8);
- }
+ p->indexFiles.insert(s);
}
/*! Finalizes the HTML help. This will finish and close the
@@ -546,36 +585,35 @@ void HtmlHelp::addIndexFile(const char *s)
void HtmlHelp::finalize()
{
// end the contents file
- cts << "</UL>\n";
- cts << "</BODY>\n";
- cts << "</HTML>\n";
- cts.unsetDevice();
- cf->close();
- delete cf;
-
- index->writeFields(kts);
-
+ p->cts << "</UL>\n";
+ p->cts << "</BODY>\n";
+ p->cts << "</HTML>\n";
+ p->cts.unsetDevice();
+ p->cf.close();
+
+ p->index.writeFields(p->kts);
+
// end the index file
- kts << "</UL>\n";
- kts << "</BODY>\n";
- kts << "</HTML>\n";
- kts.unsetDevice();
- kf->close();
- delete kf;
-
- createProjectFile();
- s_languageDict.clear();
+ p->kts << "</UL>\n";
+ p->kts << "</BODY>\n";
+ p->kts << "</HTML>\n";
+ p->kts.unsetDevice();
+ p->kf.close();
+
+ p->createProjectFile();
+
+ p->recoder.finalize();
}
-/*! Increase the level of the contents hierarchy.
+/*! Increase the level of the contents hierarchy.
* This will start a new unnumbered HTML list in contents file.
* \sa decContentsDepth()
*/
void HtmlHelp::incContentsDepth()
{
- int i; for (i=0;i<dc+1;i++) cts << " ";
- cts << "<UL>\n";
- ++dc;
+ int i; for (i=0;i<p->dc+1;i++) p->cts << " ";
+ p->cts << "<UL>\n";
+ ++p->dc;
}
/*! Decrease the level of the contents hierarchy.
@@ -584,31 +622,9 @@ void HtmlHelp::incContentsDepth()
*/
void HtmlHelp::decContentsDepth()
{
- int i; for (i=0;i<dc;i++) cts << " ";
- cts << "</UL>\n";
- --dc;
-}
-
-QCString HtmlHelp::recode(const QCString &s)
-{
- int iSize = s.length();
- int oSize = iSize*4+1;
- QCString output(oSize);
- size_t iLeft = iSize;
- size_t oLeft = oSize;
- char *iPtr = s.rawData();
- char *oPtr = output.rawData();
- if (!portable_iconv(m_fromUtf8,&iPtr,&iLeft,&oPtr,&oLeft))
- {
- oSize -= (int)oLeft;
- output.resize(oSize+1);
- output.at(oSize)='\0';
- return output;
- }
- else
- {
- return s;
- }
+ int i; for (i=0;i<p->dc;i++) p->cts << " ";
+ p->cts << "</UL>\n";
+ --p->dc;
}
/*! Add an list item to the contents file.
@@ -623,53 +639,54 @@ QCString HtmlHelp::recode(const QCString &s)
*/
void HtmlHelp::addContentsItem(bool isDir,
const char *name,
- const char * /*ref*/,
+ const char * /*ref*/,
const char *file,
const char *anchor,
bool /* separateIndex */,
bool /* addToNavIndex */,
const Definition * /* def */)
{
- // If we're using a binary toc then folders cannot have links.
+ // If we're using a binary toc then folders cannot have links.
// Tried this and I didn't see any problems, when not using
// the resetting of file and anchor the TOC works better
// (prev / next button)
- //if(Config_getBool(BINARY_TOC) && isDir)
+ //if(Config_getBool(BINARY_TOC) && isDir)
//{
//file = 0;
//anchor = 0;
//}
- int i; for (i=0;i<dc;i++) cts << " ";
- cts << "<LI><OBJECT type=\"text/sitemap\">";
- cts << "<param name=\"Name\" value=\"" << convertToHtml(recode(name),TRUE) << "\">";
+ p->ctsItemPresent = true;
+ int i; for (i=0;i<p->dc;i++) p->cts << " ";
+ p->cts << "<LI><OBJECT type=\"text/sitemap\">";
+ p->cts << "<param name=\"Name\" value=\"" << convertToHtml(p->recoder.recode(name),TRUE) << "\">";
if (file) // made file optional param - KPW
{
if (file && (file[0]=='!' || file[0]=='^')) // special markers for user defined URLs
{
- cts << "<param name=\"";
- if (file[0]=='^') cts << "URL"; else cts << "Local";
- cts << "\" value=\"";
- cts << &file[1];
+ p->cts << "<param name=\"";
+ if (file[0]=='^') p->cts << "URL"; else p->cts << "Local";
+ p->cts << "\" value=\"";
+ p->cts << &file[1];
}
else
{
- cts << "<param name=\"Local\" value=\"";
- cts << file << Doxygen::htmlFileExtension;
- if (anchor) cts << "#" << anchor;
+ p->cts << "<param name=\"Local\" value=\"";
+ p->cts << file << Doxygen::htmlFileExtension;
+ if (anchor) p->cts << "#" << anchor;
}
- cts << "\">";
+ p->cts << "\">";
}
- cts << "<param name=\"ImageNumber\" value=\"";
+ p->cts << "<param name=\"ImageNumber\" value=\"";
if (isDir) // added - KPW
{
- cts << (int)BOOK_CLOSED ;
+ p->cts << (int)BOOK_CLOSED ;
}
else
{
- cts << (int)TEXT;
+ p->cts << (int)TEXT;
}
- cts << "\">";
- cts << "</OBJECT>\n";
+ p->cts << "\">";
+ p->cts << "</OBJECT>\n";
}
@@ -695,18 +712,18 @@ void HtmlHelp::addIndexItem(const Definition *context,const MemberDef *md,
QCString contRef = separateMemberPages ? cfname : cfiname;
QCString memRef = cfname;
QCString anchor = sectionAnchor ? QCString(sectionAnchor) : md->anchor();
- index->addItem(level1,level2,contRef,anchor,TRUE,FALSE);
- index->addItem(level2,level1,memRef,anchor,TRUE,TRUE);
+ p->index.addItem(level1,level2,contRef,anchor,TRUE,FALSE);
+ p->index.addItem(level2,level1,memRef,anchor,TRUE,TRUE);
}
else if (context)
{
QCString level1 = word ? QCString(word) : context->name();
- index->addItem(level1,0,context->getOutputFileBase(),sectionAnchor,TRUE,FALSE);
+ p->index.addItem(level1,0,context->getOutputFileBase(),sectionAnchor,TRUE,FALSE);
}
}
void HtmlHelp::addImageFile(const char *fileName)
{
- if (!imageFiles.contains(fileName)) imageFiles.append(fileName);
+ p->imageFiles.insert(fileName);
}
diff --git a/src/htmlhelp.h b/src/htmlhelp.h
index 184b929..421320e 100644
--- a/src/htmlhelp.h
+++ b/src/htmlhelp.h
@@ -1,12 +1,10 @@
/******************************************************************************
*
- *
- *
- * Copyright (C) 1997-2015 by Dimitri van Heesch.
+ * Copyright (C) 1997-2020 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby
- * granted. No representations are made about the suitability of this software
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
@@ -21,14 +19,10 @@
#ifndef HTMLHELP_H
#define HTMLHELP_H
-#include <qstrlist.h>
-#include <qdict.h>
+#include <memory>
#include "index.h"
-#include "ftextstream.h"
-class QFile;
class Definition;
-class HtmlHelpIndex;
/** A class that generated the HTML Help specific files.
*
@@ -37,10 +31,10 @@ class HtmlHelpIndex;
*/
class HtmlHelp : public IndexIntf
{
- /*! used in imageNumber param of HTMLHelp::addContentsItem() function
- to specify document icon in tree view.
+ /*! used in imageNumber param of HTMLHelp::addContentsItem() function
+ to specify document icon in tree view.
Writes \<param name="ImageNumber" value="xx"\> in .HHC file. */
- enum ImageNumber {
+ enum ImageNumber {
BOOK_CLOSED=1, BOOK_OPEN,
BOOK_CLOSED_NEW, BOOK_OPEN_NEW,
FOLDER_CLOSED, FOLDER_OPEN,
@@ -72,8 +66,8 @@ class HtmlHelp : public IndexIntf
void incContentsDepth();
void decContentsDepth();
void addContentsItem(bool isDir,
- const char *name,
- const char *ref,
+ const char *name,
+ const char *ref,
const char *file,
const char *anchor,
bool separateIndex,
@@ -87,19 +81,10 @@ class HtmlHelp : public IndexIntf
static QCString getLanguageString();
private:
- friend class HtmlHelpIndex;
- void createProjectFile();
-
- QFile *cf,*kf;
- FTextStream cts,kts;
- HtmlHelpIndex *index;
- int dc;
- QStrList indexFiles;
- QStrList imageFiles;
- QDict<void> indexFileDict;
- static HtmlHelp *theInstance;
+ class Private;
+ std::unique_ptr<Private> p;
QCString recode(const QCString &s);
- void *m_fromUtf8;
+
};
#endif /* HTMLHELP_H */
diff --git a/src/markdown.cpp b/src/markdown.cpp
index 2863669..86727a9 100644
--- a/src/markdown.cpp
+++ b/src/markdown.cpp
@@ -153,8 +153,8 @@ int Trace::s_indent = 0;
// is character at position i in data allowed before an emphasis section
#define isOpenEmphChar(i) \
(data[i]=='\n' || data[i]==' ' || data[i]=='\'' || data[i]=='<' || \
- data[i]=='{' || data[i]=='(' || data[i]=='[' || data[i]==',' || \
- data[i]==':' || data[i]==';')
+ data[i]=='>' || data[i]=='{' || data[i]=='(' || data[i]=='[' || \
+ data[i]==',' || data[i]==':' || data[i]==';')
// is character at position i in data an escape that prevents ending an emphasis section
// so for example *bla (*.txt) is cool*
diff --git a/src/res2cc_cmd.py b/src/res2cc_cmd.py
index 268ae86..f6321f6 100755
--- a/src/res2cc_cmd.py
+++ b/src/res2cc_cmd.py
@@ -116,13 +116,10 @@ def main():
print("#include \"resourcemgr.h\"\n",file=outputFile)
for f in files:
f.writeContents(outputFile)
- print("static Resource resourceDir[] =",file=outputFile)
- print("{",file=outputFile)
+ print("void initResources() { ResourceMgr::instance().registerResources({",file=outputFile)
for f in files:
f.writeDirEntry(outputFile)
- print("};",file=outputFile)
- print("static int resourceDir_len = %s;" % len(files), file=outputFile)
- print("void initResources() { ResourceMgr::instance().registerResources(resourceDir,resourceDir_len); }",file=outputFile)
+ print("});}",file=outputFile)
if __name__ == '__main__':
main()
diff --git a/src/resourcemgr.cpp b/src/resourcemgr.cpp
index 6d2946c..36ce30d 100644
--- a/src/resourcemgr.cpp
+++ b/src/resourcemgr.cpp
@@ -12,7 +12,8 @@
* input used in their production; they are not affected by this license.
*
*/
-#include <qdict.h>
+
+#include <map>
#include <qfile.h>
#include <qcstring.h>
#include <qglobal.h>
@@ -28,8 +29,7 @@
class ResourceMgr::Private
{
public:
- Private() : resources(257) {}
- QDict<Resource> resources;
+ std::map<std::string,Resource> resources;
};
ResourceMgr &ResourceMgr::instance()
@@ -38,37 +38,34 @@ ResourceMgr &ResourceMgr::instance()
return theInstance;
}
-ResourceMgr::ResourceMgr()
+ResourceMgr::ResourceMgr() : p(std::make_unique<Private>())
{
- p = new Private;
}
ResourceMgr::~ResourceMgr()
{
- delete p;
}
-void ResourceMgr::registerResources(const Resource resources[],int numResources)
+void ResourceMgr::registerResources(std::initializer_list<Resource> resources)
{
- for (int i=0;i<numResources;i++)
+ for (auto &res : resources)
{
- p->resources.insert(resources[i].name,&resources[i]);
+ p->resources.insert({res.name,res});
}
}
bool ResourceMgr::writeCategory(const char *categoryName,const char *targetDir) const
{
- QDictIterator<Resource> it(p->resources);
- const Resource *res;
- for (it.toFirst();(res=it.current());++it)
+ for (auto &kv : p->resources)
{
- if (qstrcmp(res->category,categoryName)==0)
+ Resource &res = kv.second;
+ if (qstrcmp(res.category,categoryName)==0)
{
- QCString pathName = QCString(targetDir)+"/"+res->name;
+ QCString pathName = QCString(targetDir)+"/"+res.name;
QFile f(pathName);
- if (!f.open(IO_WriteOnly) || f.writeBlock((const char *)res->data,res->size)!=res->size)
+ if (!f.open(IO_WriteOnly) || f.writeBlock((const char *)res.data,res.size)!=res.size)
{
- err("Failed to write resource '%s' to directory '%s'\n",res->name,targetDir);
+ err("Failed to write resource '%s' to directory '%s'\n",res.name,targetDir);
return FALSE;
}
}
@@ -178,7 +175,9 @@ bool ResourceMgr::copyResource(const char *name,const char *targetDir) const
const Resource *ResourceMgr::get(const char *name) const
{
- return p->resources.find(name);
+ auto it = p->resources.find(name);
+ if (it!=p->resources.end()) return &it->second;
+ return 0;
}
QCString ResourceMgr::getAsString(const char *name) const
diff --git a/src/resourcemgr.h b/src/resourcemgr.h
index 1959ec4..2d7ad9b 100644
--- a/src/resourcemgr.h
+++ b/src/resourcemgr.h
@@ -15,6 +15,9 @@
#ifndef RESOURCEMGR_H
#define RESOURCEMGR_H
+#include <memory>
+#include <initializer_list>
+
#include <qcstring.h>
/** @brief Compiled resource */
@@ -36,7 +39,7 @@ class ResourceMgr
static ResourceMgr &instance();
/** Registers an array of resources */
- void registerResources(const Resource resources[],int numResources);
+ void registerResources(std::initializer_list<Resource> resources);
/** Writes all resource belonging to a given category to a given target directory */
bool writeCategory(const char *categoryName,const char *targetDir) const;
@@ -57,7 +60,7 @@ class ResourceMgr
ResourceMgr();
~ResourceMgr();
class Private;
- Private *p;
+ std::unique_ptr<Private> p;
};
#endif
diff --git a/src/translator.h b/src/translator.h
index 94f5abf..ef642de 100644
--- a/src/translator.h
+++ b/src/translator.h
@@ -652,11 +652,11 @@ class Translator
virtual QCString trDataMemberDocumentation() = 0;
//////////////////////////////////////////////////////////////////////////
-// new since 1.8.19, but completely filled so no need for a TranslatorAdapter_1_8_19
+// new since 1.8.19
//////////////////////////////////////////////////////////////////////////
- /// see for complete list: https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
virtual QCString trISOLang() = 0;
+ virtual QCString trDesignUnitDocumentation() = 0;
};
#endif
diff --git a/src/translator_adapter.h b/src/translator_adapter.h
index fdc68f9..af18ab4 100644
--- a/src/translator_adapter.h
+++ b/src/translator_adapter.h
@@ -41,7 +41,17 @@ class TranslatorAdapterBase : public Translator
};
-class TranslatorAdapter_1_8_15 : public TranslatorAdapterBase
+class TranslatorAdapter_1_8_19 : public TranslatorAdapterBase
+{
+ public:
+ virtual QCString updateNeededMessage()
+ { return createUpdateNeededMessage(idLanguage(),"release 1.8.19"); }
+
+ virtual QCString trDesignUnitDocumentation()
+ { return english.trDesignUnitDocumentation(); }
+};
+
+class TranslatorAdapter_1_8_15 : public TranslatorAdapter_1_8_19
{
public:
virtual QCString updateNeededMessage()
diff --git a/src/translator_br.h b/src/translator_br.h
index 2630435..7135f7e 100644
--- a/src/translator_br.h
+++ b/src/translator_br.h
@@ -49,7 +49,7 @@
#ifndef TRANSLATOR_BR_H
#define TRANSLATOR_BR_H
-class TranslatorBrazilian : public Translator
+class TranslatorBrazilian : public TranslatorAdapter_1_8_19
{
public:
diff --git a/src/translator_de.h b/src/translator_de.h
index 2e23a6d..46eea58 100644
--- a/src/translator_de.h
+++ b/src/translator_de.h
@@ -480,7 +480,7 @@ class TranslatorGerman : public TranslatorAdapter_1_8_15
}
else if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
{
- return "Entwurfseinheiten-Dokumentation";
+ return trDesignUnitDocumentation();
}
else
{
@@ -2246,15 +2246,16 @@ class TranslatorGerman : public TranslatorAdapter_1_8_15
virtual QCString trCustomReference(const char *name)
{ return QCString(name)+"-Referenz"; }
-
//////////////////////////////////////////////////////////////////////////
-// new since 1.8.19, but completely filled so no need for a TranslatorAdapter_1_8_19
+// new since 1.8.19
//////////////////////////////////////////////////////////////////////////
virtual QCString trISOLang()
- {
- return("de");
- }
+ { return("de"); }
+ /** VHDL design unit documentation */
+ virtual QCString trDesignUnitDocumentation()
+ { return "Entwurfseinheiten-Dokumentation"; }
+
};
#endif
diff --git a/src/translator_en.h b/src/translator_en.h
index d1cd7be..611c5fd 100644
--- a/src/translator_en.h
+++ b/src/translator_en.h
@@ -394,6 +394,10 @@ class TranslatorEnglish : public Translator
{
return "Data Structure Documentation";
}
+ else if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
+ {
+ return trDesignUnitDocumentation();
+ }
else
{
return "Class Documentation";
@@ -2246,13 +2250,15 @@ class TranslatorEnglish : public Translator
}
//////////////////////////////////////////////////////////////////////////
-// new since 1.8.19, but completely filled so no need for a TranslatorAdapter_1_8_19
+// new since 1.8.19
//////////////////////////////////////////////////////////////////////////
virtual QCString trISOLang()
- {
- return("en-US");
- }
+ { return("en-US"); }
+ /** VHDL design unit documentation */
+ virtual QCString trDesignUnitDocumentation()
+ { return "Design Unit Documentation"; }
+
};
#endif
diff --git a/src/translator_nl.h b/src/translator_nl.h
index b6625ac..a80bd34 100644
--- a/src/translator_nl.h
+++ b/src/translator_nl.h
@@ -18,7 +18,7 @@
#ifndef TRANSLATOR_NL_H
#define TRANSLATOR_NL_H
-class TranslatorDutch : public Translator
+class TranslatorDutch : public TranslatorAdapter_1_8_19
{
public:
QCString idLanguage()
diff --git a/src/translator_pt.h b/src/translator_pt.h
index b884849..3a9b2be 100644
--- a/src/translator_pt.h
+++ b/src/translator_pt.h
@@ -59,7 +59,7 @@
#define TRANSLATOR_PT_H
-class TranslatorPortuguese : public Translator
+class TranslatorPortuguese : public TranslatorAdapter_1_8_19
{
public:
diff --git a/src/translator_sc.h b/src/translator_sc.h
index 34db617..187dcb9 100644
--- a/src/translator_sc.h
+++ b/src/translator_sc.h
@@ -72,7 +72,7 @@ class TranslatorSerbianCyrillic : public TranslatorAdapter_1_6_0
virtual QCString latexLanguageSupportCommand()
{
return "\\usepackage[T2A]{fontenc}\n"
- "\\usepackage[russian]{babel}\n";
+ "\\usepackage[serbianc]{babel}\n";
}
virtual QCString latexFontenc()
{
diff --git a/src/translator_sv.h b/src/translator_sv.h
index a885344..e409efa 100644
--- a/src/translator_sv.h
+++ b/src/translator_sv.h
@@ -143,7 +143,7 @@ I left use clause untouched as I didn't find a suitable translation for it.
#ifndef TRANSLATOR_SE_H
#define TRANSLATOR_SE_H
-class TranslatorSwedish : public Translator
+class TranslatorSwedish : public TranslatorAdapter_1_8_19
{
public:
diff --git a/src/translator_tr.h b/src/translator_tr.h
index 3fc658b..f7147b8 100644
--- a/src/translator_tr.h
+++ b/src/translator_tr.h
@@ -71,7 +71,7 @@ class TranslatorTurkish : public TranslatorAdapter_1_7_5
*/
virtual QCString latexLanguageSupportCommand()
{
- return "";
+ return "\\usepackage[turkish]{babel}\n";
}
// --- Language translation methods -------------------
diff --git a/src/translator_za.h b/src/translator_za.h
index 43e1e8f..99cd191 100644
--- a/src/translator_za.h
+++ b/src/translator_za.h
@@ -57,9 +57,7 @@ class TranslatorAfrikaans : public TranslatorAdapter_1_6_0
*/
virtual QCString latexLanguageSupportCommand()
{
- //should we use return "\\usepackage[afrikaans]{babel}\n";
- // not sure - for now return an empty string
- return "";
+ return "\\usepackage[afrikaans]{babel}\n";
}
// --- Language translation methods -------------------
diff --git a/testing/055/md_055_markdown.xml b/testing/055/md_055_markdown.xml
index ef15ca4..423a28c 100644
--- a/testing/055/md_055_markdown.xml
+++ b/testing/055/md_055_markdown.xml
@@ -25,6 +25,12 @@
</para>
<para>Dash - NDash <ndash/> MDash <mdash/> EDash - ENDash -- EMDash --- E3Dash --- </para>
</sect2>
+ <sect2 id="md_055_markdown_1autotoc_md3">
+ <title>Markdown in HTML</title>
+ <para>
+ <heading level="3"><bold>Header3</bold> blah <emphasis>blah</emphasis> <computeroutput>blah</computeroutput></heading>
+ </para>
+ </sect2>
</sect1>
</detaileddescription>
</compounddef>
diff --git a/testing/055_markdown.md b/testing/055_markdown.md
index 375040e..695c340 100644
--- a/testing/055_markdown.md
+++ b/testing/055_markdown.md
@@ -22,3 +22,7 @@ More text
[U]: http://example.com/last-line
Dash - NDash -- MDash --- EDash \- ENDash \-- EMDash \--- E3Dash \-\-\-
+
+## Markdown in HTML
+
+<h3>**Header3** blah _blah_ `blah`</h3>
diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt
index 40cb40b..1851c9f 100644
--- a/testing/CMakeLists.txt
+++ b/testing/CMakeLists.txt
@@ -1,9 +1,24 @@
+# run all tests sequentially (keep for backward compatibilty)
add_custom_target(tests
- COMMENT "Running doxygen tests..."
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/testing/runtests.py --doxygen ${PROJECT_BINARY_DIR}/bin/doxygen --inputdir ${CMAKE_SOURCE_DIR}/testing --outputdir ${PROJECT_BINARY_DIR}/testing
- DEPENDS doxygen
-)
-add_test(NAME suite
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/testing/runtests.py --doxygen $<TARGET_FILE:doxygen> --inputdir ${CMAKE_SOURCE_DIR}/testing --outputdir ${PROJECT_BINARY_DIR}/testing
+ COMMENT "Running doxygen tests..."
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/testing/runtests.py --doxygen ${PROJECT_BINARY_DIR}/bin/doxygen --inputdir ${CMAKE_SOURCE_DIR}/testing --outputdir ${PROJECT_BINARY_DIR}/testing
+ DEPENDS doxygen
)
+# get the files in the testing directory starting with 3 digits and an underscore
+if (${CMAKE_VERSION} VERSION_EQUAL "3.11.0" OR ${CMAKE_VERSION} VERSION_GREATER "3.11.0")
+ file(GLOB TEST_FILES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/[0-9][0-9][0-9]_*.*")
+else()
+ file(GLOB TEST_FILES "${CMAKE_CURRENT_SOURCE_DIR}/[0-9][0-9][0-9]_*.*")
+endif()
+
+foreach(TEST_FILE ${TEST_FILES})
+ # extract the test name from the file name
+ string(REGEX REPLACE "^.*/([0-9][0-9][0-9]*.*)\\.[^.]*$" "\\1" TEST_NAME "${TEST_FILE}")
+ # extract the test id from the file name
+ string(REGEX REPLACE "^.*/([0-9][0-9][0-9]*).*$" "\\1" TEST_ID "${TEST_FILE}")
+ # add a test target for each test
+ add_test(NAME ${TEST_NAME}
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/testing/runtests.py --id ${TEST_ID} --doxygen $<TARGET_FILE:doxygen> --inputdir ${CMAKE_SOURCE_DIR}/testing --outputdir ${PROJECT_BINARY_DIR}/testing
+ )
+endforeach()
diff --git a/vhdlparser/VhdlParserTokenManager.cc b/vhdlparser/VhdlParserTokenManager.cc
index d51b004..341469f 100644
--- a/vhdlparser/VhdlParserTokenManager.cc
+++ b/vhdlparser/VhdlParserTokenManager.cc
@@ -3538,6 +3538,11 @@ void VhdlParserTokenManager::SkipLexicalActions(Token *matchedToken){
void VhdlParserTokenManager::TokenLexicalActions(Token *matchedToken){
switch(jjmatchedKind)
{
+ case 14 : {
+ image.append(input_stream->GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ parser->outlineParser()->setLineParsed(ALIAS_T);
+ break;
+ }
case 17 : {
image.append(input_stream->GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
parser->outlineParser()->setLineParsed(ARCHITECTURE_T);
diff --git a/vhdlparser/vhdlparser.jj b/vhdlparser/vhdlparser.jj
index 007bd5b..177b5f4 100755
--- a/vhdlparser/vhdlparser.jj
+++ b/vhdlparser/vhdlparser.jj
@@ -143,7 +143,7 @@ TOKEN [IGNORE_CASE] :
<ABS_T: "abs">
| <ACCESS_T: "access">
| <AFTER_T: "after">
-| <ALIAS_T: "alias">
+| <ALIAS_T: "alias"> {parser->outlineParser()->setLineParsed(ALIAS_T);}
| <ALL_T: "all">
| <AND_T: "and">
| <ARCHITECTURE_T: "architecture"> {parser->outlineParser()->setLineParsed(ARCHITECTURE_T);}