summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/classdef.cpp98
-rw-r--r--src/code.l1
-rw-r--r--src/commentcnv.l1
-rw-r--r--src/commentscan.l2
-rw-r--r--src/config.xml23
-rw-r--r--src/configimpl.l59
-rw-r--r--src/context.cpp2
-rw-r--r--src/debug.cpp3
-rw-r--r--src/debug.h3
-rw-r--r--src/defargs.l1
-rw-r--r--src/definition.cpp64
-rw-r--r--src/docbookgen.cpp1
-rw-r--r--src/docparser.cpp52
-rw-r--r--src/docsets.cpp2
-rw-r--r--src/doctokenizer.l51
-rw-r--r--src/doxygen.cpp246
-rw-r--r--src/fortranscanner.l4
-rw-r--r--src/groupdef.cpp15
-rw-r--r--src/growbuf.h10
-rw-r--r--src/htmlgen.cpp3
-rw-r--r--src/htmlhelp.cpp12
-rw-r--r--src/index.cpp9
-rw-r--r--src/layout.h1
-rw-r--r--src/mangen.cpp1
-rw-r--r--src/markdown.cpp44
-rw-r--r--src/memberdef.cpp319
-rw-r--r--src/memberdef.h1
-rw-r--r--src/memberlist.cpp2
-rw-r--r--src/message.cpp63
-rw-r--r--src/message.h1
-rw-r--r--src/pagedef.cpp4
-rw-r--r--src/perlmodgen.cpp2
-rw-r--r--src/pre.l133
-rw-r--r--src/regex.cpp736
-rw-r--r--src/regex.h336
-rw-r--r--src/rtfgen.cpp2
-rw-r--r--src/rtfstyle.cpp211
-rw-r--r--src/rtfstyle.h4
-rw-r--r--src/scanner.l41
-rw-r--r--src/searchindex.cpp11
-rw-r--r--src/sqlite3gen.cpp2
-rw-r--r--src/symbolresolver.cpp2
-rw-r--r--src/template.cpp36
-rw-r--r--src/util.cpp824
-rw-r--r--src/util.h25
-rw-r--r--src/vhdlcode.l58
-rw-r--r--src/vhdldocgen.cpp173
-rw-r--r--src/vhdldocgen.h2
-rw-r--r--src/vhdljjparser.cpp74
-rw-r--r--src/xmlgen.cpp6
51 files changed, 2457 insertions, 1320 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c6af813..4488067 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -281,6 +281,7 @@ add_library(doxymain STATIC
qhp.cpp
qhpxmlwriter.cpp
reflist.cpp
+ regex.cpp
resourcemgr.cpp
rtfdocvisitor.cpp
rtfgen.cpp
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 625f70f..198a1c9 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -20,7 +20,6 @@
#include <qfile.h>
#include <qfileinfo.h>
-#include <qregexp.h>
#include "classdef.h"
#include "classlist.h"
#include "entry.h"
@@ -1627,80 +1626,61 @@ void ClassDefImpl::writeInheritanceGraph(OutputList &ol) const
if (!m_impl->inherits.empty())
{
- ol.startParagraph();
- //parseText(ol,theTranslator->trInherits()+" ");
-
- QCString inheritLine = theTranslator->trInheritsList((int)m_impl->inherits.size());
- QRegExp marker("@[0-9]+");
- int index=0,newIndex,matchLen;
- // now replace all markers in inheritLine with links to the classes
- while ((newIndex=marker.match(inheritLine,index,&matchLen))!=-1)
+ auto replaceFunc = [this,&ol](size_t entryIndex)
{
- ol.parseText(inheritLine.mid(index,newIndex-index));
- bool ok;
- uint entryIndex = inheritLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
- BaseClassDef &bcd=m_impl->inherits.at(entryIndex);
- if (ok)
- {
- ClassDef *cd=bcd.classDef;
+ BaseClassDef &bcd=m_impl->inherits[entryIndex];
+ ClassDef *cd=bcd.classDef;
- // use the class name but with the template arguments as given
- // in the inheritance relation
- QCString displayName = insertTemplateSpecifierInScope(
- cd->displayName(),bcd.templSpecifiers);
+ // use the class name but with the template arguments as given
+ // in the inheritance relation
+ QCString displayName = insertTemplateSpecifierInScope(
+ cd->displayName(),bcd.templSpecifiers);
- if (cd->isLinkable())
- {
- ol.writeObjectLink(cd->getReference(),
- cd->getOutputFileBase(),
- cd->anchor(),
- displayName);
- }
- else
- {
- ol.docify(displayName);
- }
+ if (cd->isLinkable())
+ {
+ ol.writeObjectLink(cd->getReference(),
+ cd->getOutputFileBase(),
+ cd->anchor(),
+ displayName);
}
else
{
- err("invalid marker %d in inherits list!\n",entryIndex);
+ ol.docify(displayName);
}
- index=newIndex+matchLen;
- }
- ol.parseText(inheritLine.right(inheritLine.length()-(uint)index));
+ };
+
+ ol.startParagraph();
+ writeMarkerList(ol,
+ theTranslator->trInheritsList((int)m_impl->inherits.size()).str(),
+ m_impl->inherits.size(),
+ replaceFunc);
ol.endParagraph();
}
// write subclasses
if (!m_impl->inheritedBy.empty())
{
- ol.startParagraph();
- QCString inheritLine = theTranslator->trInheritedByList((int)m_impl->inheritedBy.size());
- QRegExp marker("@[0-9]+");
- int index=0,newIndex,matchLen;
- // now replace all markers in inheritLine with links to the classes
- while ((newIndex=marker.match(inheritLine,index,&matchLen))!=-1)
+
+ auto replaceFunc = [this,&ol](size_t entryIndex)
{
- ol.parseText(inheritLine.mid(index,newIndex-index));
- bool ok;
- uint entryIndex = inheritLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
- BaseClassDef &bcd=m_impl->inheritedBy.at(entryIndex);
- if (ok)
+ BaseClassDef &bcd=m_impl->inheritedBy[entryIndex];
+ ClassDef *cd=bcd.classDef;
+ if (cd->isLinkable())
{
- ClassDef *cd=bcd.classDef;
- if (cd->isLinkable())
- {
- ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),cd->displayName());
- }
- else
- {
- ol.docify(cd->displayName());
- }
- writeInheritanceSpecifier(ol,bcd);
+ ol.writeObjectLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),cd->displayName());
}
- index=newIndex+matchLen;
- }
- ol.parseText(inheritLine.right(inheritLine.length()-(uint)index));
+ else
+ {
+ ol.docify(cd->displayName());
+ }
+ writeInheritanceSpecifier(ol,bcd);
+ };
+
+ ol.startParagraph();
+ writeMarkerList(ol,
+ theTranslator->trInheritedByList((int)m_impl->inheritedBy.size()).str(),
+ m_impl->inheritedBy.size(),
+ replaceFunc);
ol.endParagraph();
}
diff --git a/src/code.l b/src/code.l
index f7e1775..5481fdc 100644
--- a/src/code.l
+++ b/src/code.l
@@ -38,7 +38,6 @@
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
-#include <qregexp.h>
#include <qdir.h>
#include "code.h"
diff --git a/src/commentcnv.l b/src/commentcnv.l
index 817feb3..7a3cda5 100644
--- a/src/commentcnv.l
+++ b/src/commentcnv.l
@@ -29,7 +29,6 @@
#include <stdlib.h>
#include <stack>
-#include <qregexp.h>
#include <qtextstream.h>
#include <qglobal.h>
diff --git a/src/commentscan.l b/src/commentscan.l
index 767b964..faaa1fc 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -592,12 +592,10 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
addOutput(yyscanner,yytext);
}
<Comment>"</summary>" { // start of a .NET XML style detailed description
- setOutput(yyscanner,OutputBrief);
addOutput(yyscanner,yytext);
setOutput(yyscanner,OutputDoc);
}
<Comment>"</remarks>" { // end of a brief or detailed description
-
setOutput(yyscanner,OutputDoc);
addOutput(yyscanner,yytext);
}
diff --git a/src/config.xml b/src/config.xml
index d9b29aa..1474698 100644
--- a/src/config.xml
+++ b/src/config.xml
@@ -1316,22 +1316,33 @@ FILE_VERSION_FILTER = "cleartool desc -fmt \%Vn"
<docs>
<![CDATA[
If the \c WARN_IF_DOC_ERROR tag is set to \c YES, doxygen will generate warnings for
- potential errors in the documentation, such as not documenting some
- parameters in a documented function, or documenting parameters that
+ potential errors in the documentation, such as documenting some
+ parameters in a documented function twice, or documenting parameters that
don't exist or using markup commands wrongly.
]]>
</docs>
</option>
+ <option type='bool' id='WARN_IF_INCOMPLETE_DOC' defval='1'>
+ <docs>
+<![CDATA[
+ If \c WARN_IF_INCOMPLETE_DOC is set to \c YES, doxygen will warn about
+ incomplete function parameter documentation.
+ If set to \c NO, doxygen will accept that some parameters have no
+ documentation without warning.
+]]>
+ </docs>
+ </option>
<option type='bool' id='WARN_NO_PARAMDOC' defval='0'>
<docs>
<![CDATA[
This \c WARN_NO_PARAMDOC option can be enabled to get warnings for
functions that are documented, but have no documentation for their parameters
or return value. If set to \c NO, doxygen will only warn about
- wrong or incomplete parameter documentation, but not about the absence of
+ wrong parameter documentation, but not about the absence of
documentation.
If \ref cfg_extract_all "EXTRACT_ALL" is set to \c YES then this flag will
automatically be disabled.
+ See also \ref cfg_warn_if_incomplete_doc "WARN_IF_INCOMPLETE_DOC"
]]>
</docs>
</option>
@@ -1740,11 +1751,11 @@ to disable this feature.
]]>
</docs>
</option>
- <option type='bool' id='CLANG_ADD_INC_PATHS' setting='USE_LIBCLANG' defval='1'>
+ <option type='bool' id='CLANG_ADD_INC_PATHS' setting='USE_LIBCLANG' depends='CLANG_ASSISTED_PARSING' defval='1'>
<docs>
<![CDATA[
- If clang assisted parsing is enabled and the \c CLANG_ADD_INC_PATHS tag
- is set to \c YES then doxygen will add the directory of each input to the
+ If the \c CLANG_ASSISTED_PARSING tag is set to \c YES and the \c CLANG_ADD_INC_PATHS
+ tag is set to \c YES then doxygen will add the directory of each input to the
include path.
]]>
</docs>
diff --git a/src/configimpl.l b/src/configimpl.l
index 83c4c89..1f9be8d 100644
--- a/src/configimpl.l
+++ b/src/configimpl.l
@@ -29,11 +29,11 @@
#include <qfileinfo.h>
#include <qdir.h>
-#include <qregexp.h>
#include <thread>
#include <algorithm>
+#include "regex.h"
#include "configimpl.h"
#include "version.h"
#include "portable.h"
@@ -1132,25 +1132,35 @@ void ConfigImpl::emptyValueToDefault()
}
}
-static void substEnvVarsInString(QCString &s)
+static void substEnvVarsInString(QCString &str)
{
- static QRegExp re("\\$\\([a-z_A-Z0-9.-]+\\)");
- static QRegExp re2("\\$\\([a-z_A-Z0-9.-]+\\([a-z_A-Z0-9.-]+\\)\\)"); // For e.g. PROGRAMFILES(X86)
- if (s.isEmpty()) return;
- int p=0;
- int i,l;
- //printf("substEnvVarInString(%s) start\n",s.data());
- while ((i=re.match(s,p,&l))!=-1 || (i=re2.match(s,p,&l))!=-1)
+ if (str.isEmpty()) return;
+ auto replace = [](const std::string &s, const reg::Ex &re) -> std::string
{
- //printf("Found environment var s.mid(%d,%d)='%s'\n",i+2,l-3,s.mid(i+2,l-3).data());
- QCString env=Portable::getenv(s.mid(i+2,l-3));
- substEnvVarsInString(env); // recursively expand variables if needed.
- s = s.left(i)+env+s.right(s.length()-i-l);
- p=i+env.length(); // next time start at the end of the expanded string
- }
- s=s.stripWhiteSpace(); // to strip the bogus space that was added when an argument
- // has quotes
- //printf("substEnvVarInString(%s) end\n",s.data());
+ reg::Iterator it(s,re);
+ reg::Iterator end;
+ std::string result;
+ size_t p = 0;
+ for (; it!=end ; ++it)
+ {
+ const auto &match = *it;
+ size_t i = match.position();
+ size_t l = match.length();
+ result+=s.substr(p,i-p);
+ std::string matchContents = match[1].str();
+ QCString env=Portable::getenv(matchContents.c_str()); // get content of $(..) match
+ substEnvVarsInString(env); // recursively expand variables if needed.
+ result+=env.str();
+ p=i+l;
+ }
+ result+=s.substr(p);
+ return result;
+ };
+
+ // match e.g. re1=$(HOME) but also re2=$(PROGRAMFILES(X86))
+ static const reg::Ex re1(R"(\$\((\a[\w.-]*)\))");
+ static const reg::Ex re2(R"(\$\((\a[\w.-]*\(\a[\w.-]*\))\))");
+ str = QCString(replace(replace(str.str(),re1),re2)).stripWhiteSpace();
}
static void substEnvVarsInStrList(StringVector &sl)
@@ -1641,16 +1651,15 @@ void Config::checkAndCorrect()
//------------------------
// check ALIASES
const StringVector &aliasList = Config_getList(ALIASES);
- for (const auto &s : aliasList)
+ for (const auto &alias : aliasList)
{
- QRegExp re1("[a-z_A-Z][a-z_A-Z0-9]*[ \t]*="); // alias without argument
- QRegExp re2("[a-z_A-Z][a-z_A-Z0-9]*{[0-9]+}[ \t]*="); // alias with argument
- QCString alias=s.c_str();
- alias=alias.stripWhiteSpace();
- if (alias.find(re1)!=0 && alias.find(re2)!=0)
+ // match aliases of the form re1='name=' and re2='name{2} ='
+ static const reg::Ex re1(R"(\a\w*\s*=)");
+ static const reg::Ex re2(R"(\a\w*{\d+}\s*=)");
+ if (!reg::search(alias,re1) && !reg::search(alias,re2))
{
err("Illegal ALIASES format '%s'. Use \"name=value\" or \"name{n}=value\", where n is the number of arguments\n",
- alias.data());
+ alias.c_str());
}
}
diff --git a/src/context.cpp b/src/context.cpp
index d2cfa9e..8bdc23c 100644
--- a/src/context.cpp
+++ b/src/context.cpp
@@ -136,7 +136,7 @@ class GenericConstIterator : public TemplateListIntf::ConstIterator
}
void toLast()
{
- m_index=m_list.size()-1;
+ m_index=(int)m_list.size()-1;
}
void toNext()
{
diff --git a/src/debug.cpp b/src/debug.cpp
index c270b47..bc5abb2 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -31,6 +31,7 @@ static std::map< std::string, Debug::DebugMask > s_labels =
{ "functions", Debug::Functions },
{ "variables", Debug::Variables },
{ "preprocessor", Debug::Preprocessor },
+ { "nolineno", Debug::NoLineNo },
{ "classes", Debug::Classes },
{ "commentcnv", Debug::CommentCnv },
{ "commentscan", Debug::CommentScan },
@@ -79,7 +80,7 @@ static int labelToEnumValue(const char *l)
int Debug::setFlag(const char *lab)
{
int retVal = labelToEnumValue(lab);
- curMask = (DebugMask)(curMask | labelToEnumValue(lab));
+ curMask = (DebugMask)(curMask | retVal);
return retVal;
}
diff --git a/src/debug.h b/src/debug.h
index e71595f..5d4717a 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -37,7 +37,8 @@ class Debug
Lex = 0x00002000,
Plantuml = 0x00004000,
FortranFixed2Free = 0x00008000,
- Cite = 0x00010000
+ Cite = 0x00010000,
+ NoLineNo = 0x00020000
};
static void print(DebugMask mask,int prio,const char *fmt,...);
diff --git a/src/defargs.l b/src/defargs.l
index e25c1fe..6846544 100644
--- a/src/defargs.l
+++ b/src/defargs.l
@@ -56,7 +56,6 @@
//#include <iostream.h>
#include <assert.h>
#include <ctype.h>
-#include <qregexp.h>
#include <qcstringlist.h>
#include "defargs.h"
diff --git a/src/definition.cpp b/src/definition.cpp
index 88b5960..70c1839 100644
--- a/src/definition.cpp
+++ b/src/definition.cpp
@@ -21,11 +21,11 @@
#include <string>
#include <ctype.h>
-#include <qregexp.h>
#include "md5.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
+#include "regex.h"
#include "config.h"
#include "definitionimpl.h"
#include "doxygen.h"
@@ -164,7 +164,7 @@ static bool matchExcludedSymbols(const char *name)
{
const StringVector &exclSyms = Config_getList(EXCLUDE_SYMBOLS);
if (exclSyms.empty()) return FALSE; // nothing specified
- QCString symName = name;
+ std::string symName = name;
for (const auto &pat : exclSyms)
{
QCString pattern = pat.c_str();
@@ -176,15 +176,13 @@ static bool matchExcludedSymbols(const char *name)
pattern=pattern.left(pattern.length()-1),forceEnd=TRUE;
if (pattern.find('*')!=-1) // wildcard mode
{
- QRegExp re(substitute(pattern,"*",".*"),TRUE);
- int pl;
- int i = re.match(symName,0,&pl);
- //printf(" %d = re.match(%s) pattern=%s pl=%d len=%d\n",i,symName.data(),pattern.data(),pl,symName.length());
- if (i!=-1) // wildcard match
+ const reg::Ex re(substitute(pattern,"*",".*").str());
+ reg::Match match;
+ if (reg::search(symName,match,re)) // wildcard match
{
- uint ui=(uint)i;
- uint sl=symName.length();
- // check if it is a whole word match
+ size_t ui = match.position();
+ size_t pl = match.length();
+ size_t sl = symName.length();
if ((ui==0 || pattern.at(0)=='*' || (!isId(symName.at(ui-1)) && !forceStart)) &&
(ui+pl==sl || pattern.at(pattern.length()-1)=='*' || (!isId(symName.at(ui+pl)) && !forceEnd))
)
@@ -196,12 +194,12 @@ static bool matchExcludedSymbols(const char *name)
}
else if (!pattern.isEmpty()) // match words
{
- int i = symName.find(pattern);
- if (i!=-1) // we have a match!
+ size_t i = symName.find(pattern);
+ if (i!=std::string::npos) // we have a match!
{
- uint ui=(uint)i;
- uint pl=pattern.length();
- uint sl=symName.length();
+ size_t ui=i;
+ size_t pl=pattern.length();
+ size_t sl=symName.length();
// check if it is a whole word match
if ((ui==0 || (!isId(symName.at(ui-1)) && !forceStart)) &&
(ui+pl==sl || (!isId(symName.at(ui+pl)) && !forceEnd))
@@ -1208,24 +1206,10 @@ void DefinitionImpl::_writeSourceRefList(OutputList &ol,const char *scopeName,
{
auto members = refMapToVector(membersMap);
- ol.startParagraph("reference");
- ol.parseText(text);
- ol.docify(" ");
-
- QCString ldefLine=theTranslator->trWriteList((int)members.size());
-
- QRegExp marker("@[0-9]+");
- uint index=0;
- int matchLen;
- int newIndex;
- // now replace all markers in inheritLine with links to the classes
- while ((newIndex=marker.match(ldefLine,index,&matchLen))!=-1)
+ auto replaceFunc = [this,&members,scopeName,&ol](size_t entryIndex)
{
- bool ok;
- ol.parseText(ldefLine.mid(index,(uint)newIndex-index));
- uint entryIndex = ldefLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
- const MemberDef *md=members.at(entryIndex);
- if (ok && md)
+ const MemberDef *md=members[entryIndex];
+ if (md)
{
QCString scope=md->getScopeString();
QCString name=md->name();
@@ -1340,11 +1324,18 @@ void DefinitionImpl::_writeSourceRefList(OutputList &ol,const char *scopeName,
ol.docify(name);
}
}
- index=(uint)newIndex+matchLen;
- }
- ol.parseText(ldefLine.right(ldefLine.length()-index));
+ };
+
+ ol.startParagraph("reference");
+ ol.parseText(text);
+ ol.docify(" ");
+ writeMarkerList(ol,
+ theTranslator->trWriteList((int)members.size()).str(),
+ members.size(),
+ replaceFunc);
ol.writeString(".");
ol.endParagraph();
+
}
ol.popGeneratorState();
}
@@ -1850,8 +1841,7 @@ QCString abbreviate(const char *s,const char *name)
const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF);
for (const auto &p : briefDescAbbrev)
{
- QCString str = p.c_str();
- str.replace(QRegExp("\\$name"), scopelessName); // replace $name with entity name
+ QCString str = substitute(p.c_str(),"$name",scopelessName); // replace $name with entity name
str += " ";
stripWord(result,str);
}
diff --git a/src/docbookgen.cpp b/src/docbookgen.cpp
index 372a462..984d685 100644
--- a/src/docbookgen.cpp
+++ b/src/docbookgen.cpp
@@ -20,7 +20,6 @@
#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>
-#include <qregexp.h>
#include "docbookgen.h"
#include "doxygen.h"
#include "message.h"
diff --git a/src/docparser.cpp b/src/docparser.cpp
index 5e68c52..6325cd8 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -20,10 +20,10 @@
#include <qfile.h>
#include <qfileinfo.h>
#include <qcstring.h>
-#include <qregexp.h>
#include <ctype.h>
#include <qcstringlist.h>
+#include "regex.h"
#include "doxygen.h"
#include "debug.h"
#include "util.h"
@@ -425,7 +425,7 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type, bool
* member g_memberDef, then a warning is raised (unless warnings
* are disabled altogether).
*/
-static void checkArgumentName(const QCString &name)
+static void checkArgumentName(const std::string &name)
{
if (!Config_getBool(WARN_IF_DOC_ERROR)) return;
if (g_memberDef==0) return; // not a member
@@ -436,11 +436,13 @@ static void checkArgumentName(const QCString &name)
//printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition());
if (al.empty()) return; // no argument list
- static QRegExp re("$?[a-zA-Z0-9_\\x80-\\xFF]+\\.*");
- int p=0,i=0,l;
- while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
+ static const reg::Ex re(R"(\$?\w+\.*)");
+ reg::Iterator it(name,re);
+ reg::Iterator end;
+ for (; it!=end ; ++it)
{
- QCString aName=name.mid(i,l);
+ const auto &match = *it;
+ QCString aName=match.str();
if (lang==SrcLangExt_Fortran) aName=aName.lower();
//printf("aName='%s'\n",aName.data());
bool found=FALSE;
@@ -482,7 +484,6 @@ static void checkArgumentName(const QCString &name)
qPrint(aName), qPrint(scope), qPrint(g_memberDef->name()),
qPrint(alStr), qPrint(inheritedFrom));
}
- p=i+l;
}
}
/*! Collects the return values found with \@retval command
@@ -512,7 +513,7 @@ static void checkRetvalName(const QCString &name)
*/
static void checkUnOrMultipleDocumentedParams()
{
- if (g_memberDef && g_hasParamCommand && Config_getBool(WARN_IF_DOC_ERROR))
+ if (g_memberDef && g_hasParamCommand)
{
const ArgumentList &al=g_memberDef->isDocsForDefinition() ?
g_memberDef->argumentList() :
@@ -544,7 +545,7 @@ static void checkUnOrMultipleDocumentedParams()
if (argName == par) count++;
}
}
- if (count > 1)
+ if ((count > 1) && Config_getBool(WARN_IF_DOC_ERROR))
{
warn_doc_error(g_memberDef->getDefFileName(),
g_memberDef->getDefLine(),
@@ -555,7 +556,7 @@ static void checkUnOrMultipleDocumentedParams()
" has multiple @param documentation sections").data());
}
}
- if (notArgCnt>0)
+ if ((notArgCnt>0) && Config_getBool(WARN_IF_INCOMPLETE_DOC))
{
bool first=TRUE;
QCString errMsg=
@@ -587,10 +588,10 @@ static void checkUnOrMultipleDocumentedParams()
errMsg+=" parameter '"+argName+"'";
}
}
- warn_doc_error(g_memberDef->getDefFileName(),
- g_memberDef->getDefLine(),
- "%s",
- substitute(errMsg,"%","%%").data());
+ warn_incomplete_doc(g_memberDef->getDefFileName(),
+ g_memberDef->getDefLine(),
+ "%s",
+ substitute(errMsg,"%","%%").data());
}
}
}
@@ -872,9 +873,9 @@ static int handleStyleArgument(DocNode *parent,DocNodeList &children,
tok!=TK_ENDLIST
)
{
- static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
+ static const reg::Ex specialChar(R"([.,|()\[\]:;?])");
if (tok==TK_WORD && g_token->name.length()==1 &&
- g_token->name.find(specialChar)!=-1)
+ reg::match(g_token->name.str(),specialChar))
{
// special character that ends the markup command
return tok;
@@ -4518,7 +4519,7 @@ int DocParamList::parse(const QCString &cmdName)
{
warn_doc_error(g_fileName,getDoctokinizerLineNr(),"expected whitespace after \\%s command",
qPrint(saveCmdName));
- retval=0;
+ retval=RetVal_EndParBlock;
goto endparamlist;
}
doctokenizerYYsetStateParam();
@@ -4533,13 +4534,13 @@ int DocParamList::parse(const QCString &cmdName)
handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator));
g_token->name = g_token->name.mid(typeSeparator+1);
g_hasParamCommand=TRUE;
- checkArgumentName(g_token->name);
+ checkArgumentName(g_token->name.str());
((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE;
}
else
{
g_hasParamCommand=TRUE;
- checkArgumentName(g_token->name);
+ checkArgumentName(g_token->name.str());
}
}
else if (m_type==DocParamSect::RetVal)
@@ -4556,14 +4557,17 @@ int DocParamList::parse(const QCString &cmdName)
{
warn_doc_error(g_fileName,getDoctokinizerLineNr(),"unexpected end of comment block while parsing the "
"argument of command %s",qPrint(saveCmdName));
- retval=0;
+ retval=RetVal_EndParBlock;
goto endparamlist;
}
if (tok!=TK_WHITESPACE) /* premature end of comment block */
{
- warn_doc_error(g_fileName,getDoctokinizerLineNr(),"unexpected token in comment block while parsing the "
- "argument of command %s",qPrint(saveCmdName));
- retval=0;
+ if (tok!=TK_NEWPARA) /* empty param description */
+ {
+ warn_doc_error(g_fileName,getDoctokinizerLineNr(),"unexpected token in comment block while parsing the "
+ "argument of command %s",qPrint(saveCmdName));
+ }
+ retval=RetVal_EndParBlock;
goto endparamlist;
}
@@ -4588,7 +4592,7 @@ int DocParamList::parseXml(const QCString &paramName)
if (m_type==DocParamSect::Param)
{
g_hasParamCommand=TRUE;
- checkArgumentName(g_token->name);
+ checkArgumentName(g_token->name.str());
}
else if (m_type==DocParamSect::RetVal)
{
diff --git a/src/docsets.cpp b/src/docsets.cpp
index 4f04623..2911025 100644
--- a/src/docsets.cpp
+++ b/src/docsets.cpp
@@ -201,7 +201,7 @@ void DocSets::finalize()
QCString DocSets::Private::indent()
{
QCString result;
- result.fill(' ',(indentStack.size()+2)*2);
+ result.fill(' ',((int)indentStack.size()+2)*2);
return result;
}
diff --git a/src/doctokenizer.l b/src/doctokenizer.l
index 0c167ca..9bafcab 100644
--- a/src/doctokenizer.l
+++ b/src/doctokenizer.l
@@ -26,10 +26,10 @@
#include <ctype.h>
#include <stack>
+#include <string>
#include <qfile.h>
#include <qstring.h>
-#include <qregexp.h>
#include "doctokenizer.h"
#include "cmdmapper.h"
@@ -41,6 +41,7 @@
#include "doxygen.h"
#include "portable.h"
#include "cite.h"
+#include "regex.h"
#define YY_NO_INPUT 1
#define YY_NO_UNISTD_H 1
@@ -513,9 +514,11 @@ RCSID "$"("Author"|"Date"|"Header"|"Id"|"Locker"|"Log"|"Name"|"RCSfile"|"Revisio
else
{
lineCount(yytext,yyleng);
- QCString text=yytext;
- static QRegExp re("[*+]");
- int listPos = text.findRev(re);
+ std::string text=yytext;
+ static const reg::Ex re(R"([*+][^*+]*$)"); // find last + or *
+ reg::Match match;
+ reg::search(text,match,re);
+ size_t listPos = match.position();
g_token->isEnumList = FALSE;
g_token->id = -1;
g_token->indent = computeIndent(yytext,listPos);
@@ -529,13 +532,13 @@ RCSID "$"("Author"|"Date"|"Header"|"Id"|"Locker"|"Log"|"Name"|"RCSfile"|"Revisio
}
else
{
- QCString text=yytext;
- static QRegExp re("[1-9]");
- int digitPos = text.find(re);
- int dotPos = text.find('.',digitPos);
- g_token->isEnumList = TRUE;
- g_token->id = atoi(QCString(yytext).mid(digitPos,dotPos-digitPos));
- g_token->indent = computeIndent(yytext,digitPos);
+ std::string text=yytext;
+ static const reg::Ex re(R"(\d+)");
+ reg::Match match;
+ reg::search(text,match,re);
+ g_token->isEnumList = true;
+ g_token->id = std::stoul(match.str());
+ g_token->indent = computeIndent(yytext,match.position());
return TK_LISTITEM;
}
}
@@ -556,12 +559,14 @@ RCSID "$"("Author"|"Date"|"Header"|"Id"|"Locker"|"Log"|"Name"|"RCSfile"|"Revisio
else
{
lineCount(yytext,yyleng);
- QCString text=extractPartAfterNewLine(yytext);
- static QRegExp re("[*+]");
- int markPos = text.findRev(re);
+ std::string text=extractPartAfterNewLine(yytext).str();
+ static const reg::Ex re(R"([*+][^*+]*$)"); // find last + or *
+ reg::Match match;
+ reg::search(text,match,re);
+ size_t markPos = match.position();
g_token->isEnumList = FALSE;
g_token->id = -1;
- g_token->indent = computeIndent(text,markPos);
+ g_token->indent = computeIndent(text.c_str(),markPos);
return TK_LISTITEM;
}
}
@@ -573,13 +578,13 @@ RCSID "$"("Author"|"Date"|"Header"|"Id"|"Locker"|"Log"|"Name"|"RCSfile"|"Revisio
else
{
lineCount(yytext,yyleng);
- QCString text=extractPartAfterNewLine(yytext);
- static QRegExp re("[1-9]");
- int digitPos = text.find(re);
- int dotPos = text.find('.',digitPos);
- g_token->isEnumList = TRUE;
- g_token->id = atoi(QCString(text).mid(digitPos,dotPos-digitPos));
- g_token->indent = computeIndent(text,digitPos);
+ std::string text=extractPartAfterNewLine(yytext).str();
+ static const reg::Ex re(R"(\d+)");
+ reg::Match match;
+ reg::search(text,match,re);
+ g_token->isEnumList = true;
+ g_token->id = std::stoul(match.str());
+ g_token->indent = computeIndent(text.c_str(),match.position());
return TK_LISTITEM;
}
}
@@ -808,7 +813,7 @@ RCSID "$"("Author"|"Date"|"Header"|"Id"|"Locker"|"Log"|"Name"|"RCSfile"|"Revisio
}
lineCount(yytext,yyleng);
}
-<St_Para>({BLANK}*(\n|"\\ilinebr"))+{BLANK}*(\n|"\\ilinebr"){BLANK}* {
+<St_Para,St_Param>({BLANK}*(\n|"\\ilinebr"))+{BLANK}*(\n|"\\ilinebr"){BLANK}* {
lineCount(yytext,yyleng);
if (g_insidePre)
{
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index b79e55b..03313ea 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -14,12 +14,12 @@
*/
#include <chrono>
-#include <locale.h>
+#include <clocale>
+#include <locale>
#include <qfileinfo.h>
#include <qfile.h>
#include <qdir.h>
-#include <qregexp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
@@ -105,6 +105,15 @@
#include "threadpool.h"
#include "clangparser.h"
#include "symbolresolver.h"
+#include "regex.h"
+
+#if USE_SQLITE3
+#include <sqlite3.h>
+#endif
+
+#if USE_LIBCLANG
+#include <clang/Basic/Version.h>
+#endif
// provided by the generated file resources.cpp
extern void initResources();
@@ -2211,12 +2220,12 @@ static MemberDef *addVariableToFile(
{
ttype.stripPrefix("struct ");
ttype.stripPrefix("union ");
- static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
- int l,s;
- s = re.match(ttype,0,&l);
- if (s>=0)
+ static const reg::Ex re(R"(\a\w*)");
+ reg::Match match;
+ std::string typ = ttype.str();
+ if (reg::search(typ,match,re))
{
- QCString typeValue = ttype.mid(s,l);
+ QCString typeValue = match.str();
ClassDefMutable *cd = getClassMutable(typeValue);
if (cd)
{
@@ -2423,27 +2432,36 @@ static MemberDef *addVariableToFile(
* \returns -1 if this is not a function pointer variable or
* the index at which the closing brace of (...*name) was found.
*/
-static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
+static int findFunctionPtr(const std::string &type,SrcLangExt lang, int *pLength=0)
{
if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
{
return -1; // Fortran and VHDL do not have function pointers
}
- static const QRegExp re("([^)]*[\\*\\^][^)]*)");
- int i=-1,l;
- int bb=type.find('<');
- int be=type.findRev('>');
- if (!type.isEmpty() && // return type is non-empty
- (i=re.match(type,0,&l))!=-1 && // contains (...*...)
- type.find("operator")==-1 && // not an operator
- (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
- // not a function pointer return type
+
+ static const reg::Ex re(R"(\([^)]*[*^][^)]*\))");
+ reg::Match match;
+ size_t i=std::string::npos;
+ size_t l=0;
+ if (reg::search(type,match,re)) // contains (...*...)
+ {
+ i = match.position();
+ l = match.length();
+ }
+ size_t bb=type.find('<');
+ size_t be=type.rfind('>');
+
+ if (!type.empty() && // return type is non-empty
+ i!=std::string::npos && // contains (...*...)
+ type.find("operator")==std::string::npos && // not an operator
+ (type.find(")(")==std::string::npos || type.find("typedef ")!=std::string::npos) &&
+ // not a function pointer return type
!(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
)
{
- if (pLength) *pLength=l;
- //printf("findFunctionPtr=%d\n",i);
- return i;
+ if (pLength) *pLength=(int)l;
+ //printf("findFunctionPtr=%d\n",(int)i);
+ return (int)i;
}
else
{
@@ -2458,8 +2476,6 @@ static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
*/
static bool isVarWithConstructor(const Entry *root)
{
- static QRegExp initChars("[0-9\"'&*!^]+");
- static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
bool result=FALSE;
bool typeIsClass = false;
bool typePtrType = false;
@@ -2516,9 +2532,12 @@ static bool isVarWithConstructor(const Entry *root)
}
for (const Argument &a : root->argList)
{
+ static const reg::Ex initChars(R"([\d"'&*!^]+)");
+ reg::Match match;
if (!a.name.isEmpty() || !a.defval.isEmpty())
{
- if (a.name.find(initChars)==0)
+ std::string name = a.name.str();
+ if (reg::search(name,match,initChars) && match.position()==0)
{
result=TRUE;
}
@@ -2547,17 +2566,18 @@ static bool isVarWithConstructor(const Entry *root)
result=FALSE; // argument is a typedef
goto done;
}
- if (a.type.find(initChars)==0)
+ std::string atype = a.type.str();
+ if (reg::search(atype,match,initChars) && match.position()==0)
{
result=TRUE; // argument type starts with typical initializer char
goto done;
}
- QCString resType=resolveTypeDef(ctx,a.type);
- if (resType.isEmpty()) resType=a.type;
- int len;
- if (idChars.match(resType,0,&len)==0) // resType starts with identifier
+ std::string resType=resolveTypeDef(ctx,a.type).str();
+ if (resType.empty()) resType=atype;
+ static const reg::Ex idChars(R"(\a\w*)");
+ if (reg::search(resType,match,idChars) && match.position()==0) // resType starts with identifier
{
- resType=resType.left(len);
+ resType=match.str();
//printf("resType=%s\n",resType.data());
if (resType=="int" || resType=="long" || resType=="float" ||
resType=="double" || resType=="char" || resType=="signed" ||
@@ -2604,15 +2624,15 @@ static void addVariable(const Entry *root,int isFuncPtr=-1)
// type="" name="int *" args="(var[10])"
type=name;
- static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
- int l=0;
- int j=0;
- int i=args.isEmpty() ? -1 : reName.match(args,0,&l);
- if (i!=-1)
+ std::string sargs = args.str();
+ static const reg::Ex reName(R"(\a\w*)");
+ reg::Match match;
+ if (reg::search(sargs,match,reName))
{
- name=args.mid(i,l);
- j=args.find(')',i+l)-i-l;
- if (j >= 0) args=args.mid(i+l,j);
+ name = match.str(); // e.g. 'var' in '(var[10])'
+ sargs = match.suffix().str(); // e.g. '[10]) in '(var[10])'
+ size_t j = sargs.find(')');
+ if (j!=std::string::npos) args=sargs.substr(0,j); // extract, e.g '[10]' from '[10])'
}
//printf("new: type='%s' name='%s' args='%s'\n",
// type.data(),name.data(),args.data());
@@ -2620,7 +2640,7 @@ static void addVariable(const Entry *root,int isFuncPtr=-1)
else
{
int i=isFuncPtr;
- if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(type,root->lang); // for typedefs isFuncPtr is not yet set
+ if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(type.str(),root->lang); // for typedefs isFuncPtr is not yet set
Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
if (i!=-1) // function pointer
{
@@ -2862,7 +2882,7 @@ static void buildVarList(const Entry *root)
(root->section==Entry::VARIABLE_SEC // it's a variable
) ||
(root->section==Entry::FUNCTION_SEC && // or maybe a function pointer variable
- (isFuncPtr=findFunctionPtr(root->type,root->lang))!=-1
+ (isFuncPtr=findFunctionPtr(root->type.str(),root->lang))!=-1
) ||
(root->section==Entry::FUNCTION_SEC && // class variable initialized by constructor
isVarWithConstructor(root)
@@ -3027,24 +3047,8 @@ static void addMethodToClass(const Entry *root,ClassDefMutable *cd,
{
FileDef *fd=root->fileDef();
- int l;
- static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
QCString type = rtype;
QCString args = rargs;
- int ts=type.find('<');
- int te=type.findRev('>');
- int i=re.match(type,0,&l);
- if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
- {
- i=-1;
- }
-
- if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
- !type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
- {
- args+=type.right(type.length()-i-l);
- type=type.left(i+l);
- }
QCString name=removeRedundantWhiteSpace(rname);
if (name.left(2)=="::") name=name.right(name.length()-2);
@@ -3057,6 +3061,7 @@ static void addMethodToClass(const Entry *root,ClassDefMutable *cd,
else mtype=MemberType_Function;
// strip redundant template specifier for constructors
+ int i = -1;
int j = -1;
if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
name.left(9)!="operator " && // not operator
@@ -3364,21 +3369,9 @@ static void buildFunctionList(const Entry *root)
}
}
- static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
- int ts=root->type.find('<');
- int te=root->type.findRev('>');
- int ti;
if (!root->parent()->name.isEmpty() &&
(root->parent()->section & Entry::COMPOUND_MASK) &&
- cd &&
- // do some fuzzy things to exclude function pointers
- (root->type.isEmpty() ||
- ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
- (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
- root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
- root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
- cd->getLanguage()!=SrcLangExt_Cpp // language other than C
- )
+ cd
)
{
Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
@@ -3817,25 +3810,26 @@ static void transferRelatedFunctionDocumentation()
* Example: A template class A with template arguments <R,S,T>
* that inherits from B<T,T,S> will have T and S in the dictionary.
*/
-static TemplateNameMap getTemplateArgumentsInName(const ArgumentList &templateArguments,const QCString &name)
+static TemplateNameMap getTemplateArgumentsInName(const ArgumentList &templateArguments,const std::string &name)
{
std::map<std::string,int> templateNames;
- static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
int count=0;
for (const Argument &arg : templateArguments)
{
- int i,p=0,l;
- while ((i=re.match(name,p,&l))!=-1)
+ static const reg::Ex re(R"(\a[\w:]*)");
+ reg::Iterator it(name,re);
+ reg::Iterator end;
+ for (; it!=end ; ++it)
{
- QCString n = name.mid(i,l);
+ const auto &match = *it;
+ std::string n = match.str();
if (n==arg.name)
{
- if (templateNames.find(n.str())==templateNames.end())
+ if (templateNames.find(n)==templateNames.end())
{
- templateNames.insert(std::make_pair(n.str(),count));
+ templateNames.insert(std::make_pair(n,count));
}
}
- p=i+l;
}
}
return templateNames;
@@ -3908,7 +3902,7 @@ static void findUsedClassesForClass(const Entry *root,
QCString templSpec;
bool found=FALSE;
// the type can contain template variables, replace them if present
- type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
+ type = substituteTemplateArgumentsInString(type.str(),formalArgs,actualArgs);
//printf(" template substitution gives=%s\n",type.data());
while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,root->lang)!=-1)
@@ -3938,7 +3932,7 @@ static void findUsedClassesForClass(const Entry *root,
TemplateNameMap formTemplateNames;
if (templateNames.empty())
{
- formTemplateNames = getTemplateArgumentsInName(formalArgs,usedName);
+ formTemplateNames = getTemplateArgumentsInName(formalArgs,usedName.str());
}
BaseInfo bi(usedName,Public,Normal);
findClassRelation(root,context,instanceCd,&bi,formTemplateNames,TemplateInstances,isArtificial);
@@ -4064,10 +4058,10 @@ static void findBaseClassesForClass(
TemplateNameMap formTemplateNames;
if (templateNames.empty())
{
- formTemplateNames = getTemplateArgumentsInName(formalArgs,bi.name);
+ formTemplateNames = getTemplateArgumentsInName(formalArgs,bi.name.str());
}
BaseInfo tbi = bi;
- tbi.name = substituteTemplateArgumentsInString(bi.name,formalArgs,actualArgs);
+ tbi.name = substituteTemplateArgumentsInString(bi.name.str(),formalArgs,actualArgs);
//printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
if (mode==DocumentedOnly)
@@ -4784,7 +4778,7 @@ static void computeTemplateClassRelations()
if (!tl.empty())
{
TemplateNameMap baseClassNames = tcd->getTemplateBaseClassNames();
- TemplateNameMap templateNames = getTemplateArgumentsInName(tl,bi.name);
+ TemplateNameMap templateNames = getTemplateArgumentsInName(tl,bi.name.str());
// for each template name that we inherit from we need to
// substitute the formal with the actual arguments
TemplateNameMap actualTemplateNames;
@@ -4807,7 +4801,7 @@ static void computeTemplateClassRelations()
}
}
- tbi.name = substituteTemplateArgumentsInString(bi.name,tl,templArgs);
+ tbi.name = substituteTemplateArgumentsInString(bi.name.str(),tl,templArgs);
// find a documented base class in the correct scope
if (!findClassRelation(root,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
{
@@ -5327,18 +5321,23 @@ static bool scopeIsTemplate(const Definition *d)
static QCString substituteTemplatesInString(
const ArgumentLists &srcTempArgLists,
const ArgumentLists &dstTempArgLists,
- const QCString &src
+ const std::string &src
)
{
- QCString dst;
- QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
+ std::string dst;
+ static const reg::Ex re(R"(\a\w*)");
+ reg::Iterator it(src,re);
+ reg::Iterator end;
//printf("type=%s\n",sa->type.data());
- int i,p=0,l;
- while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
+ size_t p=0;
+ for (; it!=end ; ++it) // for each word in srcType
{
+ const auto &match = *it;
+ size_t i = match.position();
+ size_t l = match.length();
bool found=FALSE;
- dst+=src.mid(p,i-p);
- QCString name=src.mid(i,l);
+ dst+=src.substr(p,i-p);
+ std::string name=match.str();
auto srcIt = srcTempArgLists.begin();
auto dstIt = dstTempArgLists.begin();
@@ -5381,7 +5380,7 @@ static QCString substituteTemplatesInString(
}
if (!tdaName.isEmpty())
{
- name=tdaName; // substitute
+ name=tdaName.str(); // substitute
found=TRUE;
}
}
@@ -5397,7 +5396,7 @@ static QCString substituteTemplatesInString(
dst+=name;
p=i+l;
}
- dst+=src.right(src.length()-p);
+ dst+=src.substr(p);
//printf(" substituteTemplatesInString(%s)=%s\n",
// src.data(),dst.data());
return dst;
@@ -5413,8 +5412,8 @@ static void substituteTemplatesInArgList(
auto dstIt = dst.begin();
for (const Argument &sa : src)
{
- QCString dstType = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.type);
- QCString dstArray = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.array);
+ QCString dstType = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.type.str());
+ QCString dstArray = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.array.str());
if (dstIt == dst.end())
{
Argument da = sa;
@@ -5436,7 +5435,7 @@ static void substituteTemplatesInArgList(
dst.setPureSpecifier(src.pureSpecifier());
dst.setTrailingReturnType(substituteTemplatesInString(
srcTempArgLists,dstTempArgLists,
- src.trailingReturnType()));
+ src.trailingReturnType().str()));
//printf("substituteTemplatesInArgList: replacing %s with %s\n",
// argListToString(src).data(),argListToString(dst).data()
// );
@@ -6638,7 +6637,7 @@ static void filterMemberDocumentation(const Entry *root,const QCString relates)
QCString type = root->type;
QCString args = root->args;
if ( // detect func variable/typedef to func ptr
- (i=findFunctionPtr(type,root->lang,&l))!=-1
+ (i=findFunctionPtr(type.str(),root->lang,&l))!=-1
)
{
//printf("Fixing function pointer!\n");
@@ -9960,6 +9959,39 @@ static void devUsage()
//----------------------------------------------------------------------------
+// print the version of doxygen
+
+static void version(const bool extended)
+{
+ QCString versionString = getFullVersion();
+ msg("%s\n",versionString.data());
+ if (extended)
+ {
+ QCString extVers;
+#if USE_SQLITE3
+ if (!extVers.isEmpty()) extVers+= ", ";
+ extVers += "sqlite3 ";
+ extVers += sqlite3_libversion();
+#endif
+#if USE_LIBCLANG
+ if (!extVers.isEmpty()) extVers+= ", ";
+ extVers += "clang support ";
+ extVers += CLANG_VERSION_STRING;
+#endif
+#if MULTITHREADED_SOURCE_GENERATOR
+ if (!extVers.isEmpty()) extVers+= ", ";
+ extVers += "multi-threaded support ";
+#endif
+ if (!extVers.isEmpty())
+ {
+ int lastComma = extVers.findRev(',');
+ if (lastComma != -1) extVers = extVers.replace(lastComma,1," and");
+ msg(" with %s.\n",extVers.data());
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
// print the usage of doxygen
static void usage(const char *name,const char *versionString)
@@ -9993,7 +10025,7 @@ static void usage(const char *name,const char *versionString)
msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
msg("If configName is omitted 'Doxyfile' will be used as a default.\n");
msg("If - is used for configFile doxygen will write / read the configuration to /from standard output / input.\n\n");
- msg("-v print version string\n");
+ msg("-v print version string, -V print extended version information\n");
}
//----------------------------------------------------------------------------
@@ -10032,9 +10064,9 @@ void initDoxygen()
initResources();
const char *lang = Portable::getenv("LC_ALL");
if (lang) Portable::setenv("LANG",lang);
- setlocale(LC_ALL,"");
- setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
- setlocale(LC_NUMERIC,"C");
+ std::setlocale(LC_ALL,"");
+ std::setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
+ std::setlocale(LC_NUMERIC,"C");
Portable::correct_path();
@@ -10401,7 +10433,12 @@ void readConfiguration(int argc, char **argv)
g_dumpSymbolMap = TRUE;
break;
case 'v':
- msg("%s\n",versionString.data());
+ version(false);
+ cleanUpDoxygen();
+ exit(0);
+ break;
+ case 'V':
+ version(true);
cleanUpDoxygen();
exit(0);
break;
@@ -10413,7 +10450,14 @@ void readConfiguration(int argc, char **argv)
}
else if (qstrcmp(&argv[optind][2],"version")==0)
{
- msg("%s\n",versionString.data());
+ version(false);
+ cleanUpDoxygen();
+ exit(0);
+ }
+ else if ((qstrcmp(&argv[optind][2],"Version")==0) ||
+ (qstrcmp(&argv[optind][2],"VERSION")==0))
+ {
+ version(true);
cleanUpDoxygen();
exit(0);
}
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 74d6d03..e43e0f4 100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
@@ -56,7 +56,6 @@
#include <assert.h>
#include <ctype.h>
-#include <qregexp.h>
#include <qfile.h>
#include "fortranscanner.h"
@@ -1151,7 +1150,8 @@ private {
if (yyextra->ifType == IF_ABSTRACT || yyextra->ifType == IF_SPECIFIC)
{
- yyextra->current_root->name.replace(QRegExp("\\$interface\\$"), yytext);
+ yyextra->current_root->name = substitute(
+ yyextra->current_root->name, "$interface$", yytext);
}
BEGIN(Parameterlist);
diff --git a/src/groupdef.cpp b/src/groupdef.cpp
index b900148..095069e 100644
--- a/src/groupdef.cpp
+++ b/src/groupdef.cpp
@@ -19,7 +19,6 @@
#include <vector>
#include <ctype.h>
-#include <qregexp.h>
#include "groupdef.h"
#include "classdef.h"
@@ -46,6 +45,7 @@
#include "dirdef.h"
#include "config.h"
#include "definitionimpl.h"
+#include "regex.h"
//---------------------------------------------------------------------------
@@ -1090,12 +1090,15 @@ void GroupDefImpl::writeDocumentation(OutputList &ol)
if (Doxygen::searchIndex)
{
Doxygen::searchIndex->setCurrentDoc(this,anchor(),FALSE);
- static QRegExp we("[a-zA-Z_][-a-zA-Z_0-9]*");
- int i=0,p=0,l=0;
- while ((i=we.match(m_title,p,&l))!=-1) // foreach word in the title
+ std::string title = m_title.str();
+ static const reg::Ex re(R"(\a[\w-]*)");
+ reg::Iterator it(title,re);
+ reg::Iterator end;
+ for (; it!=end ; ++it)
{
- Doxygen::searchIndex->addWord(m_title.mid(i,l),TRUE);
- p=i+l;
+ const auto &match = *it;
+ std::string matchStr = match.str();
+ Doxygen::searchIndex->addWord(matchStr.c_str(),TRUE);
}
}
diff --git a/src/growbuf.h b/src/growbuf.h
index 2f8075b..bb26404 100644
--- a/src/growbuf.h
+++ b/src/growbuf.h
@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
+#include <string>
#define GROW_AMOUNT 1024
@@ -27,6 +28,15 @@ class GrowBuf
m_pos+=l;
}
}
+ void addStr(const std::string &s) {
+ if (!s.empty())
+ {
+ uint l=(uint)s.length();
+ if (m_pos+l>=m_len) { m_len+=l+GROW_AMOUNT; m_str = (char*)realloc(m_str,m_len); }
+ strcpy(&m_str[m_pos],s.c_str());
+ m_pos+=l;
+ }
+ }
void addStr(const char *s) {
if (s)
{
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index c9f7bf2..3f335e5 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -21,7 +21,6 @@
#include <mutex>
#include <qdir.h>
-#include <qregexp.h>
#include "message.h"
#include "htmlgen.h"
#include "config.h"
@@ -1075,7 +1074,7 @@ void HtmlGenerator::startFile(const char *name,const char *,
}
m_lastFile = fileName;
- t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),m_relPath);
+ t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title?title:"")),m_relPath);
t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
<< getDoxygenVersion() << " -->" << endl;
diff --git a/src/htmlhelp.cpp b/src/htmlhelp.cpp
index af511bb..3d88e4f 100644
--- a/src/htmlhelp.cpp
+++ b/src/htmlhelp.cpp
@@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <qregexp.h>
#include <qfile.h>
#include <qfileinfo.h>
@@ -34,6 +33,7 @@
#include "filedef.h"
#include "util.h"
#include "linkedmap.h"
+#include "regex.h"
//----------------------------------------------------------------------------
@@ -154,13 +154,15 @@ void HtmlHelpIndex::addItem(const char *level1,const char *level2,
const char *url,const char *anchor,bool hasLink,
bool reversed)
{
- QCString key = level1;
- if (level2) key+= (QCString)"?" + level2;
- if (key.find(QRegExp("@[0-9]+"))!=-1) // skip anonymous stuff
+ static const reg::Ex re(R"(@\d+)");
+ std::string key = level1;
+ if (level2) key+= std::string("?") + level2;
+ if (reg::search(key,re)) // skip anonymous stuff
{
return;
}
- m_map.add(key+anchor,key,url,anchor,hasLink,reversed);
+ std::string key_anchor = key+anchor;
+ m_map.add(key_anchor.c_str(),key.c_str(),url,anchor,hasLink,reversed);
}
static QCString field2URL(const IndexField *f,bool checkReversed)
diff --git a/src/index.cpp b/src/index.cpp
index 1f425d4..0984ac2 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -26,7 +26,6 @@
#include <assert.h>
#include <qtextstream.h>
#include <qdir.h>
-#include <qregexp.h>
#include "message.h"
#include "index.h"
@@ -3465,7 +3464,7 @@ static void writeExampleIndex(OutputList &ol)
ol.writeObjectLink(0,n,0,pd->title());
if (addToIndex)
{
- Doxygen::indexList->addContentsItem(FALSE,filterTitle(pd->title()),pd->getReference(),n,0,FALSE,TRUE);
+ Doxygen::indexList->addContentsItem(FALSE,filterTitle(pd->title().str()),pd->getReference(),n,0,FALSE,TRUE);
}
}
else
@@ -3516,7 +3515,7 @@ static bool mainPageHasOwnTitle()
QCString title;
if (Doxygen::mainPage)
{
- title = filterTitle(Doxygen::mainPage->title());
+ title = filterTitle(Doxygen::mainPage->title().str());
}
return !projectName.isEmpty() && mainPageHasTitle() && qstricmp(title,projectName)!=0;
}
@@ -3538,7 +3537,7 @@ static void writePages(const PageDef *pd,FTVHelp *ftv)
if (pd->title().isEmpty())
pageTitle=pd->name();
else
- pageTitle=filterTitle(pd->title());
+ pageTitle=filterTitle(pd->title().str());
if (ftv)
{
@@ -4094,7 +4093,7 @@ static void writeIndex(OutputList &ol)
}
else if (Doxygen::mainPage)
{
- title = filterTitle(Doxygen::mainPage->title());
+ title = filterTitle(Doxygen::mainPage->title().str());
}
QCString indexName="index";
diff --git a/src/layout.h b/src/layout.h
index 4dce583..851af22 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -26,7 +26,6 @@
class LayoutParser;
struct LayoutNavEntry;
class MemberList;
-class QTextStream;
/** @brief Base class representing a piece of a documentation page */
struct LayoutDocEntry
diff --git a/src/mangen.cpp b/src/mangen.cpp
index e58aa6e..9139aa8 100644
--- a/src/mangen.cpp
+++ b/src/mangen.cpp
@@ -445,7 +445,6 @@ void ManGenerator::startDoxyAnchor(const char *,const char *manName,
{
FTextStream linkstream;
linkstream.setDevice(&linkfile);
- //linkstream.setEncoding(QTextStream::UnicodeUTF8);
linkstream << ".so " << getSubdir() << "/" << buildFileName( manName ) << endl;
}
}
diff --git a/src/markdown.cpp b/src/markdown.cpp
index 2bc8206..185a43e 100644
--- a/src/markdown.cpp
+++ b/src/markdown.cpp
@@ -33,7 +33,6 @@
#include <stdio.h>
#include <qglobal.h>
-#include <qregexp.h>
#include <qfileinfo.h>
#include <unordered_map>
@@ -51,6 +50,7 @@
#include "section.h"
#include "message.h"
#include "portable.h"
+#include "regex.h"
#if !defined(NDEBUG)
#define ENABLE_TRACING
@@ -213,6 +213,26 @@ inline int isNewline(const char *data)
return 0;
}
+// escape double quotes in string
+static QCString escapeDoubleQuotes(const QCString &s)
+{
+ TRACE(s.data());
+ if (s.isEmpty()) return "";
+ GrowBuf growBuf;
+ const char *p=s;
+ char c,pc='\0';
+ while ((c=*p++))
+ {
+ switch (c)
+ {
+ case '"': if (pc!='\\') { growBuf.addChar('\\'); } growBuf.addChar(c); break;
+ default: growBuf.addChar(c); break;
+ }
+ pc=c;
+ }
+ growBuf.addChar(0);
+ return growBuf.get();
+}
// escape characters that have a special meaning later on.
static QCString escapeSpecialChars(const QCString &s)
{
@@ -775,13 +795,13 @@ void Markdown::writeMarkdownImage(const char *fmt, bool explicitTitle,
if (!explicitTitle && !content.isEmpty())
{
m_out.addStr(" \"");
- m_out.addStr(content);
+ m_out.addStr(escapeDoubleQuotes(content));
m_out.addStr("\"");
}
else if ((content.isEmpty() || explicitTitle) && !title.isEmpty())
{
m_out.addStr(" \"");
- m_out.addStr(title);
+ m_out.addStr(escapeDoubleQuotes(title));
m_out.addStr("\"");
}
else
@@ -1451,15 +1471,15 @@ static int isHRuler(const char *data,int size)
static QCString extractTitleId(QCString &title, int level)
{
TRACE(title.data());
- //static QRegExp r1("^[a-z_A-Z][a-z_A-Z0-9\\-]*:");
- static QRegExp r2("\\{#[a-z_A-Z][a-z_A-Z0-9\\-]*\\}");
- int l=0;
- int i = r2.match(title,0,&l);
- if (i!=-1 && title.mid(i+l).stripWhiteSpace().isEmpty()) // found {#id} style id
- {
- QCString id = title.mid(i+2,l-3);
- title = title.left(i);
- //printf("found id='%s' title='%s'\n",id.data(),title.data());
+ // match e.g. '{#id-b11} ' and capture 'id-b11'
+ static const reg::Ex r2(R"({#(\a[\w-]*)}\s*$)");
+ reg::Match match;
+ std::string ti = title.str();
+ if (reg::search(ti,match,r2))
+ {
+ std::string id = match[1].str();
+ title = title.left((int)match.position());
+ //printf("found match id='%s' title=%s\n",id.c_str(),title.data());
return id;
}
if ((level > 0) && (level <= Config_getInt(TOC_INCLUDE_HEADINGS)))
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index 7e58331..c357c43 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -13,10 +13,11 @@
*
*/
+
#include <stdio.h>
#include <qglobal.h>
-#include <qregexp.h>
#include <assert.h>
+
#include "md5.h"
#include "memberdef.h"
#include "membername.h"
@@ -36,7 +37,6 @@
#include "dotcallgraph.h"
#include "searchindex.h"
#include "parserintf.h"
-
#include "vhdldocgen.h"
#include "arguments.h"
#include "memberlist.h"
@@ -44,6 +44,7 @@
#include "filedef.h"
#include "config.h"
#include "definitionimpl.h"
+#include "regex.h"
//-----------------------------------------------------------------------------
@@ -920,27 +921,12 @@ static bool writeDefArgumentList(OutputList &ol,const Definition *scope,const Me
ol.startParameterName(TRUE);
}
}
- QRegExp re(")("),res("(.*\\*");
- int vp=a.type.find(re);
- int wp=a.type.find(res);
-
- // use the following to put the function pointer type before the name
- bool hasFuncPtrType=FALSE;
if (!a.attrib.isEmpty() && !md->isObjCMethod()) // argument has an IDL attribute
{
ol.docify(a.attrib+" ");
}
- if (hasFuncPtrType) // argument type is a function pointer
- {
- //printf("a.type='%s' a.name='%s'\n",a.type.data(),a.name.data());
- QCString n=a.type.left(vp);
- if (hasFuncPtrType) n=a.type.left(wp);
- if (md->isObjCMethod()) { n.prepend("("); n.append(")"); }
- if (!cName.isEmpty()) n=addTemplateNames(n,scope->name(),cName);
- linkifyText(TextGeneratorOLImpl(ol),scope,md->getBodyDef(),md,n);
- }
- else // non-function pointer type
+
{
QCString n=a.type;
if (md->isObjCMethod()) { n.prepend("("); n.append(")"); }
@@ -950,6 +936,7 @@ static bool writeDefArgumentList(OutputList &ol,const Definition *scope,const Me
linkifyText(TextGeneratorOLImpl(ol),scope,md->getBodyDef(),md,n);
}
}
+
if (!isDefine)
{
if (paramTypeStarted)
@@ -959,16 +946,8 @@ static bool writeDefArgumentList(OutputList &ol,const Definition *scope,const Me
}
ol.startParameterName(defArgList.size()<2);
}
- if (hasFuncPtrType)
- {
- ol.docify(a.type.mid(wp,vp-wp));
- }
if (!a.name.isEmpty() || a.type=="...") // argument has a name
{
- //if (!hasFuncPtrType)
- //{
- // ol.docify(" ");
- //}
ol.disable(OutputGenerator::Latex);
ol.disable(OutputGenerator::Docbook);
ol.disable(OutputGenerator::Html);
@@ -992,12 +971,6 @@ static bool writeDefArgumentList(OutputList &ol,const Definition *scope,const Me
{
ol.docify(a.array);
}
- if (hasFuncPtrType) // write the part of the argument type
- // that comes after the name
- {
- linkifyText(TextGeneratorOLImpl(ol),scope,md->getBodyDef(),
- md,a.type.right(a.type.length()-vp));
- }
if (!a.defval.isEmpty()) // write the default value
{
QCString n=a.defval;
@@ -1855,6 +1828,8 @@ void MemberDefImpl::writeLink(OutputList &ol,
*/
ClassDef *MemberDefImpl::getClassDefOfAnonymousType() const
{
+ //printf("%s:getClassDefOfAnonymousType() cache=%s\n",name().data(),
+ // m_impl->cachedAnonymousType?m_impl->cachedAnonymousType->name().data():"<empty>");
if (m_impl->cachedAnonymousType) return m_impl->cachedAnonymousType;
QCString cname;
@@ -1871,20 +1846,18 @@ ClassDef *MemberDefImpl::getClassDefOfAnonymousType() const
//if (ltype.left(7)=="static ") ltype=ltype.right(ltype.length()-7);
// strip 'friend' keyword from ltype
ltype.stripPrefix("friend ");
- static QRegExp r("@[0-9]+");
- int l,i=r.match(ltype,0,&l);
- //printf("ltype='%s' i=%d\n",ltype.data(),i);
+
// search for the last anonymous scope in the member type
ClassDef *annoClassDef=0;
- if (i!=-1) // found anonymous scope in type
- {
- int il=i-1,ir=i+l;
- // extract anonymous scope
- while (il>=0 && (isId(ltype.at(il)) || ltype.at(il)==':' || ltype.at(il)=='@')) il--;
- if (il>0) il++; else if (il<0) il=0;
- while (ir<(int)ltype.length() && (isId(ltype.at(ir)) || ltype.at(ir)==':' || ltype.at(ir)=='@')) ir++;
- QCString annName = ltype.mid(il,ir-il);
+ // match expression if it contains at least one @1 marker, e.g.
+ // 'struct A::@1::@2::B' matches 'A::@1::@2::B' but 'struct A::B' does not match.
+ std::string stype = ltype.str();
+ static const reg::Ex r(R"([\w@:]*@\d+[\w@:]*)");
+ reg::Match match;
+ if (reg::search(stype,match,r)) // found anonymous scope in type
+ {
+ QCString annName = match.str();
// if inside a class or namespace try to prepend the scope name
if (!cname.isEmpty() && annName.left(cname.length()+2)!=cname+"::")
@@ -2130,12 +2103,14 @@ void MemberDefImpl::writeDeclaration(OutputList &ol,
}
// strip 'friend' keyword from ltype
ltype.stripPrefix("friend ");
- static QRegExp r("@[0-9]+");
-
+ static const reg::Ex r(R"(@\d+)");
+ reg::Match match;
+ std::string stype = ltype.str();
bool endAnonScopeNeeded=FALSE;
- int l,i=r.match(ltype,0,&l);
- if (i!=-1) // member has an anonymous type
+ if (reg::search(stype,match,r)) // member has an anonymous type
{
+ int i = (int)match.position();
+ int l = (int)match.length();
//printf("annoClassDef=%p annMemb=%p scopeName='%s' anonymous='%s'\n",
// annoClassDef,annMemb,cname.data(),ltype.mid(i,l).data());
@@ -2790,76 +2765,69 @@ void MemberDefImpl::_writeReimplements(OutputList &ol) const
void MemberDefImpl::_writeReimplementedBy(OutputList &ol) const
{
const MemberList &bml=reimplementedBy();
- if (!bml.empty())
+ size_t count=0;
+ for (const auto &bmd : bml)
{
- uint count=0;
- for (const auto &bmd : bml)
+ const ClassDef *bcd=bmd->getClassDef();
+ // count the members that directly inherit from md and for
+ // which the member and class are visible in the docs.
+ if ( bcd && bmd->isLinkable() && bcd->isLinkable() )
{
- const ClassDef *bcd=bmd->getClassDef();
- // count the members that directly inherit from md and for
- // which the member and class are visible in the docs.
- if ( bcd && bmd->isLinkable() && bcd->isLinkable() )
- {
- count++;
- }
+ count++;
}
- if (count>0)
+ }
+ if (count>0)
+ {
+ auto replaceFunc = [&bml,&ol](size_t entryIndex)
{
- // write the list of classes that overwrite this member
- ol.startParagraph();
-
- QCString reimplInLine;
- if (m_impl->virt==Pure || (getClassDef() && getClassDef()->compoundType()==ClassDef::Interface))
- {
- reimplInLine = theTranslator->trImplementedInList(count);
- }
- else
- {
- reimplInLine = theTranslator->trReimplementedInList(count);
- }
- static QRegExp marker("@[0-9]+");
- int index=0,newIndex,matchLen;
- // now replace all markers in reimplInLine with links to the classes
- while ((newIndex=marker.match(reimplInLine,index,&matchLen))!=-1)
+ size_t cnt=0;
+ auto it = bml.begin();
+ // find the entryIndex-th documented entry in the inheritance list.
+ const MemberDef *bmd = 0;
+ const ClassDef *bcd = 0;
+ while (it!=bml.end())
{
- ol.parseText(reimplInLine.mid(index,newIndex-index));
- bool ok;
- uint entryIndex = reimplInLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
-
- count=0;
- auto it = bml.begin();
- // find the entryIndex-th documented entry in the inheritance list.
- const MemberDef *bmd = 0;
- const ClassDef *bcd = 0;
- while (it!=bml.end())
+ bmd = *it;
+ bcd = bmd->getClassDef();
+ if ( bmd->isLinkable() && bcd->isLinkable())
{
- bmd = *it;
- bcd = bmd->getClassDef();
- if ( bmd->isLinkable() && bcd->isLinkable())
- {
- if (count==entryIndex) break;
- count++;
- }
- ++it;
+ if (cnt==entryIndex) break;
+ cnt++;
}
+ ++it;
+ }
- if (ok && bcd && bmd) // write link for marker
- {
- //ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(),
- // bmd->anchor(),bcd->name());
- ol.writeObjectLink(bmd->getReference(),bmd->getOutputFileBase(),
- bmd->anchor(),bcd->displayName());
+ if (bcd && bmd) // write link for marker
+ {
+ //ol.writeObjectLink(bcd->getReference(),bcd->getOutputFileBase(),
+ // bmd->anchor(),bcd->name());
+ ol.writeObjectLink(bmd->getReference(),bmd->getOutputFileBase(),
+ bmd->anchor(),bcd->displayName());
- if (bmd->isLinkableInProject() )
- {
- writePageRef(ol,bmd->getOutputFileBase(),bmd->anchor());
- }
+ if (bmd->isLinkableInProject() )
+ {
+ writePageRef(ol,bmd->getOutputFileBase(),bmd->anchor());
}
- index=newIndex+matchLen;
}
- ol.parseText(reimplInLine.right(reimplInLine.length()-index));
- ol.endParagraph();
+ };
+
+ QCString reimplInLine;
+ if (m_impl->virt==Pure || (getClassDef() && getClassDef()->compoundType()==ClassDef::Interface))
+ {
+ reimplInLine = theTranslator->trImplementedInList((int)count);
}
+ else
+ {
+ reimplInLine = theTranslator->trReimplementedInList((int)count);
+ }
+
+ // write the list of classes that overwrite this member
+ ol.startParagraph();
+ writeMarkerList(ol,
+ reimplInLine.str(),
+ count,
+ replaceFunc);
+ ol.endParagraph();
}
}
@@ -3007,6 +2975,9 @@ void MemberDefImpl::_writeEnumValues(OutputList &ol,const Definition *container,
}
}
+// match from the start of the scope until the last marker
+static const reg::Ex reAnonymous(R"([\w:@]*@\d+)");
+
QCString MemberDefImpl::displayDefinition() const
{
QCString ldef = definition();
@@ -3037,21 +3008,14 @@ QCString MemberDefImpl::displayDefinition() const
ldef=ldef.mid(2);
}
}
- static QRegExp r("@[0-9]+");
- int l,i=r.match(ldef,0,&l);
- if (i!=-1) // replace anonymous parts with { ... }
+
+ std::string sdef = ldef.str();
+ reg::Match match;
+ if (reg::search(sdef,match,reAnonymous))
{
- int si=ldef.find(' '),pi,ei=i+l;
- if (si==-1) si=0;
- while ((pi=r.match(ldef,i+l,&l))!=-1)
- {
- i=pi;
- ei=i+l;
- }
- int ni=ldef.find("::",si);
- if (ni>=ei) ei=ni+2;
- ldef = ldef.left(si) + " { ... } " + ldef.right(ldef.length()-ei);
+ ldef = match.prefix().str() + " { ... } " + match.suffix().str();
}
+
const ClassDef *cd=getClassDef();
if (cd && cd->isObjectiveC())
{
@@ -3071,9 +3035,9 @@ QCString MemberDefImpl::displayDefinition() const
{
ldef=ldef.left(dp+1);
}
- l=ldef.length();
+ int l=ldef.length();
//printf("start >%s<\n",ldef.data());
- i=l-1;
+ int i=l-1;
while (i>=0 && (isId(ldef.at(i)) || ldef.at(i)==':')) i--;
while (i>=0 && isspace((uchar)ldef.at(i))) i--;
if (i>0)
@@ -3220,9 +3184,6 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
{
title += "()";
}
- int i=0,l;
- static QRegExp r("@[0-9]+");
-
if (lang == SrcLangExt_Slice)
{
// Remove the container scope from the member name.
@@ -3242,19 +3203,24 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
QStrList sl;
getLabels(sl,scopedContainer);
- if ((isVariable() || isTypedef()) && (i=r.match(ldef,0,&l))!=-1)
+ static const reg::Ex r(R"(@\d+)");
+ reg::Match match;
+ std::string sdef = ldef.str();
+ if ((isVariable() || isTypedef()) && reg::search(sdef,match,r))
{
// find enum type and insert it in the definition
bool found=false;
for (const auto &vmd : *ml)
{
- if (vmd->isEnumerate() && ldef.mid(i,l)==vmd->name())
+ if (vmd->isEnumerate() && match.str()==vmd->name())
{
ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs);
ol.startMemberDoc(ciname,name(),memAnchor,name(),memCount,memTotal,showInline);
- linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,ldef.left(i));
+ std::string prefix = match.prefix().str();
+ std::string suffix = match.suffix().str();
+ linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,prefix.c_str());
vmd->writeEnumDeclaration(ol,getClassDef(),getNamespaceDef(),getFileDef(),getGroupDef());
- linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,ldef.right(ldef.length()-i-l));
+ linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,suffix.c_str());
found=true;
break;
@@ -3266,21 +3232,20 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs);
ol.startMemberDoc(ciname,name(),memAnchor,"",memCount,memTotal,showInline);
// search for the last anonymous compound name in the definition
- int si=ldef.find(' '),pi,ei=i+l;
- if (si==-1) si=0;
- while ((pi=r.match(ldef,i+l,&l))!=-1)
+
+ ol.startMemberDocName(isObjCMethod());
+ if (reg::search(sdef,match,reAnonymous))
{
- i=pi;
- ei=i+l;
+ std::string prefix = match.prefix().str();
+ std::string suffix = match.suffix().str();
+ ol.docify(prefix.c_str());
+ ol.docify(" { ... } ");
+ linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,suffix.c_str());
+ }
+ else
+ {
+ linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,ldef);
}
- // first si characters of ldef contain compound type name
- ol.startMemberDocName(isObjCMethod());
- ol.docify(ldef.left(si));
- ol.docify(" { ... } ");
- // last ei characters of ldef contain pointer/reference specifiers
- int ni=ldef.find("::",si);
- if (ni>=ei) ei=ni+2;
- linkifyText(TextGeneratorOLImpl(ol),scopedContainer,getBodyDef(),this,ldef.right(ldef.length()-ei));
}
}
else // not an enum value or anonymous compound
@@ -3374,7 +3339,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
}
int dl=ldef.length();
//printf("start >%s<\n",ldef.data());
- i=dl-1;
+ int i=dl-1;
while (i>=0 && (isId(ldef.at(i)) || ldef.at(i)==':')) i--;
while (i>=0 && isspace((uchar)ldef.at(i))) i--;
if (i>0)
@@ -3642,69 +3607,23 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
}
// strip scope and field name from the type
-// example: "struct N::S.v.c" will become "struct v"
+// example: "struct N<K::J>::S.v.c" will become "struct v"
static QCString simplifyTypeForTable(const QCString &s)
{
QCString ts=removeAnonymousScopes(s);
if (ts.right(2)=="::") ts = ts.left(ts.length()-2);
- static QRegExp re("[A-Z_a-z0-9]+::");
- int i,l;
- while ((i=re.match(ts,0,&l))!=-1)
+ static const reg::Ex re1(R"(\a\w*::(\a\w*))"); // non-template version
+ static const reg::Ex re2(R"(\a\w*<[^>]*>::(\a\w*))"); // template version
+ reg::Match match;
+ std::string t = ts.str();
+ if (reg::search(t,match,re1) || reg::search(t,match,re2))
{
- ts=ts.left(i)+ts.mid(i+l);
+ ts = match[1].str(); // take the identifier after the last ::
}
- i=ts.findRev('.');
- if (i!=-1) ts = ts.left(i);
- i=ts.findRev('.');
- if (i!=-1) ts = ts.right(ts.length()-i-1);
//printf("simplifyTypeForTable(%s)->%s\n",s.data(),ts.data());
return ts;
}
-#if 0
-/** Returns the type definition corresponding to a member's return type.
- * @param[in] scope The scope in which to search for the class definition.
- * @param[in] type The string representing the member's return type.
- * @param[in] lang The programming language in which the class is defined.
- * @param[out] start The string position where the class definition name was found.
- * @param[out] length The length of the class definition's name.
- */
-static Definition *getClassFromType(Definition *scope,const QCString &type,SrcLangExt lang,int &start,int &length)
-{
- int pos=0;
- int i;
- QCString name;
- QCString templSpec;
- while ((i=extractClassNameFromType(type,pos,name,templSpec,lang))!=-1)
- {
- ClassDef *cd=0;
- MemberDef *md=0;
- int l = name.length()+templSpec.length();
- if (!templSpec.isEmpty())
- {
- cd = getResolvedClass(scope,0,name+templSpec,&md);
- }
- cd = getResolvedClass(scope,0,name);
- if (cd)
- {
- start=i;
- length=l;
- printf("getClassFromType: type=%s name=%s start=%d length=%d\n",type.data(),name.data(),start,length);
- return cd;
- }
- else if (md)
- {
- start=i;
- length=l;
- printf("getClassFromType: type=%s name=%s start=%d length=%d\n",type.data(),name.data(),start,length);
- return md;
- }
- pos=i+l;
- }
- return 0;
-}
-#endif
-
QCString MemberDefImpl::fieldType() const
{
QCString type = m_impl->accessorType;
@@ -4178,29 +4097,29 @@ MemberDefMutable *MemberDefImpl::createTemplateInstanceMember(
// replace formal arguments with actuals
for (Argument &arg : *actualArgList)
{
- arg.type = substituteTemplateArgumentsInString(arg.type,formalArgs,actualArgs);
+ arg.type = substituteTemplateArgumentsInString(arg.type.str(),formalArgs,actualArgs);
}
actualArgList->setTrailingReturnType(
- substituteTemplateArgumentsInString(actualArgList->trailingReturnType(),formalArgs,actualArgs));
+ substituteTemplateArgumentsInString(actualArgList->trailingReturnType().str(),formalArgs,actualArgs));
}
QCString methodName=name();
if (methodName.left(9)=="operator ") // conversion operator
{
- methodName=substituteTemplateArgumentsInString(methodName,formalArgs,actualArgs);
+ methodName=substituteTemplateArgumentsInString(methodName.str(),formalArgs,actualArgs);
}
MemberDefMutable *imd = createMemberDef(
getDefFileName(),getDefLine(),getDefColumn(),
- substituteTemplateArgumentsInString(m_impl->type,formalArgs,actualArgs),
+ substituteTemplateArgumentsInString(m_impl->type.str(),formalArgs,actualArgs),
methodName,
- substituteTemplateArgumentsInString(m_impl->args,formalArgs,actualArgs),
+ substituteTemplateArgumentsInString(m_impl->args.str(),formalArgs,actualArgs),
m_impl->exception, m_impl->prot,
m_impl->virt, m_impl->stat, m_impl->related, m_impl->mtype,
ArgumentList(), ArgumentList(), ""
);
imd->moveArgumentList(std::move(actualArgList));
- imd->setDefinition(substituteTemplateArgumentsInString(m_impl->def,formalArgs,actualArgs));
+ imd->setDefinition(substituteTemplateArgumentsInString(m_impl->def.str(),formalArgs,actualArgs));
imd->setBodyDef(getBodyDef());
imd->setBodySegment(getDefLine(),getStartBodyLine(),getEndBodyLine());
//imd->setBodyMember(this);
diff --git a/src/memberdef.h b/src/memberdef.h
index 7b27cff..abaf3ff 100644
--- a/src/memberdef.h
+++ b/src/memberdef.h
@@ -36,7 +36,6 @@ class MemberGroup;
class ExampleList;
class OutputList;
class GroupDef;
-class QTextStream;
class QStrList;
struct TagInfo;
class MemberDefMutable;
diff --git a/src/memberlist.cpp b/src/memberlist.cpp
index 9181e3f..8d07ae4 100644
--- a/src/memberlist.cpp
+++ b/src/memberlist.cpp
@@ -15,8 +15,6 @@
*
*/
-#include <qregexp.h>
-
#include "memberlist.h"
#include "classdef.h"
#include "message.h"
diff --git a/src/message.cpp b/src/message.cpp
index 95a7553..6c7c8ac 100644
--- a/src/message.cpp
+++ b/src/message.cpp
@@ -25,12 +25,6 @@
static QCString outputFormat;
static const char *warning_str = "warning: ";
static const char *error_str = "error: ";
-//static int warnFormatOrder; // 1 = $file,$line,$text
-// // 2 = $text,$line,$file
-// // 3 = $line,$text,$file
-// // 4 = $file,$text,$line
-// // 5 = $text,$file,$line
-// // 6 = $line,$file,$text
static FILE *warnFile = stderr;
@@ -47,55 +41,6 @@ static std::mutex g_mutex;
void initWarningFormat()
{
-// int filePos = Config_getString(WARN_FORMAT).find("$file");
-// int linePos = Config_getString(WARN_FORMAT).find("$line");
-// int textPos = Config_getString(WARN_FORMAT).find("$text");
-//
-// // sort items on position (there are 6 cases)
-// warnFormatOrder = 1;
-// if (filePos>linePos && filePos>textPos)
-// {
-// if (linePos>textPos) // $text,$line,$file
-// {
-// warnFormatOrder = 2;
-// }
-// else // $line,$text,$file
-// {
-// warnFormatOrder = 3;
-// }
-// }
-// else if (filePos<linePos && filePos<textPos)
-// {
-// if (linePos>textPos) // $file,$text,$line
-// {
-// warnFormatOrder = 4;
-// }
-// }
-// else if (filePos<linePos && filePos>textPos) // $text,$file,$line
-// {
-// warnFormatOrder = 5;
-// }
-// else // $line,$file,$text
-// {
-// warnFormatOrder = 6;
-// }
-// outputFormat =
-// substitute(
-// substitute(
-// substitute(
-// Config_getString(WARN_FORMAT),
-// "$file","%s"
-// ),
-// "$text","%s"
-// ),
-// "$line","%d"
-// )+'\n';
-
- // replace(QRegExp("\\$file"),"%s").
- // replace(QRegExp("\\$text"),"%s").
- // replace(QRegExp("\\$line"),"%d")+
- // '\n';
-
outputFormat = Config_getString(WARN_FORMAT);
if (!Config_getString(WARN_LOGFILE).isEmpty())
@@ -240,6 +185,14 @@ void warn_undoc(const char *file,int line,const char *fmt, ...)
va_end(args);
}
+void warn_incomplete_doc(const char *file,int line,const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ do_warn(Config_getBool(WARN_IF_INCOMPLETE_DOC), file, line, warning_str, fmt, args);
+ va_end(args);
+}
+
void warn_doc_error(const char *file,int line,const char *fmt, ...)
{
va_list args;
diff --git a/src/message.h b/src/message.h
index af49632..aa63ecb 100644
--- a/src/message.h
+++ b/src/message.h
@@ -29,6 +29,7 @@ extern void warn(const char *file,int line,const char *fmt, ...) PRINTFLIKE(3, 4
extern void va_warn(const char* file, int line, const char* fmt, va_list args);
extern void warn_simple(const char *file,int line,const char *text);
extern void warn_undoc(const char *file,int line,const char *fmt, ...) PRINTFLIKE(3, 4);
+extern void warn_incomplete_doc(const char *file,int line,const char *fmt, ...) PRINTFLIKE(3, 4);
extern void warn_doc_error(const char *file,int line,const char *fmt, ...) PRINTFLIKE(3, 4);
extern void warn_uncond(const char *fmt, ...) PRINTFLIKE(1, 2);
extern void err(const char *fmt, ...) PRINTFLIKE(1, 2);
diff --git a/src/pagedef.cpp b/src/pagedef.cpp
index a3cc0b5..4634be7 100644
--- a/src/pagedef.cpp
+++ b/src/pagedef.cpp
@@ -13,8 +13,6 @@
*
*/
-#include <qregexp.h>
-
#include "pagedef.h"
#include "groupdef.h"
#include "docparser.h"
@@ -288,7 +286,7 @@ void PageDefImpl::writeDocumentation(OutputList &ol)
ol.popGeneratorState();
//1.}
- Doxygen::indexList->addIndexItem(this,0,0,filterTitle(title()));
+ Doxygen::indexList->addIndexItem(this,0,0,filterTitle(title().str()));
}
void PageDefImpl::writePageDocumentation(OutputList &ol) const
diff --git a/src/perlmodgen.cpp b/src/perlmodgen.cpp
index 20bd01b..4cf0d4a 100644
--- a/src/perlmodgen.cpp
+++ b/src/perlmodgen.cpp
@@ -2144,7 +2144,7 @@ void PerlModGenerator::generatePerlModForPage(PageDef *pd)
const SectionInfo *si = SectionManager::instance().find(pd->name());
if (si)
- m_output.addFieldQuotedString("title4", filterTitle(si->title()));
+ m_output.addFieldQuotedString("title4", filterTitle(si->title().str()));
addPerlModDocBlock(m_output,"detailed",pd->docFile(),pd->docLine(),0,0,pd->documentation());
m_output.closeHash();
diff --git a/src/pre.l b/src/pre.l
index e817a9d..0b12ea9 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -41,7 +41,6 @@
#include <errno.h>
#include <qcstring.h>
-#include <qregexp.h>
#include <qfileinfo.h>
#include "containers.h"
@@ -60,6 +59,7 @@
#include "condparser.h"
#include "config.h"
#include "filedef.h"
+#include "regex.h"
#define YY_NO_UNISTD_H 1
@@ -1959,31 +1959,48 @@ static QCString stringize(const QCString &s)
*/
static void processConcatOperators(QCString &expr)
{
- //printf("processConcatOperators: in='%s'\n",expr.data());
- QRegExp r("[ \\t\\n]*##[ \\t\\n]*");
- int l,n,i=0;
if (expr.isEmpty()) return;
- while ((n=r.match(expr,i,&l))!=-1)
+ //printf("processConcatOperators: in='%s'\n",expr.data());
+ std::string e = expr.str();
+ static const reg::Ex r(R"(\s*##\s*)");
+ reg::Iterator end;
+
+ size_t i=0;
+ for (;;)
{
- //printf("Match: '%s'\n",expr.data()+i);
- if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
+ reg::Iterator it(e,r,i);
+ if (it!=end)
{
- // remove no-rescan marker after ID
- l+=2;
+ const auto &match = *it;
+ size_t n = match.position();
+ size_t l = match.length();
+ //printf("Match: '%s'\n",expr.data()+i);
+ if (n+l+1<e.length() && e[n+l]=='@' && expr[n+l+1]=='-')
+ {
+ // remove no-rescan marker after ID
+ l+=2;
+ }
+ //printf("found '%s'\n",expr.mid(n,l).data());
+ // remove the ## operator and the surrounding whitespace
+ e=e.substr(0,n)+e.substr(n+l);
+ int k=n-1;
+ while (k>=0 && isId(e[k])) k--;
+ if (k>0 && e[k]=='-' && e[k-1]=='@')
+ {
+ // remove no-rescan marker before ID
+ e=e.substr(0,k-1)+e.substr(k+1);
+ n-=2;
+ }
+ i=n;
}
- //printf("found '%s'\n",expr.mid(n,l).data());
- // remove the ## operator and the surrounding whitespace
- expr=expr.left(n)+expr.right(expr.length()-n-l);
- int k=n-1;
- while (k>=0 && isId(expr.at(k))) k--;
- if (k>0 && expr.at(k)=='-' && expr.at(k-1)=='@')
+ else
{
- // remove no-rescan marker before ID
- expr=expr.left(k-1)+expr.right(expr.length()-k-1);
- n-=2;
+ break;
}
- i=n;
}
+
+ expr = e;
+
//printf("processConcatOperators: out='%s'\n",expr.data());
}
@@ -3172,30 +3189,29 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName)
// add predefined macros
const StringVector &predefList = Config_getList(PREDEFINED);
- for (const auto &defStr : predefList)
+ for (const auto &ds : predefList)
{
- QCString ds = defStr.c_str();
- int i_equals=ds.find('=');
- int i_obrace=ds.find('(');
- int i_cbrace=ds.find(')');
- bool nonRecursive = i_equals>0 && ds.at(i_equals-1)==':';
+ size_t i_equals=ds.find('=');
+ size_t i_obrace=ds.find('(');
+ size_t i_cbrace=ds.find(')');
+ bool nonRecursive = i_equals!=std::string::npos && i_equals>0 && ds[i_equals-1]==':';
- if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds.at(i_equals-1)==':'))
+ if ((i_obrace==0) || (i_equals==0) || (i_equals==1 && ds[i_equals-1]==':'))
{
continue; // no define name
}
if (i_obrace<i_equals && i_cbrace<i_equals &&
- i_obrace!=-1 && i_cbrace!=-1 &&
+ i_obrace!=std::string::npos && i_cbrace!=std::string::npos &&
i_obrace<i_cbrace
) // predefined function macro definition
{
+ static const reg::Ex reId(R"(\a\w*)");
+ reg::Iterator end;
bool varArgs = false;
int count = 0;
- int i,pi,l;
std::map<std::string,int> argMap;
- QRegExp reId("[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*"); // regexp matching an id
- if (ds.mid(i_obrace+1,i_cbrace-i_obrace-1)=="...")
+ if (ds.substr(i_obrace+1,i_cbrace-i_obrace-1)=="...")
{
varArgs = true;
argMap.emplace("__VA_ARGS__",count);
@@ -3203,14 +3219,18 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName)
}
else
{
- //printf("predefined function macro '%s'\n",qPrint(ds.mid(i_obrace+1,i_cbrace-i_obrace-1)));
- i=i_obrace+1;
+ size_t i=i_obrace+1;
+ //printf("predefined function macro '%s'\n",ds.c_str());
+ reg::Iterator it(ds,reId,i);
// gather the formal arguments in a dictionary
- while (i<i_cbrace && (pi=reId.match(ds,i,&l)))
+ while (i<i_cbrace && it!=end)
{
+ const auto &match = *it;
+ size_t pi = match.position();
+ size_t l = match.length();
if (l>0) // see bug375037
{
- argMap.emplace(toStdString(ds.mid(pi,l)),count);
+ argMap.emplace(match.str(),count);
count++;
i=pi+l;
}
@@ -3218,18 +3238,24 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName)
{
i++;
}
+ ++it;
}
}
// strip definition part
- QCString tmp=ds.right(ds.length()-i_equals-1);
- QCString definition;
- i=0;
+ std::string definition;
+ std::string in=ds.substr(i_equals+1);
+ reg::Iterator re_it(in,reId);
+ size_t i=0;
// substitute all occurrences of formal arguments by their
// corresponding markers
- while ((pi=reId.match(tmp,i,&l))!=-1)
+ for (; re_it!=end; ++re_it)
{
- if (pi>i) definition+=tmp.mid(i,pi-i);
- auto it = argMap.find(tmp.mid(pi,l).data());
+ const auto &match = *re_it;
+ size_t pi = match.position();
+ size_t l = match.length();
+ if (pi>i) definition+=in.substr(i,pi-i);
+
+ auto it = argMap.find(match.str());
if (it!=argMap.end())
{
int argIndex = it->second;
@@ -3239,15 +3265,15 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName)
}
else
{
- definition+=tmp.mid(pi,l);
+ definition+=match.str();
}
i=pi+l;
}
- if (i<(int)tmp.length()) definition+=tmp.mid(i,tmp.length()-i);
+ definition+=in.substr(i);
// add define definition to the dictionary of defines for this file
- QCString dname = ds.left(i_obrace);
- if (!dname.isEmpty())
+ std::string dname = ds.substr(0,i_obrace);
+ if (!dname.empty())
{
Define def;
def.name = dname;
@@ -3263,16 +3289,12 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName)
//printf("#define '%s' '%s' #nargs=%d\n",
// def->name.data(),def->definition.data(),def->nargs);
}
-
}
- else if ((i_obrace==-1 || i_obrace>i_equals) &&
- (i_cbrace==-1 || i_cbrace>i_equals) &&
- !ds.isEmpty() && (int)ds.length()>i_equals
- ) // predefined non-function macro definition
+ else if (!ds.empty()) // predefined non-function macro definition
{
- //printf("predefined normal macro '%s'\n",defStr);
+ //printf("predefined normal macro '%s'\n",ds.c_str());
Define def;
- if (i_equals==-1) // simple define without argument
+ if (i_equals==std::string::npos) // simple define without argument
{
def.name = ds;
def.definition = "1"; // substitute occurrences by 1 (true)
@@ -3280,8 +3302,8 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName)
else // simple define with argument
{
int ine=i_equals - (nonRecursive ? 1 : 0);
- def.name = ds.left(ine);
- def.definition = ds.right(ds.length()-i_equals-1);
+ def.name = ds.substr(0,ine);
+ def.definition = ds.substr(i_equals+1);
}
if (!def.name.isEmpty())
{
@@ -3390,11 +3412,12 @@ void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output
char *newPos=output.data()+output.curPos();
Debug::print(Debug::Preprocessor,0,"Preprocessor output of %s (size: %d bytes):\n",fileName,newPos-orgPos);
int line=1;
- Debug::print(Debug::Preprocessor,0,"---------\n00001 ");
+ Debug::print(Debug::Preprocessor,0,"---------\n");
+ if (!Debug::isFlagSet(Debug::NoLineNo)) Debug::print(Debug::Preprocessor,0,"00001 ");
while (orgPos<newPos)
{
putchar(*orgPos);
- if (*orgPos=='\n') Debug::print(Debug::Preprocessor,0,"%05d ",++line);
+ if (*orgPos=='\n' && !Debug::isFlagSet(Debug::NoLineNo)) Debug::print(Debug::Preprocessor,0,"%05d ",++line);
orgPos++;
}
Debug::print(Debug::Preprocessor,0,"\n---------\n");
diff --git a/src/regex.cpp b/src/regex.cpp
new file mode 100644
index 0000000..62678b7
--- /dev/null
+++ b/src/regex.cpp
@@ -0,0 +1,736 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2021 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
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#include "regex.h"
+#include <cstdint>
+#include <vector>
+#include <cctype>
+#include <cassert>
+#include <algorithm>
+
+#define ENABLE_DEBUG 0
+#if ENABLE_DEBUG
+#define DBG(fmt,...) do { fprintf(stderr,fmt,__VA_ARGS__); } while(0)
+#else
+#define DBG(fmt,...) do {} while(0)
+#endif
+
+namespace reg
+{
+
+/** Class representing a token in the compiled regular expression token stream.
+ * A token has a kind and an optional value whose meaning depends on the kind.
+ * It is also possible to store a (from,to) character range in a token.
+ */
+class PToken
+{
+ public:
+ /** The kind of token.
+ *
+ * Ranges per bit mask:
+ * - `0x00FF` from part of a range, except for `0x0000` which is the End marker
+ * - `0x1FFF` built-in ranges
+ * - `0x2FFF` user defined ranges
+ * - `0x4FFF` special operations
+ * - `0x8000` literal character
+ */
+ enum class Kind : uint16_t
+ {
+ End = 0x0000,
+ WhiteSpace = 0x1001, // \s range [ \t\r\n]
+ Digit = 0x1002, // \d range [0-9]
+ Alpha = 0x1003, // \a range [a-z_A-Z\x80-\xFF]
+ AlphaNum = 0x1004, // \w range [a-Z_A-Z0-9\x80-\xFF]
+ CharClass = 0x2001, // []
+ NegCharClass = 0x2002, // [^]
+ BeginOfLine = 0x4001, // ^
+ EndOfLine = 0x4002, // $
+ BeginOfWord = 0x4003, // \<
+ EndOfWord = 0x4004, // \>
+ BeginCapture = 0x4005, // (
+ EndCapture = 0x4006, // )
+ Any = 0x4007, // .
+ Star = 0x4008, // *
+ Optional = 0x4009, // ?
+ Character = 0x8000 // c
+ };
+
+ /** returns a string representation of the tokens kind (useful for debugging). */
+ const char *kindStr() const
+ {
+ if ((m_rep>>16)>=0x1000 || m_rep==0)
+ {
+ switch(static_cast<Kind>((m_rep>>16)))
+ {
+ case Kind::End: return "End";
+ case Kind::Alpha: return "Alpha";
+ case Kind::AlphaNum: return "AlphaNum";
+ case Kind::WhiteSpace: return "WhiteSpace";
+ case Kind::Digit: return "Digit";
+ case Kind::CharClass: return "CharClass";
+ case Kind::NegCharClass: return "NegCharClass";
+ case Kind::Character: return "Character";
+ case Kind::BeginOfLine: return "BeginOfLine";
+ case Kind::EndOfLine: return "EndOfLine";
+ case Kind::BeginOfWord: return "BeginOfWord";
+ case Kind::EndOfWord: return "EndOfWord";
+ case Kind::BeginCapture: return "BeginCapture";
+ case Kind::EndCapture: return "EndCapture";
+ case Kind::Any: return "Any";
+ case Kind::Star: return "Star";
+ case Kind::Optional: return "Optional";
+ }
+ }
+ else
+ {
+ return "Range";
+ }
+ }
+
+ /** Creates a token of kind 'End' */
+ PToken() : m_rep(0) {}
+
+ /** Creates a token of the given kind \a k */
+ explicit PToken(Kind k) : m_rep(static_cast<uint32_t>(k)<<16) {}
+
+ /** Create a token for an ASCII character */
+ PToken(char c) : m_rep((static_cast<uint32_t>(Kind::Character)<<16) |
+ static_cast<uint32_t>(c)) {}
+
+ /** Create a token for a byte of an UTF-8 character */
+ PToken(uint16_t v) : m_rep((static_cast<uint32_t>(Kind::Character)<<16) |
+ static_cast<uint32_t>(v)) {}
+
+ /** Create a token representing a range from one character \a from to another character \a to */
+ PToken(uint16_t from,uint16_t to) : m_rep(static_cast<uint32_t>(from)<<16 | to) {}
+
+ /** Sets the value for a token */
+ void setValue(uint16_t value) { m_rep = (m_rep & 0xFFFF0000) | value; }
+
+ /** Returns the kind of the token */
+ Kind kind() const { return static_cast<Kind>(m_rep>>16); }
+
+ /** Returns the 'from' part of the character range. Only valid if this token represents a range */
+ uint16_t from() const { return m_rep>>16; }
+
+ /** Returns the 'to' part of the character range. Only valid if this token represents a range */
+ uint16_t to() const { return m_rep & 0xFFFF; }
+
+ /** Returns the value for this token */
+ uint16_t value() const { return m_rep & 0xFFFF; }
+
+ /** Returns the value for this token as a ASCII character */
+ char asciiValue() const { return static_cast<char>(m_rep); }
+
+ /** Returns true iff this token represents a range of characters */
+ bool isRange() const { return m_rep!=0 && from()<=to(); }
+
+ /** Returns true iff this token is a positive or negative character class */
+ bool isCharClass() const { return kind()==Kind::CharClass || kind()==Kind::NegCharClass; }
+
+ private:
+ uint32_t m_rep;
+};
+
+/** Private members of a regular expression */
+class Ex::Private
+{
+ public:
+ /** Creates the private part */
+ Private(const std::string &pat) : pattern(pat)
+ {
+ data.reserve(100);
+ }
+ void compile();
+#if ENABLE_DEBUG
+ void dump();
+#endif
+ bool matchAt(size_t tokenPos,const std::string &str,Match &match,size_t pos,int level) const;
+
+ /** Flag indicating the expression was successfully compiled */
+ bool error = false;
+
+ /** The token stream representing the compiled regular expression. */
+ std::vector<PToken> data; // compiled pattern
+
+ /** The pattern string as passed by the user */
+ std::string pattern;
+};
+
+/** Compiles a regular expression passed as a string into a stream of tokens that can be used for
+ * efficient searching.
+ */
+void Ex::Private::compile()
+{
+ error = false;
+ data.clear();
+ if (pattern.empty()) return;
+ const char *start = pattern.c_str();
+ const char *ps = start;
+ char c;
+
+ int prevTokenPos=-1;
+ int tokenPos=0;
+
+ auto addToken = [&](PToken tok)
+ {
+ tokenPos++;
+ data.emplace_back(tok);
+ };
+
+ auto getNextCharacter = [&]() -> PToken
+ {
+ char cs=*ps;
+ PToken result = PToken(cs);
+ if (cs=='\\') // escaped character
+ {
+ ps++;
+ cs=*ps;
+ switch (cs)
+ {
+ case 'n': result = PToken('\n'); break;
+ case 'r': result = PToken('\r'); break;
+ case 't': result = PToken('\t'); break;
+ case 's': result = PToken(PToken::Kind::WhiteSpace); break;
+ case 'a': result = PToken(PToken::Kind::Alpha); break;
+ case 'w': result = PToken(PToken::Kind::AlphaNum); break;
+ case 'd': result = PToken(PToken::Kind::Digit); break;
+ case '<': result = PToken(PToken::Kind::BeginOfWord); break;
+ case '>': result = PToken(PToken::Kind::EndOfWord); break;
+ case 'x':
+ case 'X':
+ {
+ uint16_t v=0;
+ for (int i=0;i<2 && (cs=(*(ps+1)));i++) // 2 hex digits
+ {
+ int d = (cs>='a' && cs<='f') ? cs-'a'+10 :
+ (cs>='A' && cs<='F') ? cs-'A'+10 :
+ (cs>='0' && cs<='9') ? cs-'0' :
+ -1;
+ if (d>=0) { v<<=4; v|=d; ps++; } else break;
+ }
+ result = PToken(v);
+ }
+ break;
+ case '\0': ps--; break; // backslash at the end of the pattern
+ default:
+ result = PToken(cs);
+ break;
+ }
+ }
+ return result;
+ };
+
+ while ((c=*ps))
+ {
+ switch (c)
+ {
+ case '^': // beginning of line (if first character of the pattern)
+ prevTokenPos = tokenPos;
+ addToken(ps==start ? PToken(PToken::Kind::BeginOfLine) :
+ PToken(c));
+ break;
+ case '$': // end of the line (if last character of the pattern)
+ prevTokenPos = tokenPos;
+ addToken(*(ps+1)=='\0' ? PToken(PToken::Kind::EndOfLine) :
+ PToken(c));
+ break;
+ case '.': // any character
+ prevTokenPos = tokenPos;
+ addToken(PToken(PToken::Kind::Any));
+ break;
+ case '(': // begin of capture group
+ prevTokenPos = tokenPos;
+ addToken(PToken(PToken::Kind::BeginCapture));
+ break;
+ case ')': // end of capture group
+ prevTokenPos = tokenPos;
+ addToken(PToken(PToken::Kind::EndCapture));
+ break;
+ case '[': // character class
+ {
+ prevTokenPos = tokenPos;
+ ps++;
+ if (*ps==0) { error=true; return; }
+ bool esc = *ps=='\\';
+ PToken tok = getNextCharacter();
+ ps++;
+ if (!esc && tok.kind()==PToken::Kind::Character &&
+ tok.asciiValue()=='^') // negated character class
+ {
+ addToken(PToken(PToken::Kind::NegCharClass));
+ if (*ps==0) { error=true; return; }
+ tok = getNextCharacter();
+ ps++;
+ }
+ else
+ {
+ addToken(PToken(PToken::Kind::CharClass));
+ }
+ uint16_t numTokens=0;
+ while ((c=*ps))
+ {
+ if (c=='-' && *(ps+1)!=']' && *(ps+1)!=0) // range
+ {
+ getNextCharacter();
+ ps++;
+ PToken endTok = getNextCharacter();
+ ps++;
+ if (tok.value()>endTok.value())
+ {
+ addToken(PToken(endTok.value(),tok.value())); // swap start and end
+ }
+ else
+ {
+ addToken(PToken(tok.value(),endTok.value()));
+ }
+ numTokens++;
+ }
+ else // single char, from==to
+ {
+ if (tok.kind()==PToken::Kind::Character)
+ {
+ addToken(PToken(tok.value(),tok.value()));
+ }
+ else // special token, add as-is since from>to
+ {
+ addToken(tok);
+ }
+ numTokens++;
+ }
+ if (*ps==0) { error=true; return; } // expected at least a ]
+ esc = *ps=='\\';
+ tok = getNextCharacter();
+ if (!esc && tok.kind()==PToken::Kind::Character &&
+ tok.value()==static_cast<uint16_t>(']'))
+ {
+ break; // end of character class
+ }
+ if (*ps==0) { error=true; return; } // no ] found
+ ps++;
+ }
+ // set the value of either NegCharClass or CharClass
+ data[prevTokenPos].setValue(numTokens);
+ }
+ break;
+ case '*': // 0 or more
+ case '+': // 1 or more
+ case '?': // optional: 0 or 1
+ {
+ if (prevTokenPos==-1)
+ {
+ error=true;
+ return;
+ }
+ switch (data[prevTokenPos].kind())
+ {
+ case PToken::Kind::BeginOfLine: // $* or $+ or $?
+ case PToken::Kind::BeginOfWord: // \<* or \<+ or \<?
+ case PToken::Kind::EndOfWord: // \>* or \>+ or \>?
+ case PToken::Kind::Star: // ** or *+ or *?
+ case PToken::Kind::Optional: // ?* or ?+ or ??
+ error=true;
+ return;
+ default: // ok
+ break;
+ }
+ int ddiff = static_cast<int>(tokenPos-prevTokenPos);
+ if (*ps=='+') // convert <pat>+ -> <pat><pat>*
+ {
+ // turn a sequence of token [T1...Tn] followed by '+' into [T1..Tn T1..Tn T*]
+ // ddiff=n ^prevTokenPos
+ data.resize(data.size()+ddiff);
+ std::copy_n(data.begin()+prevTokenPos,ddiff,data.begin()+tokenPos);
+ prevTokenPos+=ddiff;
+ tokenPos+=ddiff;
+ }
+ data.insert(data.begin()+prevTokenPos,
+ c=='?' ? PToken(PToken::Kind::Optional) : PToken(PToken::Kind::Star));
+ tokenPos++;
+ addToken(PToken(PToken::Kind::End));
+ // turn a sequence of tokens [T1 T2 T3] followed by 'T*' or into [T* T1 T2 T3 TEND]
+ // ^prevTokenPos
+ // same for 'T?'.
+ }
+ break;
+ default:
+ prevTokenPos = tokenPos;
+ addToken(getNextCharacter());
+ break;
+ }
+ ps++;
+ }
+ //addToken(PToken(PToken::Kind::End));
+}
+
+#if ENABLE_DEBUG
+/** Dump the compiled token stream for this regular expression. For debugging purposes. */
+void Ex::Private::dump()
+{
+ size_t l = data.size();
+ size_t i =0;
+ DBG("==== compiled token stream for pattern '%s' ===\n",pattern.c_str());
+ while (i<l)
+ {
+ DBG("[%s:%04x]\n",data[i].kindStr(),data[i].value());
+ if (data[i].kind()==PToken::Kind::CharClass || data[i].kind()==PToken::Kind::NegCharClass)
+ {
+ uint16_t num = data[i].value();
+ while (num>0 && i<l)
+ {
+ i++;
+ if (data[i].isRange()) // from-to range
+ {
+ DBG("[%04x(%c)-%04x(%c)]\n",data[i].from(),data[i].from(),data[i].to(),data[i].to());
+ }
+ else // special character like \n or \s
+ {
+ DBG("[%s:%04x]\n",data[i].kindStr(),data[i].value());
+ }
+ num--;
+ }
+ }
+ i++;
+ }
+}
+#endif
+
+/** Internal matching routine.
+ * @param tokenPos Offset into the token stream.
+ * @param str The input string to match against.
+ * @param match The object used to store the matching results.
+ * @param pos The position in the input string to start with matching
+ * @param level Recursion level (used for debugging)
+ */
+bool Ex::Private::matchAt(size_t tokenPos,const std::string &str,Match &match,const size_t pos,int level) const
+{
+ DBG("%d:matchAt(tokenPos=%zu, str='%s', pos=%zu)\n",level,tokenPos,str.c_str(),pos);
+ auto isStartIdChar = [](char c) { return std::isalpha(c) || c=='_' || c<0; };
+ auto isIdChar = [](char c) { return std::isalnum(c) || c=='_' || c<0; };
+ auto matchCharClass = [this,isStartIdChar,isIdChar](size_t tp,char c) -> bool
+ {
+ PToken tok = data[tp];
+ bool negate = tok.kind()==PToken::Kind::NegCharClass;
+ uint16_t numFields = tok.value();
+ bool found = false;
+ for (uint16_t i=0;i<numFields;i++)
+ {
+ tok = data[++tp];
+ // first check for built-in ranges
+ if ((tok.kind()==PToken::Kind::Alpha && isStartIdChar(c)) ||
+ (tok.kind()==PToken::Kind::AlphaNum && isIdChar(c)) ||
+ (tok.kind()==PToken::Kind::WhiteSpace && std::isspace(c)) ||
+ (tok.kind()==PToken::Kind::Digit && std::isdigit(c))
+ )
+ {
+ found=true;
+ break;
+ }
+ else // user specified range
+ {
+ uint16_t v = static_cast<uint16_t>(c);
+ if (tok.from()<=v && v<=tok.to())
+ {
+ found=true;
+ break;
+ }
+ }
+ }
+ DBG("matchCharClass(tp=%zu,c=%c (x%02x))=%d\n",tp,c,c,negate?!found:found);
+ return negate ? !found : found;
+ };
+ size_t index = pos;
+ enum SequenceType { Star, Optional };
+ auto processSequence = [this,&tokenPos,&index,&str,&matchCharClass,
+ &isStartIdChar,&isIdChar,&match,&level,&pos](SequenceType type) -> bool
+ {
+ size_t startIndex = index;
+ PToken tok = data[++tokenPos];
+ if (tok.kind()==PToken::Kind::Character) // 'x*' -> eat x's
+ {
+ char c_tok = tok.asciiValue();
+ while (index<=str.length() && str[index]==c_tok) { index++; if (type==Optional) break; }
+ tokenPos++;
+ }
+ else if (tok.isCharClass()) // '[a-f0-4]* -> eat matching characters
+ {
+ while (index<=str.length() && matchCharClass(tokenPos,str[index])) { index++; if (type==Optional) break; }
+ tokenPos+=tok.value()+1; // skip over character ranges + end token
+ }
+ else if (tok.kind()==PToken::Kind::Alpha) // '\a*' -> eat start id characters
+ {
+ while (index<=str.length() && isStartIdChar(str[index])) { index++; if (type==Optional) break; }
+ tokenPos++;
+ }
+ else if (tok.kind()==PToken::Kind::AlphaNum) // '\w*' -> eat id characters
+ {
+ while (index<=str.length() && isIdChar(str[index])) { index++; if (type==Optional) break; }
+ tokenPos++;
+ }
+ else if (tok.kind()==PToken::Kind::WhiteSpace) // '\s*' -> eat spaces
+ {
+ while (index<=str.length() && std::isspace(str[index])) { index++; if (type==Optional) break; }
+ tokenPos++;
+ }
+ else if (tok.kind()==PToken::Kind::Digit) // '\d*' -> eat digits
+ {
+ while (index<=str.length() && std::isdigit(str[index])) { index++; if (type==Optional) break; }
+ tokenPos++;
+ }
+ else if (tok.kind()==PToken::Kind::Any) // '.*' -> eat all
+ {
+ if (type==Optional) index++; else index = str.length();
+ tokenPos++;
+ }
+ tokenPos++; // skip over end marker
+ while ((int)index>=(int)startIndex)
+ {
+ // pattern 'x*xy' should match 'xy' and 'xxxxy'
+ bool found = matchAt(tokenPos,str,match,index,level+1);
+ if (found)
+ {
+ match.setMatch(pos,index-pos+match.length());
+ return true;
+ }
+ index--;
+ }
+ return false;
+ };
+
+ while (tokenPos<data.size())
+ {
+ PToken tok = data[tokenPos];
+ //DBG("loop tokenPos=%zu token=%s\n",tokenPos,tok.kindStr());
+ if (tok.kind()==PToken::Kind::Character) // match literal character
+ {
+ char c_tok = tok.asciiValue();
+ if (index>=str.length() || str[index]!=c_tok) return false; // end of string, or non matching char
+ index++,tokenPos++;
+ }
+ else if (tok.isCharClass())
+ {
+ if (index>=str.length() || !matchCharClass(tokenPos,str[index])) return false;
+ index++,tokenPos+=tok.value()+1; // skip over character ranges + end token
+ }
+ else
+ {
+ switch (tok.kind())
+ {
+ case PToken::Kind::Alpha:
+ if (index>=str.length() || !isStartIdChar(str[index])) return false;
+ index++;
+ break;
+ case PToken::Kind::AlphaNum:
+ if (index>=str.length() || !isIdChar(str[index])) return false;
+ index++;
+ break;
+ case PToken::Kind::WhiteSpace:
+ if (index>=str.length() || !std::isspace(str[index])) return false;
+ index++;
+ break;
+ case PToken::Kind::Digit:
+ if (index>=str.length() || !std::isdigit(str[index])) return false;
+ index++;
+ break;
+ case PToken::Kind::BeginOfLine:
+ if (index!=pos) return false;
+ break;
+ case PToken::Kind::EndOfLine:
+ if (index<str.length()) return false;
+ break;
+ case PToken::Kind::BeginOfWord:
+ DBG("BeginOfWord: index=%zu isIdChar(%c)=%d prev.isIdChar(%c)=%d\n",
+ index,str[index],isIdChar(str[index]),
+ index>0?str[index]-1:0,
+ index>0?isIdChar(str[index-1]):-1);
+ if (index>=str.length() ||
+ !isIdChar(str[index]) ||
+ (index>0 && isIdChar(str[index-1]))) return false;
+ break;
+ case PToken::Kind::EndOfWord:
+ DBG("EndOfWord: index=%zu pos=%zu idIdChar(%c)=%d prev.isIsChar(%c)=%d\n",
+ index,pos,str[index],isIdChar(str[index]),
+ index==0 ? 0 : str[index-1],
+ index==0 ? -1 : isIdChar(str[index-1]));
+ if (index<str.length() &&
+ (isIdChar(str[index]) || index==0 || !isIdChar(str[index-1]))) return false;
+ break;
+ case PToken::Kind::BeginCapture:
+ DBG("BeginCapture(%zu)\n",index);
+ match.startCapture(index);
+ break;
+ case PToken::Kind::EndCapture:
+ DBG("EndCapture(%zu)\n",index);
+ match.endCapture(index);
+ break;
+ case PToken::Kind::Any:
+ if (index>=str.length()) return false;
+ index++;
+ break;
+ case PToken::Kind::Star:
+ return processSequence(Star);
+ case PToken::Kind::Optional:
+ return processSequence(Optional);
+ default:
+ return false;
+ }
+ tokenPos++;
+ }
+ }
+ match.setMatch(pos,index-pos);
+ return true;
+}
+
+static std::string wildcard2regex(const std::string &pattern)
+{
+ std::string result="^"; // match start of input
+ char c;
+ const char *p = pattern.c_str();
+ while ((c=*p++))
+ {
+ switch(c)
+ {
+ case '*':
+ result+=".*";
+ break; // '*' => '.*'
+ case '?':
+ result+='.';
+ break; // '?' => '.'
+ case '.':
+ case '+':
+ case '\\':
+ case '$':
+ case '^':
+ case '(':
+ case ')':
+ result+='\\'; result+=c; // escape
+ break;
+ case '[':
+ if (*p=='^') // don't escape ^ after [
+ {
+ result+="[^";
+ p++;
+ }
+ else
+ {
+ result+=c;
+ }
+ break;
+ default: // just copy
+ result+=c;
+ break;
+ }
+ }
+ result+='$'; // match end of input
+ return result;
+}
+
+
+Ex::Ex(const std::string &pattern, Mode mode)
+ : p(std::make_unique<Private>(mode==Mode::RegEx ? pattern : wildcard2regex(pattern)))
+{
+ p->compile();
+#if ENABLE_DEBUG
+ p->dump();
+ assert(!p->error);
+#endif
+}
+
+Ex::~Ex()
+{
+}
+
+bool Ex::match(const std::string &str,Match &match,size_t pos) const
+{
+ bool found=false;
+ if (p->data.size()==0 || p->error) return found;
+ match.init(&str);
+
+ PToken tok = p->data[0];
+ if (tok.kind()==PToken::Kind::BeginOfLine) // only test match at the given position
+ {
+ found = p->matchAt(0,str,match,pos,0);
+ }
+ else
+ {
+ if (tok.kind()==PToken::Kind::Character) // search for the start character
+ {
+ size_t index = str.find(tok.asciiValue(),pos);
+ if (index==std::string::npos)
+ {
+ DBG("Ex::match(str='%s',pos=%zu)=false (no start char '%c')\n",str.c_str(),pos,tok.asciiValue());
+ return false;
+ }
+ DBG("pos=%zu str='%s' char='%c' index=%zu\n",index,str.c_str(),tok.asciiValue(),index);
+ pos=index;
+ }
+ while (pos<str.length()) // search for a match starting at pos
+ {
+ found = p->matchAt(0,str,match,pos,0);
+ if (found) break;
+ pos++;
+ }
+ }
+ DBG("Ex::match(str='%s',pos=%zu)=%d\n",str.c_str(),pos,found);
+ return found;
+}
+
+bool Ex::isValid() const
+{
+ return !p->pattern.empty() && !p->error;
+}
+
+//----------------------------------------------------------------------------------------
+
+bool search(const std::string &str,Match &match,const Ex &re,size_t pos)
+{
+ return re.match(str,match,pos);
+}
+
+bool search(const std::string &str,const Ex &re,size_t pos)
+{
+ Match match;
+ return re.match(str,match,pos);
+}
+
+bool match(const std::string &str,Match &match,const Ex &re)
+{
+ return re.match(str,match,0) && match.position()==0 && match.length()==str.length();
+}
+
+bool match(const std::string &str,const Ex &re)
+{
+ Match match;
+ return re.match(str,match,0) && match.position()==0 && match.length()==str.length();
+}
+
+std::string replace(const std::string &str,const Ex &re,const std::string &replacement)
+{
+ std::string result;
+ Match match;
+ size_t p=0;
+ while (re.match(str,match,p))
+ {
+ size_t i=match.position();
+ size_t l=match.length();
+ if (i>p) result+=str.substr(p,i-p);
+ result+=replacement;
+ p=i+l;
+ }
+ if (p<str.length()) result+=str.substr(p);
+ return result;
+}
+
+}
diff --git a/src/regex.h b/src/regex.h
new file mode 100644
index 0000000..bedc052
--- /dev/null
+++ b/src/regex.h
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2021 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
+ * for any purpose. It is provided "as is" without express or implied warranty.
+ * See the GNU General Public License for more details.
+ *
+ * Documents produced by Doxygen are derivative works derived from the
+ * input used in their production; they are not affected by this license.
+ *
+ */
+
+#ifndef FREGEX_H
+#define FREGEX_H
+
+#include <memory>
+#include <string>
+#include <vector>
+#include <iterator>
+
+/** Namespace for the regular expression functions */
+namespace reg
+{
+
+class Match;
+
+/** Class representing a regular expression.
+ *
+ * It has a similar API as `std::regex`,
+ * but is much faster (and also somewhat more limited).
+ */
+class Ex
+{
+ public:
+ /** Matching algorithm */
+ enum class Mode
+ {
+ RegEx, /**< full regular expression. */
+ Wildcard /**< simple globbing pattern. */
+ };
+ /** Creates a regular expression object given the pattern as a string.
+ * Two modes of matching are supported: RegEx and Wildcard
+ *
+ * The following special characters are supported in Mode::RegEx mode.
+ * - `c` matches character `c`
+ * - `.` matches any character
+ * - `^` matches the start of the input
+ * - `$` matches the end of the input
+ * - `\<` matches the start of a word
+ * - `\>` matches the end of a word
+ * - `[]` matches a set of characters
+ * - `x*` matches a sequence of zero or more `x`'s
+ * - `x+` matches a sequence of one or more `x`'s
+ * - `x?` matches an optional `x`
+ * - `(` matches the start of a capture range
+ * - `)` matches the ends a capture range
+ * - `\c` to escape a special character, such as `+`, `[`, `*`, `(`, etc.
+ * - `\t` matches a tab character
+ * - `\n` matches a newline character
+ * - `\r` matches a return character
+ * - `\s` matches any whitespace as defined by `std::isspace()`
+ * - `\d` matches any digit as defined by `std::digit()`
+ * - `\a` matches any alphabetical characters, same as `[a-z_A-Z\x80-\xFF]`
+ * - `\w` matches any alpha numercial character, same as `[a-z_A-Z0-9\x80-\xFF]`
+ * - `\xHH` matches a hexadecimal character, e.g. `\xA0` matches character code 160.
+ *
+ * A character range can be used to match a character that falls inside a range
+ * (or set of ranges).
+ * Within the opening `[` and closing `]` brackets of a character ranges the following
+ * is supported:
+ * - `^` if at the start of the range, a character matches if it is \e not in the range,
+ * e.g. `[^\d]` matches any character not a digit
+ * - `-` when placed between 2 characters it defines a range from the first character to the second.
+ * any character that falls in the range will match, e.g. [0-9] matches the digit from 0 to 9.
+ * - `\s`, `\d`, `\a`, and `\w` as explained above.
+ *
+ * @note that special characters `.`, `*`, `?`, `$`, `+`, `[` do not have a special
+ * meaning in a character range. `^` only has a special meaning as the first character.
+ *
+ * @note that capture ranges cannot be nested, and `*`, `+`, and `?` do not work on
+ * capture ranges. e.g. `(abd)?` is not valid. If multiple capture ranges are
+ * specified then some character has to be in between them,
+ * e.g. this does not work `(.*)(a.*)`, but this does `(.*)a(.*)`.
+ *
+ * In Wildcard mode `*` is used to match any sequence of zero or more characters.
+ * The character `?` can be used to match an optional character. Character ranges are
+ * also supported, but other characters like `$` and `+` are just treated as
+ * literal characters.
+ *
+ */
+ Ex(const std::string &pattern, Mode mode=Mode::RegEx);
+
+ /** Destroys the regular expression object. Frees resources. */
+ ~Ex();
+
+ /** Check if a given string matches this regular expression.
+ * @param str The input string to match against.
+ * @param match The match object to hold the matching results.
+ * @param pos The position in the string at which to start the match.
+ * @returns true iff a match is found. Details are stored in the match object.
+ */
+ bool match(const std::string &str,Match &match,size_t pos=0) const;
+ bool isValid() const;
+ private:
+ Ex(const Ex &) = delete;
+ Ex &operator=(const Ex &e) = delete;
+
+ class Private;
+ std::unique_ptr<Private> p;
+};
+
+/** Object representing the match results of a capture range. */
+class SubMatch
+{
+ public:
+ /** Creates a match for a single capture range given a non-owning pointer to the string. */
+ SubMatch(const std::string *str) : m_str(str) {}
+
+ /** Returns the position in the string at which the match starts. */
+ size_t position() const { return m_pos; }
+
+ /** Returns the length of the matching part. */
+ size_t length() const { return m_len; }
+
+ /** Returns the matching part as a string */
+ std::string str() const { return m_str ? m_str->substr(m_pos,m_len) : std::string(); }
+
+ private:
+ friend class Match;
+ void setStart(size_t pos) { m_pos=pos; }
+ void setEnd(size_t pos) { m_len=pos-m_pos; }
+ void setMatch(size_t pos,size_t len) { m_pos=pos; m_len=len; }
+ size_t m_pos = std::string::npos;
+ size_t m_len = std::string::npos;
+ const std::string *m_str = nullptr;
+};
+
+/** Object representing the matching results. It consists of an array of
+ * SubMatch objects. The first entry of the array represents the whole match, any
+ * next elements represent each of the capture ranges.
+ *
+ * For example string `@42` and expression `@(\\d+)` will have two
+ * Submatches, match[0] will point to the input string as a whole, and
+ * match[1] will point to the number 42 only.
+ *
+ */
+class Match
+{
+ public:
+ /** Creates an empty match object */
+ Match() {}
+
+ /** Returns the position of the match or std::string::npos if no position is set. */
+ size_t position() const { return m_subMatches[0].position(); }
+
+ /** Returns the position of the match or std::string::npos if no length is set. */
+ size_t length() const { return m_subMatches[0].length(); }
+
+ /** Return a string representing the matching part. */
+ std::string str() const { return m_subMatches[0].str(); }
+
+ /** Return the part of the string after the match */
+ SubMatch suffix() const { SubMatch m(m_str); m.setMatch(0,position()); return m; }
+
+ /** Return the part of the string before the match */
+ SubMatch prefix() const
+ {
+ SubMatch m(m_str);
+ if (m_str)
+ {
+ size_t e = position()+length();
+ m.setMatch(e,m_str->length()-e);
+ }
+ return m;
+ }
+
+ /** Returns the number of sub matches available in this match. */
+ size_t size() const { return m_subMatches.size(); }
+
+ /** Returns the n-th SubMatch object. Note that there is always 1 SubMatch object
+ * representing the whole match.
+ */
+ const SubMatch &operator[](size_t index) const { return m_subMatches[index]; }
+
+ private:
+ friend class Ex;
+ void init(const std::string *str)
+ {
+ m_subMatches.clear();
+ m_subMatches.emplace_back(str);
+ m_str = str;
+ }
+ void startCapture(size_t index)
+ {
+ if (!m_insideCapture) // when backtracking we can re-entry the capture multiple times
+ // only update the index, example `\s*(x)`
+ {
+ m_captureIndex = m_subMatches.size();
+ m_subMatches.emplace_back(m_str);
+ m_insideCapture = true;
+ }
+ m_subMatches.back().setStart(index);
+ }
+ void endCapture(size_t index)
+ {
+ if (index>m_subMatches.back().position())
+ {
+ m_captureIndex=0;
+ m_subMatches.back().setEnd(index);
+ m_insideCapture = false;
+ }
+ }
+ void setMatch(size_t pos,size_t len)
+ {
+ m_subMatches[m_captureIndex].setMatch(pos,len);
+ }
+
+ std::vector<SubMatch> m_subMatches;
+ size_t m_captureIndex=0;
+ const std::string *m_str = nullptr;
+ bool m_insideCapture=false;
+};
+
+/** Iterator class to iterator through matches.
+ */
+class Iterator
+{
+ public:
+ using value_type = Match;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type*;
+ using reference = value_type&;
+ using iterator_category = std::forward_iterator_tag;
+
+ /** Creates an end-of-sequence iterator */
+ Iterator() {}
+
+ /** Creates an iterator for input string \a str, using regular expression \a re to search.
+ * @note the string and regular expression objects should remain valid while iterating.
+ */
+ Iterator(const std::string &str, const Ex &re, size_t pos=0)
+ : m_str(&str), m_re(&re), m_pos(pos) { findNext(); }
+
+ // Iterator holds pointers, so prevent temporaries to be passed as string or
+ // regular expression
+ Iterator(std::string &&str, const Ex &re) = delete;
+ Iterator(const std::string &str, Ex &&re) = delete;
+ Iterator(std::string &&str, Ex &&re) = delete;
+
+ /** Returns true if the iterators point to the same match (or both are end-of-sequence iterators) */
+ bool operator==(const Iterator &rhs) const { return rhs.m_pos==m_pos; }
+
+ /** Returns true if the iterators are not pointing to the same match */
+ bool operator!=(const Iterator &rhs) const { return rhs.m_pos!=m_pos; }
+
+ /** Returns a reference to the current match */
+ const value_type &operator*() const { return m_match; }
+
+ /** Returns a pointer to the current match */
+ const value_type *operator->() const { return &m_match; }
+
+ /** Advances the iterator to the next match. */
+ Iterator &operator++() { findNext(); return *this; }
+
+ private:
+ void findNext()
+ {
+ if (!m_re || !m_str) { m_pos=std::string::npos; return; } // end marker
+ if (m_re->match(*m_str,m_match,m_pos))
+ {
+ m_pos=m_match.position()+m_match.length(); // update m_pos to point beyond last match
+ }
+ else // no more matches, make the iterator point to the 'end-of-sequence'
+ {
+ m_pos=std::string::npos;
+ }
+ }
+ const std::string *m_str = nullptr;
+ const Ex *m_re = nullptr;
+ size_t m_pos = std::string::npos;
+ Match m_match;
+};
+
+/** Search in a given string \a str starting at position \a pos for a match against regular expression \a re.
+ * Returns true iff a match was found.
+ * Details of what part of the string has matched is returned via the \a match object.
+ *
+ * An example to show how to match all identifiers in a string.
+ * @code
+ * static reg::Ex re(R"(\a\w*)");
+ * std::string = u8"void(Func是<B_C::Códe42>(42));";
+ * while (reg::search(str,match,re,pos))
+ * {
+ * std::cout << match.str() << std::endl;
+ * pos=match.position()+match.length();
+ * }
+ * @endcode
+ * produces:
+ * @code
+ * void
+ * Func是
+ * B_C
+ * Códe42
+ * @endcode
+ *
+ * @see Ex::Ex() for details on the regular expression patterns.
+ */
+bool search(const std::string &str,Match &match,const Ex &re,size_t pos=0);
+
+/** Search in a given string \a str starting at position \a pos for a match against regular expression \a re.
+ * Returns true iff a match was found.
+ */
+bool search(const std::string &str,const Ex &re,size_t pos=0);
+
+/** Matches a given string \a str for a match against regular expression \a re.
+ * Returns true iff a match was found for the whole string.
+ * Any capture groups are returned via the \a match object.
+ */
+bool match(const std::string &str,Match &match,const Ex &re);
+
+/** Matches a given string \a str for a match against regular expression \a re.
+ * Returns true iff a match was found for the whole string.
+ */
+bool match(const std::string &str,const Ex &re);
+
+/** Searching in a given input string \a for parts that match regular expression \a re and
+ * replaces those parts by string \a replacement.
+ */
+std::string replace(const std::string &str,const Ex &re,const std::string &replacement);
+
+} // namespace
+
+#endif
diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp
index 65a5258..debda5c 100644
--- a/src/rtfgen.cpp
+++ b/src/rtfgen.cpp
@@ -22,8 +22,6 @@
#include <stdlib.h>
#include <qdir.h>
-#include <qregexp.h>
-#include <qtextstream.h>
#include "rtfgen.h"
#include "config.h"
diff --git a/src/rtfstyle.cpp b/src/rtfstyle.cpp
index 4b01002..d279eab 100644
--- a/src/rtfstyle.cpp
+++ b/src/rtfstyle.cpp
@@ -1,9 +1,6 @@
/******************************************************************************
*
- *
- *
- *
- * Copyright (C) 1997-2015 by Dimitri van Heesch.
+ * Copyright (C) 1997-2021 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
@@ -16,14 +13,12 @@
*
*/
-#include <stdlib.h>
-#include <qfile.h>
-#include <qregexp.h>
-#include <qtextstream.h>
+#include <string>
+#include <fstream>
#include "rtfstyle.h"
#include "message.h"
-
+#include "regex.h"
RTFListItemInfo rtf_listItemInfo[rtf_maxIndentLevels];
@@ -38,6 +33,21 @@ QCString rtf_documentType;
QCString rtf_documentId;
QCString rtf_keywords;
+static std::map<std::string,QCString &> g_styleMap =
+{
+ { "Title", rtf_title },
+ { "Subject", rtf_subject },
+ { "Comments", rtf_comments },
+ { "Company", rtf_company },
+ { "LogoFilename", rtf_logoFilename },
+ { "Author", rtf_author },
+ { "Manager", rtf_manager },
+ { "DocumentType", rtf_documentType },
+ { "DocumentId", rtf_documentId },
+ { "Keywords", rtf_keywords }
+};
+
+
char rtf_Style_Reset[] = "\\pard\\plain ";
#define RTF_LatexToc(lvl,nest,nxt,pos,twps) \
@@ -224,116 +234,80 @@ Rtf_Style_Default rtf_Style_Default[] =
}
};
-static const QRegExp s_clause("\\\\s[0-9]+\\s*");
+static const reg::Ex s_clause(R"(\\s(\d+)\s*)"); // match, e.g. '\s30' and capture '30'
-StyleData::StyleData(const char* reference, const char* definition)
+StyleData::StyleData(const std::string &reference, const std::string &definition)
{
- const char *ref = reference;
-
- int start = s_clause.match(ref); ASSERT(start >= 0);
- ref += start;
- m_index = (int)atol(ref + 2); ASSERT(m_index > 0);
-
- m_reference = ref;
+ reg::Match match;
+ if (reg::search(reference,match,s_clause))
+ {
+ m_index = static_cast<int>(std::stoul(match[1].str()));
+ }
+ else // error
+ {
+ m_index = 0;
+ }
+ m_reference = reference;
m_definition = definition;
}
-bool StyleData::setStyle(const char* s, const char* styleName)
+bool StyleData::setStyle(const std::string &command, const std::string &styleName)
{
- static const QRegExp subgroup("^{[^}]*}\\s*");
- static const QRegExp any_clause("^\\\\[a-z][a-z0-9-]*\\s*");
-
- int len = 0; // length of a particular RTF formatting control
- int ref_len = 0; // length of the whole formatting section of a style
- int start = s_clause.match(s, 0, &len);
- if (start < 0)
+ reg::Match match;
+ if (!reg::search(command,match,s_clause))
{
- err("Style sheet '%s' contains no '\\s' clause.\n{%s}\n", styleName, s);
- return FALSE;
- }
- s += start;
- m_index = (int)atol(s + 2); ASSERT(m_index > 0);
-
- // search for the end of pure formatting codes
- const char* end = s + len;
- ref_len = len;
- bool haveNewDefinition = TRUE;
- for(;;)
- {
- if (*end == '{')
- {
- // subgroups are used for \\additive
- if (0 != subgroup.match(end, 0, &len))
- break;
- else
- {
- end += len;
- ref_len += len;
- }
- }
- else if (*end == '\\')
- {
- if (0 == qstrncmp(end, "\\snext", 6))
- break;
- if (0 == qstrncmp(end, "\\sbasedon", 9))
- break;
- if (0 != any_clause.match(end, 0, &len))
- break;
- end += len;
- ref_len += len;
- }
- else if (*end == 0)
- { // no style-definition part, keep default value
- haveNewDefinition = FALSE;
- break;
- }
- else // plain name without leading \\snext
- break;
+ err("Style sheet '%s' contains no '\\s' clause.\n{%s}", styleName.c_str(), command.c_str());
+ return false;
}
- m_reference = s;
- if (haveNewDefinition)
+ m_index = static_cast<int>(std::stoul(match[1].str()));
+
+ size_t index = command.find("\\sbasedon");
+ if (index!=std::string::npos)
{
- m_definition = end;
+ m_reference = command.substr(0,index);
+ m_definition = command.substr(index);
}
- return TRUE;
+
+ return true;
}
+
void loadStylesheet(const char *name, StyleDataMap& map)
{
- QFile file(name);
- if (!file.open(IO_ReadOnly))
+ std::ifstream file(name);
+ if (!file.is_open())
{
- err("Can't open RTF style sheet file %s. Using defaults.\n",name);
+ err("Can't open RTF style sheet file %s. Using defaults.",name);
return;
}
msg("Loading RTF style sheet %s...\n",name);
- static const QRegExp separator("[ \t]*=[ \t]*");
uint lineNr=1;
- QTextStream t(&file);
- while (!t.eof())
+ for (std::string line ; getline(file,line) ; ) // for each line
{
- QCString s(4096); // string buffer of max line length
- s = t.readLine().stripWhiteSpace().utf8();
- if (s.isEmpty() || s.at(0)=='#') continue; // skip blanks & comments
- int sepLength;
- int sepStart = separator.match(s,0,&sepLength);
- if (sepStart<=0) // no valid assignment statement
+ if (line.empty() || line[0]=='#') continue; // skip blanks & comments
+ static const reg::Ex assignment_splitter(R"(\s*=\s*)");
+ reg::Match match;
+ if (reg::search(line,match,assignment_splitter))
{
- warn(name,lineNr,"Assignment of style sheet name expected!\n");
- continue;
+ std::string key = match.prefix().str();
+ std::string value = match.suffix().str();
+ auto it = map.find(key);
+ if (it!=map.end())
+ {
+ StyleData& styleData = it->second;
+ styleData.setStyle(value,key);
+ }
+ else
+ {
+ warn(name,lineNr,"Unknown style sheet name %s ignored.",key.data());
+ }
}
- QCString key=s.left(sepStart);
- auto it = map.find(key.str());
- if (it==map.end()) // not a valid style sheet name
+ else
{
- warn(name,lineNr,"Unknown style sheet name %s ignored.\n",key.data());
- continue;
+ warn(name,lineNr,"Assignment of style sheet name expected line='%s'!",line.c_str());
}
- StyleData& styleData = it->second;
- s+=" "; // add command separator
- styleData.setStyle(s.data() + sepStart + sepLength, key.data());
lineNr++;
}
}
@@ -342,44 +316,39 @@ StyleDataMap rtf_Style;
void loadExtensions(const char *name)
{
- QFile file(name);
- if (!file.open(IO_ReadOnly))
+ std::ifstream file(name);
+ if (!file.is_open())
{
- err("Can't open RTF extensions file %s. Using defaults.\n",name);
+ err("Can't open RTF extensions file %s. Using defaults.",name);
return;
}
msg("Loading RTF extensions %s...\n",name);
- static const QRegExp separator("[ \t]*=[ \t]*");
uint lineNr=1;
- QTextStream t(&file);
- t.setEncoding(QTextStream::UnicodeUTF8);
- while (!t.eof())
+ for (std::string line ; getline(file,line) ; ) // for each line
{
- QCString s(4096); // string buffer of max line length
- s = t.readLine().stripWhiteSpace().utf8();
- if (s.length()==0 || s.at(0)=='#') continue; // skip blanks & comments
- int sepLength;
- int sepStart = separator.match(s,0,&sepLength);
- if (sepStart<=0) // no valid assignment statement
+ if (line.empty() || line[0]=='#') continue; // skip blanks & comments
+ static const reg::Ex assignment_splitter(R"(\s*=\s*)");
+ reg::Match match;
+ if (reg::search(line,match,assignment_splitter))
+ {
+ std::string key = match.prefix().str();
+ std::string value = match.suffix().str();
+ auto it = g_styleMap.find(key);
+ if (it!=g_styleMap.end())
+ {
+ it->second = value;
+ }
+ else
+ {
+ warn(name,lineNr,"Ignoring unknown extension key '%s'...",key.c_str());
+ }
+ }
+ else
{
- warn(name,lineNr,"Assignment of extension field expected!\n");
- continue;
+ warn(name,lineNr,"Assignment of style sheet name expected!");
}
- QCString key=s.left(sepStart);
- QCString data=s.data() + sepStart + sepLength;
-
- if (key == "Title") rtf_title = data.data();
- if (key == "Subject") rtf_subject = data.data();
- if (key == "Comments") rtf_comments = data.data();
- if (key == "Company") rtf_company = data.data();
- if (key == "LogoFilename") rtf_logoFilename = data.data();
- if (key == "Author") rtf_author = data.data();
- if (key == "Manager") rtf_manager = data.data();
- if (key == "DocumentType") rtf_documentType = data.data();
- if (key == "DocumentId") rtf_documentId = data.data();
- if (key == "Keywords") rtf_keywords = data.data();
lineNr++;
}
}
diff --git a/src/rtfstyle.h b/src/rtfstyle.h
index b3d04bd..140d31f 100644
--- a/src/rtfstyle.h
+++ b/src/rtfstyle.h
@@ -63,8 +63,8 @@ struct StyleData
public:
StyleData() = default;
- StyleData(const char* reference, const char* definition);
- bool setStyle(const char* s, const char* styleName);
+ StyleData(const std::string &reference, const std::string &definition);
+ bool setStyle(const std::string &command, const std::string &styleName);
const char *reference() const { return m_reference.c_str(); }
const char *definition() const { return m_definition.c_str(); }
uint index() const { return m_index; }
diff --git a/src/scanner.l b/src/scanner.l
index 6970d3e..0193689 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -1,8 +1,6 @@
/*****************************************************************************
*
- *
- *
- * Copyright (C) 1997-2015 by Dimitri van Heesch.
+ * Copyright (C) 1997-2021 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
@@ -37,7 +35,6 @@
#include <assert.h>
#include <ctype.h>
-#include <qregexp.h>
#include <qfile.h>
#include "scanner.h"
@@ -53,6 +50,7 @@
#include "clangparser.h"
#include "markdown.h"
+#include "regex.h"
#define YY_NO_INPUT 1
#define YY_NO_UNISTD_H 1
@@ -3741,9 +3739,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
else
{
- static QRegExp re("@[0-9]+$");
+ static const reg::Ex re(R"(@\d+$)");
if (!yyextra->isTypedef && yyextra->memspecEntry &&
- yyextra->memspecEntry->name.find(re)==-1) // not typedef or anonymous type (see bug691071)
+ !reg::search(yyextra->memspecEntry->name.str(),re)) // not typedef or anonymous type (see bug691071)
{
// enabled the next two lines for bug 623424
yyextra->current->doc.resize(0);
@@ -4833,10 +4831,16 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
yyextra->current->fileName = yyextra->yyFileName;
yyextra->current->startLine = yyextra->yyBegLineNr;
yyextra->current->startColumn = yyextra->yyBegColNr;
- static QRegExp re("([^)]*[*&][^)]*)"); // (...*...)
+ static const reg::Ex re(R"(\([^)]*[*&][^)]*\))");
+ reg::Match match;
+ std::string type = yyextra->current->type.str();
+ int ti=-1;
+ if (reg::search(type,match,re))
+ {
+ ti = (int)match.position();
+ }
int ts=yyextra->current->type.find('<');
int te=yyextra->current->type.findRev('>');
- int ti=yyextra->current->type.find(re,0);
// bug677315: A<int(void *, char *)> get(); is not a function pointer
bool isFunction = ti==-1 || // not a (...*...) pattern
@@ -6891,13 +6895,24 @@ static void splitKnRArg(yyscan_t yyscanner,QCString &oldStyleArgPtr,QCString &ol
int si = yyextra->current->args.length();
if (yyextra->oldStyleArgType.isEmpty()) // new argument
{
- static QRegExp re("([^)]*)");
- int bi1 = yyextra->current->args.findRev(re);
- int bi2 = bi1!=-1 ? yyextra->current->args.findRev(re,bi1-1) : -1;
+ std::string args = yyextra->current->args.str();
+ static const reg::Ex re(R"(\([^)]*\).*)"); // find first (...)
+ int bi1=-1;
+ int bi2=-1;
+ reg::Match match;
+ if (reg::search(args,match,re))
+ {
+ bi1=(int)match.position();
+ size_t secondMatchStart = match.position()+match.length(); // search again after first match
+ if (reg::search(args,match,re,secondMatchStart))
+ {
+ bi2=(int)match.position();
+ }
+ }
char c;
if (bi1!=-1 && bi2!=-1) // found something like "int (*func)(int arg)"
{
- int s=bi2+1;
+ int s=bi2+1; // keep opening (
yyextra->oldStyleArgType = yyextra->current->args.left(s);
int i=s;
while (i<si && ((c=yyextra->current->args.at(i))=='*' || isspace((uchar)c))) i++;
@@ -6909,7 +6924,7 @@ static void splitKnRArg(yyscan_t yyscanner,QCString &oldStyleArgPtr,QCString &ol
}
else if (bi1!=-1) // redundant braces like in "int (*var)"
{
- int s=bi1;
+ int s=bi1; // strip opening (
yyextra->oldStyleArgType = yyextra->current->args.left(s);
s++;
int i=s+1;
diff --git a/src/searchindex.cpp b/src/searchindex.cpp
index 89f1681..61d2d6c 100644
--- a/src/searchindex.cpp
+++ b/src/searchindex.cpp
@@ -18,7 +18,6 @@
#include <assert.h>
#include <qfile.h>
-#include <qregexp.h>
#include "searchindex.h"
#include "config.h"
@@ -200,7 +199,6 @@ static int charsToIndex(const char *word)
void SearchIndex::addWord(const char *word,bool hiPriority,bool recurse)
{
- static QRegExp nextPart("[_a-z:][A-Z]");
if (word==0 || word[0]=='\0') return;
QCString wStr = QCString(word).lower();
//printf("SearchIndex::addWord(%s,%d) wStr=%s\n",word,hiPriority,wStr.data());
@@ -227,7 +225,14 @@ void SearchIndex::addWord(const char *word,bool hiPriority,bool recurse)
}
if (!found) // no prefix stripped
{
- if ((i=nextPart.match(word))>=1)
+ i=0;
+ while (word[i]!=0 &&
+ !((word[i]=='_' || word[i]==':' || (word[i]>='a' && word[i]<='z')) && // [_a-z:]
+ (word[i+1]>='A' && word[i+1]<='Z'))) // [A-Z]
+ {
+ i++;
+ }
+ if (word[i]!=0 && i>=1)
{
addWord(word+i+1,hiPriority,TRUE);
}
diff --git a/src/sqlite3gen.cpp b/src/sqlite3gen.cpp
index cc53b13..222b076 100644
--- a/src/sqlite3gen.cpp
+++ b/src/sqlite3gen.cpp
@@ -2348,7 +2348,7 @@ static void generateSqlite3ForPage(const PageDef *pd,bool isExample)
{
if (mainPageHasTitle())
{
- title = filterTitle(convertCharEntitiesToUTF8(Doxygen::mainPage->title()));
+ title = filterTitle(convertCharEntitiesToUTF8(Doxygen::mainPage->title()).str());
}
else
{
diff --git a/src/symbolresolver.cpp b/src/symbolresolver.cpp
index 9f80c15..dd9e0f7 100644
--- a/src/symbolresolver.cpp
+++ b/src/symbolresolver.cpp
@@ -521,7 +521,7 @@ const ClassDef *SymbolResolver::Private::newResolveTypedef(
if (typeClass && typeClass->isTemplate() &&
actTemplParams && !actTemplParams->empty())
{
- type = substituteTemplateArgumentsInString(type,
+ type = substituteTemplateArgumentsInString(type.str(),
typeClass->templateArguments(),actTemplParams);
}
QCString typedefValue = type;
diff --git a/src/template.cpp b/src/template.cpp
index a7d9bbb..9f1eb92 100644
--- a/src/template.cpp
+++ b/src/template.cpp
@@ -22,7 +22,6 @@
#include <cstdio>
#include <qfile.h>
-#include <qregexp.h>
#include <qdir.h>
#include "ftextstream.h"
@@ -30,6 +29,7 @@
#include "util.h"
#include "resourcemgr.h"
#include "portable.h"
+#include "regex.h"
#define ENABLE_TRACING 0
@@ -4184,26 +4184,32 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers>
{
TemplateListIntf::ConstIterator *it = list->createIterator();
c->push();
- QCString str = patternStr.toString();
- QRegExp marker("@[0-9]+"); // pattern for a marker, i.e. @0, @1 ... @12, etc
- int index=0,newIndex,matchLen;
- while ((newIndex=marker.match(str,index,&matchLen))!=-1)
+ std::string str = patternStr.toString().str();
+
+ static const reg::Ex marker(R"(@\d+)");
+ reg::Iterator re_it(str,marker);
+ reg::Iterator end;
+ size_t index=0;
+ for ( ; re_it!=end ; ++re_it)
{
+ const auto &match = *re_it;
+ size_t newIndex = match.position();
+ size_t matchLen = match.length();
+ std::string part = str.substr(index,newIndex-index);
if (ci->needsRecoding())
{
- ts << ci->recode(str.mid(index,newIndex-index)); // write text before marker
+ ts << ci->recode(part); // write text before marker
}
else
{
- ts << str.mid(index,newIndex-index); // write text before marker
+ ts << part; // write text before marker
}
- bool ok;
- uint entryIndex = str.mid(newIndex+1,matchLen-1).toUInt(&ok); // get marker id
+ unsigned long entryIndex = std::stoul(match.str().substr(1));
TemplateVariant var;
- uint i=0;
+ size_t i=0;
// search for list element at position id
for (it->toFirst(); (it->current(var)) && i<entryIndex; it->toNext(),i++) {}
- if (ok && i==entryIndex) // found element
+ if (i==entryIndex) // found element
{
TemplateAutoRef<TemplateStruct> s(TemplateStruct::alloc());
s->set("id",(int)i);
@@ -4214,10 +4220,6 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers>
m_nodes.render(ts,c);
ci->enableSpaceless(wasSpaceless);
}
- else if (!ok)
- {
- ci->warn(m_templateName,m_line,"markers pattern string has invalid markers '%s'",str.data());
- }
else if (i<entryIndex)
{
ci->warn(m_templateName,m_line,"markers list does not an element for marker position %d",i);
@@ -4226,11 +4228,11 @@ class TemplateNodeMarkers : public TemplateNodeCreator<TemplateNodeMarkers>
}
if (ci->needsRecoding())
{
- ts << ci->recode(str.right(str.length()-index)); // write text after last marker
+ ts << ci->recode(str.substr(index)); // write text after last marker
}
else
{
- ts << str.right(str.length()-index); // write text after last marker
+ ts << str.substr(index); // write text after last marker
}
c->pop();
delete it;
diff --git a/src/util.cpp b/src/util.cpp
index 3bf349a..1677b26 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -15,23 +15,26 @@
*/
#include <stdlib.h>
-#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <limits.h>
-#include <cinttypes>
#include <string.h>
-#include <ctime>
#include <mutex>
#include <unordered_set>
+#include <codecvt>
+#include <iostream>
+#include <algorithm>
+#include <ctime>
+#include <cctype>
+#include <cinttypes>
#include "md5.h"
-#include <qregexp.h>
#include <qfileinfo.h>
#include <qdir.h>
+#include "regex.h"
#include "util.h"
#include "message.h"
#include "classdef.h"
@@ -158,54 +161,68 @@ const int maxInheritanceDepth = 100000;
"bla @1" => "bla"
\endverbatim
*/
-QCString removeAnonymousScopes(const QCString &s)
+QCString removeAnonymousScopes(const char *str)
{
- QCString result;
- if (s.isEmpty()) return result;
- static QRegExp re("[ :]*@[0-9]+[: ]*");
- int i,l,sl=s.length();
- int p=0;
- while ((i=re.match(s,p,&l))!=-1)
+ std::string result;
+ if (str==0) return result;
+
+ // helper to check if the found delimiter starts with a colon
+ auto startsWithColon = [](const std::string &del)
{
- result+=s.mid(p,i-p);
- int c=i;
- bool b1=FALSE,b2=FALSE;
- while (c<i+l && s.at(c)!='@') if (s.at(c++)==':') b1=TRUE;
- c=i+l-1;
- while (c>=i && s.at(c)!='@') if (s.at(c--)==':') b2=TRUE;
- if (b1 && b2)
+ for (size_t i=0;i<del.size();i++)
{
- result+="::";
+ if (del[i]=='@') return false;
+ else if (del[i]==':') return true;
}
- p=i+l;
- }
- result+=s.right(sl-p);
- //printf("removeAnonymousScopes('%s')='%s'\n",s.data(),result.data());
- return result;
-}
+ return false;
+ };
-// replace anonymous scopes with __anonymous__ or replacement if provided
-QCString replaceAnonymousScopes(const QCString &s,const char *replacement)
-{
- QCString result;
- if (s.isEmpty()) return result;
- static QRegExp re("@[0-9]+");
- int i,l,sl=s.length();
- int p=0;
- while ((i=re.match(s,p,&l))!=-1)
+ // helper to check if the found delimiter ends with a colon
+ auto endsWithColon = [](const std::string &del)
{
- result+=s.mid(p,i-p);
- if (replacement)
+ for (int i=(int)del.size()-1;i>=0;i--)
{
- result+=replacement;
+ if (del[i]=='@') return false;
+ else if (del[i]==':') return true;
}
- else
+ return false;
+ };
+
+ static const reg::Ex re(R"([\s:]*@\d+[\s:]*)");
+ std::string s = str;
+ reg::Iterator iter(s,re);
+ reg::Iterator end;
+ size_t p=0;
+ size_t sl=s.length();
+ bool needsSeparator=false;
+ for ( ; iter!=end ; ++iter)
+ {
+ const auto &match = *iter;
+ size_t i = match.position();
+ if (i>p) // add non-matching prefix
{
- result+="__anonymous__";
+ if (needsSeparator) result+="::";
+ needsSeparator=false;
+ result+=s.substr(p,i-p);
}
- p=i+l;
+ std::string delim = match.str();
+ needsSeparator = needsSeparator || (startsWithColon(delim) && endsWithColon(delim));
+ p = match.position()+match.length();
}
- result+=s.right(sl-p);
+ if (p<sl) // add trailing remainder
+ {
+ if (needsSeparator) result+="::";
+ result+=s.substr(p);
+ }
+ return result;
+}
+
+// replace anonymous scopes with __anonymous__ or replacement if provided
+QCString replaceAnonymousScopes(const char *s,const char *replacement)
+{
+ if (s==0) return QCString();
+ static const reg::Ex marker(R"(@\d+)");
+ std::string result = reg::replace(s,marker,replacement?replacement:"__anonymous__");
//printf("replaceAnonymousScopes('%s')='%s'\n",s.data(),result.data());
return result;
}
@@ -872,37 +889,40 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
const char *text, bool autoBreak,bool external,
bool keepSpaces,int indentLevel)
{
- //printf("linkify='%s'\n",text);
- static QRegExp regExp("[a-z_A-Z\\x80-\\xFF][~!a-z_A-Z0-9$\\\\.:\\x80-\\xFF]*");
- static QRegExp regExpSplit("(?!:),");
if (text==0) return;
- QCString txtStr=text;
- int strLen = txtStr.length();
+ //printf("linkify='%s'\n",text);
+ std::string txtStr=text;
+ size_t strLen = txtStr.length();
if (strLen==0) return;
+
+ static const reg::Ex regExp(R"(\a[\w~!\\.:$]*)");
+ reg::Iterator it(txtStr,regExp);
+ reg::Iterator end;
+
//printf("linkifyText scope=%s fileScope=%s strtxt=%s strlen=%d external=%d\n",
// scope?scope->name().data():"<none>",
// fileScope?fileScope->name().data():"<none>",
// txtStr.data(),strLen,external);
- int matchLen;
- int index=0;
- int newIndex;
- int skipIndex=0;
- int floatingIndex=0;
- // read a word from the text string
- while ((newIndex=regExp.match(txtStr,index,&matchLen))!=-1)
- {
+ size_t index=0;
+ size_t skipIndex=0;
+ size_t floatingIndex=0;
+ for (; it!=end ; ++it) // for each word from the text string
+ {
+ const auto &match = *it;
+ size_t newIndex = match.position();
+ size_t matchLen = match.length();
floatingIndex+=newIndex-skipIndex+matchLen;
if (newIndex>0 && txtStr.at(newIndex-1)=='0') // ignore hex numbers (match x00 in 0x00)
{
- out.writeString(txtStr.mid(skipIndex,newIndex+matchLen-skipIndex),keepSpaces);
+ std::string part = txtStr.substr(skipIndex,newIndex+matchLen-skipIndex);
+ out.writeString(part.c_str(),keepSpaces);
skipIndex=index=newIndex+matchLen;
continue;
}
// add non-word part to the result
bool insideString=FALSE;
- int i;
- for (i=index;i<newIndex;i++)
+ for (size_t i=index;i<newIndex;i++)
{
if (txtStr.at(i)=='"') insideString=!insideString;
}
@@ -910,33 +930,36 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
//printf("floatingIndex=%d strlen=%d autoBreak=%d\n",floatingIndex,strLen,autoBreak);
if (strLen>35 && floatingIndex>30 && autoBreak) // try to insert a split point
{
- QCString splitText = txtStr.mid(skipIndex,newIndex-skipIndex);
- int splitLength = splitText.length();
- int offset=1;
- i=splitText.find(regExpSplit,0);
- if (i==-1) { i=splitText.find('<'); if (i!=-1) offset=0; }
- if (i==-1) i=splitText.find('>');
- if (i==-1) i=splitText.find(' ');
+ std::string splitText = txtStr.substr(skipIndex,newIndex-skipIndex);
+ size_t splitLength = splitText.length();
+ size_t offset=1;
+ size_t i = splitText.find(',');
+ if (i==std::string::npos) { i=splitText.find('<'); if (i!=std::string::npos) offset=0; }
+ if (i==std::string::npos) i=splitText.find('>');
+ if (i==std::string::npos) i=splitText.find(' ');
//printf("splitText=[%s] len=%d i=%d offset=%d\n",splitText.data(),splitLength,i,offset);
- if (i!=-1) // add a link-break at i in case of Html output
+ if (i!=std::string::npos) // add a link-break at i in case of Html output
{
- out.writeString(splitText.left(i+offset),keepSpaces);
+ std::string part1 = splitText.substr(0,i+offset);
+ out.writeString(part1.c_str(),keepSpaces);
out.writeBreak(indentLevel==0 ? 0 : indentLevel+1);
- out.writeString(splitText.right(splitLength-i-offset),keepSpaces);
+ std::string part2 = splitText.substr(i+offset);
+ out.writeString(part2.c_str(),keepSpaces);
floatingIndex=splitLength-i-offset+matchLen;
}
else
{
- out.writeString(splitText,keepSpaces);
+ out.writeString(splitText.c_str(),keepSpaces);
}
}
else
{
//ol.docify(txtStr.mid(skipIndex,newIndex-skipIndex));
- out.writeString(txtStr.mid(skipIndex,newIndex-skipIndex),keepSpaces);
+ std::string part = txtStr.substr(skipIndex,newIndex-skipIndex);
+ out.writeString(part.c_str(),keepSpaces);
}
// get word from string
- QCString word=txtStr.mid(newIndex,matchLen);
+ std::string word=txtStr.substr(newIndex,matchLen);
QCString matchWord = substitute(substitute(word,"\\","::"),".","::");
//printf("linkifyText word=%s matchWord=%s scope=%s\n",
// word.data(),matchWord.data(),scope?scope->name().data():"<none>");
@@ -963,7 +986,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
out.writeLink(typeDef->getReference(),
typeDef->getOutputFileBase(),
typeDef->anchor(),
- word);
+ word.c_str());
found=TRUE;
}
}
@@ -976,7 +999,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
{
if (cd!=self)
{
- out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word);
+ out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word.c_str());
found=TRUE;
}
}
@@ -988,7 +1011,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
{
if (cd!=self)
{
- out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word);
+ out.writeLink(cd->getReference(),cd->getOutputFileBase(),cd->anchor(),word.c_str());
found=TRUE;
}
}
@@ -1048,7 +1071,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
if (!(scope && (scope->getLanguage() == SrcLangExt_Fortran) && md->isVariable() && (md->getLanguage() != SrcLangExt_Fortran)))
{
out.writeLink(md->getReference(),md->getOutputFileBase(),
- md->anchor(),word);
+ md->anchor(),word.c_str());
//printf("found symbol %s\n",matchWord.data());
found=TRUE;
}
@@ -1058,7 +1081,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
if (!found) // add word to the result
{
- out.writeString(word,keepSpaces);
+ out.writeString(word.c_str(),keepSpaces);
}
// set next start point in the string
//printf("index=%d/%d\n",index,txtStr.length());
@@ -1066,52 +1089,59 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
}
// add last part of the string to the result.
//ol.docify(txtStr.right(txtStr.length()-skipIndex));
- out.writeString(txtStr.right(txtStr.length()-skipIndex),keepSpaces);
+ std::string lastPart = txtStr.substr(skipIndex);
+ out.writeString(lastPart.c_str(),keepSpaces);
}
-
-void writeExamples(OutputList &ol,const ExampleList &list)
+void writeMarkerList(OutputList &ol,const std::string &markerText,size_t numMarkers,
+ std::function<void(size_t)> replaceFunc)
{
- QCString exampleLine=theTranslator->trWriteList((int)list.size());
-
- //bool latexEnabled = ol.isEnabled(OutputGenerator::Latex);
- //bool manEnabled = ol.isEnabled(OutputGenerator::Man);
- //bool htmlEnabled = ol.isEnabled(OutputGenerator::Html);
- QRegExp marker("@[0-9]+");
- int index=0,newIndex,matchLen;
+ static const reg::Ex marker(R"(@(\d+))");
+ reg::Iterator it(markerText,marker);
+ reg::Iterator end;
+ size_t index=0;
// now replace all markers in inheritLine with links to the classes
- while ((newIndex=marker.match(exampleLine,index,&matchLen))!=-1)
+ for ( ; it!=end ; ++it)
{
- bool ok;
- ol.parseText(exampleLine.mid(index,newIndex-index));
- uint entryIndex = exampleLine.mid(newIndex+1,matchLen-1).toUInt(&ok);
- if (ok && entryIndex<list.size())
+ const auto &match = *it;
+ size_t newIndex = match.position();
+ size_t matchLen = match.length();
+ ol.parseText(markerText.substr(index,newIndex-index));
+ unsigned long entryIndex = std::stoul(match[1].str());
+ if (entryIndex<(unsigned long)numMarkers)
{
- const auto &e = list[entryIndex];
- ol.pushGeneratorState();
- //if (latexEnabled) ol.disable(OutputGenerator::Latex);
- ol.disable(OutputGenerator::Latex);
- ol.disable(OutputGenerator::RTF);
- ol.disable(OutputGenerator::Docbook);
- // link for Html / man
- //printf("writeObjectLink(file=%s)\n",e->file.data());
- ol.writeObjectLink(0,e.file,e.anchor,e.name);
- ol.popGeneratorState();
-
- ol.pushGeneratorState();
- //if (latexEnabled) ol.enable(OutputGenerator::Latex);
- ol.disable(OutputGenerator::Man);
- ol.disable(OutputGenerator::Html);
- // link for Latex / pdf with anchor because the sources
- // are not hyperlinked (not possible with a verbatim environment).
- ol.writeObjectLink(0,e.file,0,e.name);
- //if (manEnabled) ol.enable(OutputGenerator::Man);
- //if (htmlEnabled) ol.enable(OutputGenerator::Html);
- ol.popGeneratorState();
+ replaceFunc(entryIndex);
}
index=newIndex+matchLen;
}
- ol.parseText(exampleLine.right(exampleLine.length()-index));
+ ol.parseText(markerText.substr(index));
+}
+
+void writeExamples(OutputList &ol,const ExampleList &list)
+{
+ auto replaceFunc = [&list,&ol](size_t entryIndex)
+ {
+ const auto &e = list[entryIndex];
+ ol.pushGeneratorState();
+ ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::RTF);
+ ol.disable(OutputGenerator::Docbook);
+ // link for Html / man
+ //printf("writeObjectLink(file=%s)\n",e->file.data());
+ ol.writeObjectLink(0,e.file,e.anchor,e.name);
+ ol.popGeneratorState();
+
+ ol.pushGeneratorState();
+ ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Html);
+ // link for Latex / pdf with anchor because the sources
+ // are not hyperlinked (not possible with a verbatim environment).
+ ol.writeObjectLink(0,e.file,0,e.name);
+ ol.popGeneratorState();
+ };
+
+ writeMarkerList(ol, theTranslator->trWriteList((int)list.size()).str(), list.size(), replaceFunc);
+
ol.writeString(".");
}
@@ -1260,8 +1290,14 @@ static QCString getFilterFromList(const char *name,const StringVector &filterLis
if (i_equals!=-1)
{
QCString filterPattern = fs.left(i_equals);
- QRegExp fpat(filterPattern,Portable::fileSystemIsCaseSensitive(),TRUE);
- if (fpat.match(name)!=-1)
+ QCString input = name;
+ if (!Portable::fileSystemIsCaseSensitive())
+ {
+ filterPattern = filterPattern.lower();
+ input = input.lower();
+ }
+ reg::Ex re(filterPattern.str(),reg::Ex::Mode::Wildcard);
+ if (re.isValid() && reg::match(input.str(),re))
{
// found a match!
QCString filterName = fs.mid(i_equals+1);
@@ -1818,8 +1854,6 @@ static QCString extractCanonicalType(const Definition *d,const FileDef *fs,QCStr
//printf("extractCanonicalType(type=%s) start: def=%s file=%s\n",type.data(),
// d ? d->name().data() : "<null>",fs ? fs->name().data() : "<null>");
- //static QRegExp id("[a-z_A-Z\\x80-\\xFF][:a-z_A-Z0-9\\x80-\\xFF]*");
-
QCString canType;
QCString templSpec,word;
int i,p=0,pp=0;
@@ -1848,17 +1882,25 @@ static QCString extractCanonicalType(const Definition *d,const FileDef *fs,QCStr
// (i.e. type is not a template specialization)
// then resolve any identifiers inside.
{
- static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
- int tp=0,tl,ti;
+ std::string ts = templSpec.str();
+ static const reg::Ex re(R"(\a\w*)");
+ reg::Iterator it(ts,re);
+ reg::Iterator end;
+
+ size_t tp=0;
// for each identifier template specifier
//printf("adding resolved %s to %s\n",templSpec.data(),canType.data());
- while ((ti=re.match(templSpec,tp,&tl))!=-1)
- {
- canType += templSpec.mid(tp,ti-tp);
- canType += getCanonicalTypeForIdentifier(d,fs,templSpec.mid(ti,tl),0);
+ for (; it!=end ; ++it)
+ {
+ const auto &match = *it;
+ size_t ti = match.position();
+ size_t tl = match.length();
+ std::string matchStr = match.str();
+ canType += ts.substr(tp,ti-tp);
+ canType += getCanonicalTypeForIdentifier(d,fs,matchStr.c_str(),0);
tp=ti+tl;
}
- canType+=templSpec.right(templSpec.length()-tp);
+ canType+=ts.substr(tp);
}
pp=p;
@@ -3236,34 +3278,6 @@ void generateFileRef(OutputDocInterface &od,const char *name,const char *text)
//----------------------------------------------------------------------
-#if 0
-QCString substituteClassNames(const QCString &s)
-{
- int i=0,l,p;
- QCString result;
- if (s.isEmpty()) return result;
- QRegExp r("[a-z_A-Z][a-z_A-Z0-9]*");
- while ((p=r.match(s,i,&l))!=-1)
- {
- QCString *subst;
- if (p>i) result+=s.mid(i,p-i);
- if ((subst=substituteDict[s.mid(p,l)]))
- {
- result+=*subst;
- }
- else
- {
- result+=s.mid(p,l);
- }
- i=p+l;
- }
- result+=s.mid(i,s.length()-i);
- return result;
-}
-#endif
-
-//----------------------------------------------------------------------
-
/** Cache element for the file name to FileDef mapping cache. */
struct FindFileCacheElem
{
@@ -4240,21 +4254,27 @@ QCString convertToLaTeX(const QCString &s,bool insideTabbing,bool keepSpaces)
-QCString convertCharEntitiesToUTF8(const QCString &s)
+QCString convertCharEntitiesToUTF8(const char *str)
{
- QCString result;
- static QRegExp entityPat("&[a-zA-Z]+[0-9]*;");
+ if (str==0) return QCString();
+
+ std::string s = str;
+ static const reg::Ex re(R"(&\a\w*;)");
+ reg::Iterator it(s,re);
+ reg::Iterator end;
- if (s.length()==0) return result;
GrowBuf growBuf;
- int p,i=0,l;
- while ((p=entityPat.match(s,i,&l))!=-1)
+ size_t p,i=0,l;
+ for (; it!=end ; ++it)
{
+ const auto &match = *it;
+ p = match.position();
+ l = match.length();
if (p>i)
{
- growBuf.addStr(s.mid(i,p-i));
+ growBuf.addStr(s.substr(i,p-i));
}
- QCString entity = s.mid(p,l);
+ std::string entity = match.str();
DocSymbol::SymType symType = HtmlEntityMapper::instance()->name2sym(entity);
const char *code=0;
if (symType!=DocSymbol::Sym_Unknown && (code=HtmlEntityMapper::instance()->utf8(symType)))
@@ -4263,11 +4283,11 @@ QCString convertCharEntitiesToUTF8(const QCString &s)
}
else
{
- growBuf.addStr(s.mid(p,l));
+ growBuf.addStr(entity);
}
i=p+l;
}
- growBuf.addStr(s.mid(i,s.length()-i));
+ growBuf.addStr(s.substr(i));
growBuf.addChar(0);
//printf("convertCharEntitiesToUTF8(%s)->%s\n",s.data(),growBuf.get());
return growBuf.get();
@@ -4400,77 +4420,77 @@ void addMembersToMemberGroup(MemberList *ml,
* class \a name and a template argument list \a templSpec. If -1 is returned
* there are no more matches.
*/
-int extractClassNameFromType(const QCString &type,int &pos,QCString &name,QCString &templSpec,SrcLangExt lang)
+int extractClassNameFromType(const char *type,int &pos,QCString &name,QCString &templSpec,SrcLangExt lang)
{
- static const QRegExp re_norm("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9:\\x80-\\xFF]*");
- static const QRegExp re_ftn("[a-z_A-Z\\x80-\\xFF][()=_a-z_A-Z0-9:\\x80-\\xFF]*");
- QRegExp re;
+ static reg::Ex re_norm(R"(\a[\w:]*)");
+ static reg::Ex re_fortran(R"(\a[\w:()=]*)");
+ static const reg::Ex *re = &re_norm;
name.resize(0);
templSpec.resize(0);
- int i,l;
- int typeLen=type.length();
+ if (type==0) return -1;
+ int typeLen=qstrlen(type);
if (typeLen>0)
{
if (lang == SrcLangExt_Fortran)
{
- if (type.at(pos)==',') return -1;
- if (type.left(4).lower()=="type")
+ if (type[pos]==',') return -1;
+ if (QCString(type).left(4).lower()!="type")
{
- re = re_norm;
- }
- else
- {
- re = re_ftn;
+ re = &re_fortran;
}
}
- else
- {
- re = re_norm;
- }
+ std::string s = type;
+ reg::Iterator it(s,*re,(int)pos);
+ reg::Iterator end;
- if ((i=re.match(type,pos,&l))!=-1) // for each class name in the type
+ if (it!=end)
{
- int ts=i+l;
- int te=ts;
- int tl=0;
- while (type.at(ts)==' ' && ts<typeLen) ts++,tl++; // skip any whitespace
- if (type.at(ts)=='<') // assume template instance
+ const auto &match = *it;
+ int i = (int)match.position();
+ int l = (int)match.length();
+ int ts = i+l;
+ int te = ts;
+ int tl = 0;
+
+ while (ts<typeLen && type[ts]==' ') ts++,tl++; // skip any whitespace
+ if (ts<typeLen && type[ts]=='<') // assume template instance
{
// locate end of template
te=ts+1;
int brCount=1;
while (te<typeLen && brCount!=0)
{
- if (type.at(te)=='<')
+ if (type[te]=='<')
{
- if (te<typeLen-1 && type.at(te+1)=='<') te++; else brCount++;
+ if (te<typeLen-1 && type[te+1]=='<') te++; else brCount++;
}
- if (type.at(te)=='>')
+ if (type[te]=='>')
{
- if (te<typeLen-1 && type.at(te+1)=='>') te++; else brCount--;
+ if (te<typeLen-1 && type[te+1]=='>') te++; else brCount--;
}
te++;
}
}
- name = type.mid(i,l);
+ name = match.str();
if (te>ts)
{
- templSpec = type.mid(ts,te-ts),tl+=te-ts;
+ templSpec = QCString(type).mid(ts,te-ts);
+ tl+=te-ts;
pos=i+l+tl;
}
else // no template part
{
pos=i+l;
}
- //printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=TRUE\n",
- // type.data(),pos,name.data(),templSpec.data());
+ //printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=TRUE i=%d\n",
+ // type,pos,name.data(),templSpec.data(),i);
return i;
}
}
pos = typeLen;
//printf("extractClassNameFromType([in] type=%s,[out] pos=%d,[out] name=%s,[out] templ=%s)=FALSE\n",
- // type.data(),pos,name.data(),templSpec.data());
+ // type,pos,name.data(),templSpec.data());
return -1;
}
@@ -4485,13 +4505,19 @@ QCString normalizeNonTemplateArgumentsInString(
p++;
QCString result = name.left(p);
- static QRegExp re("[a-z:_A-Z\\x80-\\xFF][a-z:_A-Z0-9\\x80-\\xFF]*");
- int l,i;
+ std::string s = result.mid(p).str();
+ static const reg::Ex re(R"([\a:][\w:]*)");
+ reg::Iterator it(s,re);
+ reg::Iterator end;
+ size_t pi=0;
// for each identifier in the template part (e.g. B<T> -> T)
- while ((i=re.match(name,p,&l))!=-1)
+ for (; it!=end ; ++it)
{
- result += name.mid(p,i-p);
- QCString n = name.mid(i,l);
+ const auto &match = *it;
+ size_t i = match.position();
+ size_t l = match.length();
+ result += s.substr(pi,i-pi);
+ std::string n = match.str();
bool found=FALSE;
for (const Argument &formArg : formalArgs)
{
@@ -4505,7 +4531,7 @@ QCString normalizeNonTemplateArgumentsInString(
{
// try to resolve the type
SymbolResolver resolver;
- const ClassDef *cd = resolver.resolveClass(context,n);
+ const ClassDef *cd = resolver.resolveClass(context,n.c_str());
if (cd)
{
result+=cd->name();
@@ -4519,9 +4545,9 @@ QCString normalizeNonTemplateArgumentsInString(
{
result+=n;
}
- p=i+l;
+ pi=i+l;
}
- result+=name.right(name.length()-p);
+ result+=s.substr(pi);
//printf("normalizeNonTemplateArgumentInString(%s)=%s\n",name.data(),result.data());
return removeRedundantWhiteSpace(result);
}
@@ -4534,21 +4560,27 @@ QCString normalizeNonTemplateArgumentsInString(
* prevent recursive substitution.
*/
QCString substituteTemplateArgumentsInString(
- const QCString &name,
+ const std::string &name,
const ArgumentList &formalArgs,
const std::unique_ptr<ArgumentList> &actualArgs)
{
//printf("substituteTemplateArgumentsInString(name=%s formal=%s actualArg=%s)\n",
// name.data(),argListToString(formalArgs).data(),argListToString(actualArgs).data());
if (formalArgs.empty()) return name;
- QCString result;
- static QRegExp re("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9:\\x80-\\xFF]*");
- int p=0,l,i;
- // for each identifier in the base class name (e.g. B<T> -> B and T)
- while ((i=re.match(name,p,&l))!=-1)
+ std::string result;
+
+ static const reg::Ex re(R"(\a[\w:]*)");
+ reg::Iterator it(name,re);
+ reg::Iterator end;
+ size_t p=0;
+
+ for (; it!=end ; ++it)
{
- result += name.mid(p,i-p);
- QCString n = name.mid(i,l);
+ const auto &match = *it;
+ size_t i = match.position();
+ size_t l = match.length();
+ if (i>p) result += name.substr(p,i-p);
+ std::string n = match.str();
ArgumentList::iterator actIt;
if (actualArgs)
{
@@ -4616,7 +4648,7 @@ QCString substituteTemplateArgumentsInString(
formArg.defval!=name /* to prevent recursion */
)
{
- result += substituteTemplateArgumentsInString(formArg.defval,formalArgs,actualArgs)+" ";
+ result += substituteTemplateArgumentsInString(formArg.defval.str(),formalArgs,actualArgs)+" ";
found=TRUE;
}
}
@@ -4626,7 +4658,7 @@ QCString substituteTemplateArgumentsInString(
formArg.defval!=name /* to prevent recursion */
)
{
- result += substituteTemplateArgumentsInString(formArg.defval,formalArgs,actualArgs)+" ";
+ result += substituteTemplateArgumentsInString(formArg.defval.str(),formalArgs,actualArgs)+" ";
found=TRUE;
}
if (actualArgs && actIt!=actualArgs->end())
@@ -4640,10 +4672,10 @@ QCString substituteTemplateArgumentsInString(
}
p=i+l;
}
- result+=name.right(name.length()-p);
+ result+=name.substr(p);
//printf(" Inheritance relation %s -> %s\n",
// name.data(),result.data());
- return result.stripWhiteSpace();
+ return QCString(result).stripWhiteSpace();
}
@@ -5354,36 +5386,55 @@ QCString stripPath(const char *s)
}
/** returns \c TRUE iff string \a s contains word \a w */
-bool containsWord(const QCString &s,const QCString &word)
+bool containsWord(const char *str,const char *word)
{
- static QRegExp wordExp("[a-z_A-Z\\x80-\\xFF]+");
- int p=0,i,l;
- while ((i=wordExp.match(s,p,&l))!=-1)
+ if (str==0 || word==0) return false;
+ static const reg::Ex re(R"(\a+)");
+ std::string s = str;
+ for (reg::Iterator it(s,re) ; it!=reg::Iterator() ; ++it)
{
- if (s.mid(i,l)==word) return TRUE;
- p=i+l;
+ if (it->str()==word) return true;
}
- return FALSE;
+ return false;
}
-bool findAndRemoveWord(QCString &s,const QCString &word)
-{
- static QRegExp wordExp("[a-z_A-Z\\x80-\\xFF]+");
- int p=0,i,l;
- while ((i=wordExp.match(s,p,&l))!=-1)
- {
- if (s.mid(i,l)==word)
+/** removes occurrences of whole \a word from \a sentence,
+ * while keeps internal spaces and reducing multiple sequences of spaces.
+ * Example: sentence=` cat+ catfish cat cat concat cat`, word=`cat` returns: `+ catfish concat`
+ */
+bool findAndRemoveWord(QCString &sentence,const char *word)
+{
+ static reg::Ex re(R"(\s*(\<\a+\>)\s*)");
+ std::string s = sentence.str();
+ reg::Iterator it(s,re);
+ reg::Iterator end;
+ std::string result;
+ bool found=false;
+ size_t p=0;
+ for ( ; it!=end ; ++it)
+ {
+ const auto match = *it;
+ std::string part = match[1].str();
+ if (part!=word)
+ {
+ size_t i = match.position();
+ size_t l = match.length();
+ result+=s.substr(p,i-p);
+ result+=match.str();
+ p=i+l;
+ }
+ else
{
- if (i>0 && isspace((uchar)s.at(i-1)))
- i--,l++;
- else if (i+l<(int)s.length() && isspace((uchar)s.at(i+l)))
- l++;
- s = s.left(i)+s.mid(i+l); // remove word + spacing
- return TRUE;
+ found=true;
+ size_t i = match[1].position();
+ size_t l = match[1].length();
+ result+=s.substr(p,i-p);
+ p=i+l;
}
- p=i+l;
}
- return FALSE;
+ result+=s.substr(p);
+ sentence = QCString(result).simplifyWhiteSpace();
+ return found;
}
/** Special version of QCString::stripWhiteSpace() that only strips
@@ -5433,25 +5484,6 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine)
return s.mid(li,bi-li);
}
-#if 0
-void stringToSearchIndex(const QCString &docBaseUrl,const QCString &title,
- const QCString &str,bool priority,const QCString &anchor)
-{
- static bool searchEngine = Config_getBool(SEARCHENGINE);
- if (searchEngine)
- {
- Doxygen::searchIndex->setCurrentDoc(title,docBaseUrl,anchor);
- static QRegExp wordPattern("[a-z_A-Z\\x80-\\xFF][a-z_A-Z0-9\\x80-\\xFF]*");
- int i,p=0,l;
- while ((i=wordPattern.match(str,p,&l))!=-1)
- {
- Doxygen::searchIndex->addWord(str.mid(i,l),priority);
- p=i+l;
- }
- }
-}
-#endif
-
//--------------------------------------------------------------------------
static std::unordered_map<std::string,int> g_extLookup;
@@ -5738,18 +5770,37 @@ int nextUtf8CharPosition(const QCString &utf8Str,uint len,uint startPos)
}
else if (c=='&') // skip over character entities
{
- static QRegExp re1("&#[0-9]+;"); // numerical entity
- static QRegExp re2("&[A-Z_a-z]+;"); // named entity
- int l1,l2;
- int i1 = re1.match(utf8Str,startPos,&l1);
- int i2 = re2.match(utf8Str,startPos,&l2);
- if (i1!=-1)
+ int (*matcher)(int) = 0;
+ c = (uchar)utf8Str[startPos+bytes];
+ if (c=='#') // numerical entity?
{
- bytes=l1;
+ bytes++;
+ c = (uchar)utf8Str[startPos+bytes];
+ if (c=='x') // hexadecimal entity?
+ {
+ bytes++;
+ matcher = std::isxdigit;
+ }
+ else // decimal entity
+ {
+ matcher = std::isdigit;
+ }
+ }
+ else if (std::isalnum(c)) // named entity?
+ {
+ bytes++;
+ matcher = std::isalnum;
}
- else if (i2!=-1)
+ if (matcher)
{
- bytes=l2;
+ while ((c = (uchar)utf8Str[startPos+bytes])!=0 && matcher(c))
+ {
+ bytes++;
+ }
+ }
+ if (c!=';')
+ {
+ bytes=1; // not a valid entity, reset bytes counter
}
}
return startPos+bytes;
@@ -5760,6 +5811,7 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md,
{
QGString s;
if (doc.isEmpty()) return s.data();
+ //printf("parseCommentAsText(%s)\n",doc.data());
FTextStream t(&s);
DocNode *root = validatingParseDoc(fileName,lineNr,
(Definition*)scope,(MemberDef*)md,doc,FALSE,FALSE,
@@ -5799,7 +5851,7 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md,
//--------------------------------------------------------------------------------------
static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,
- const QCString s,bool allowRecursion=FALSE);
+ const std::string &s,bool allowRecursion=FALSE);
struct Marker
{
@@ -5911,7 +5963,7 @@ static QCString replaceAliasArguments(StringUnorderedSet &aliasesProcessed,
//printf("part before marker %d: '%s'\n",i,aliasValue.mid(p,m->pos-p).data());
if (m.number>0 && m.number<=(int)args.size()) // valid number
{
- result+=expandAliasRec(aliasesProcessed,args.at(m.number-1),TRUE);
+ result+=expandAliasRec(aliasesProcessed,args.at(m.number-1).str(),TRUE);
//printf("marker index=%d pos=%d number=%d size=%d replacement %s\n",i,m->pos,m->number,m->size,
// args.at(m->number-1)->data());
}
@@ -5923,7 +5975,7 @@ static QCString replaceAliasArguments(StringUnorderedSet &aliasesProcessed,
// expand the result again
result = substitute(result,"\\{","{");
result = substitute(result,"\\}","}");
- result = expandAliasRec(aliasesProcessed,substitute(result,"\\,",","));
+ result = expandAliasRec(aliasesProcessed,substitute(result,"\\,",",").str());
return result;
}
@@ -5950,19 +6002,24 @@ static QCString escapeCommas(const QCString &s)
return result.data();
}
-static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,const QCString s,bool allowRecursion)
+static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,const std::string &s,bool allowRecursion)
{
- QCString result;
- static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*");
- QCString value=s;
- int i,p=0,l;
- while ((i=cmdPat.match(value,p,&l))!=-1)
+ std::string result;
+ static const reg::Ex re(R"([\\@](\a\w*))");
+ reg::Iterator re_it(s,re);
+ reg::Iterator end;
+
+ int p = 0;
+ for ( ; re_it!=end ; ++re_it)
{
- result+=value.mid(p,i-p);
- QCString args = extractAliasArgs(value,i+l);
+ const auto &match = *re_it;
+ int i = (int)match.position();
+ int l = (int)match.length();
+ if (i>p) result+=s.substr(p,i-p);
+ QCString args = extractAliasArgs(s,i+l);
bool hasArgs = !args.isEmpty(); // found directly after command
int argsLen = args.length();
- QCString cmd = value.mid(i+1,l-1);
+ QCString cmd = match[1].str();
QCString cmdNoArgs = cmd;
int numArgs=0;
if (hasArgs)
@@ -5996,7 +6053,7 @@ static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,const QCStri
//printf("replace '%s'->'%s' args='%s'\n",
// aliasText->data(),val.data(),args.data());
}
- result+=expandAliasRec(aliasesProcessed,val);
+ result+=expandAliasRec(aliasesProcessed,val.str()).str();
if (!allowRecursion) aliasesProcessed.erase(cmd.str());
p=i+l;
if (hasArgs) p+=argsLen+2;
@@ -6004,11 +6061,11 @@ static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,const QCStri
else // command is not an alias
{
//printf("not an alias!\n");
- result+=value.mid(i,l);
+ result+=match.str();
p=i+l;
}
}
- result+=value.right(value.length()-p);
+ result+=s.substr(p);
//printf("expandAliases '%s'->'%s'\n",s.data(),result.data());
return result;
@@ -6069,7 +6126,7 @@ QCString resolveAliasCmd(const QCString aliasCmd)
QCString result;
StringUnorderedSet aliasesProcessed;
//printf("Expanding: '%s'\n",aliasCmd.data());
- result = expandAliasRec(aliasesProcessed,aliasCmd);
+ result = expandAliasRec(aliasesProcessed,aliasCmd.str());
//printf("Expanding result: '%s'->'%s'\n",aliasCmd.data(),result.data());
return result;
}
@@ -6269,18 +6326,23 @@ bool readInputFile(const char *fileName,BufStr &inBuf,bool filter,bool isSourceC
}
// Replace %word by word in title
-QCString filterTitle(const QCString &title)
-{
- QCString tf;
- static QRegExp re("%[A-Z_a-z]");
- int p=0,i,l;
- while ((i=re.match(title,p,&l))!=-1)
- {
- tf+=title.mid(p,i-p);
- tf+=title.mid(i+1,l-1); // skip %
+QCString filterTitle(const std::string &title)
+{
+ std::string tf;
+ static const reg::Ex re(R"(%[a-z_A-Z]+)");
+ reg::Iterator it(title,re);
+ reg::Iterator end;
+ size_t p = 0;
+ for (; it!=end ; ++it)
+ {
+ const auto &match = *it;
+ size_t i = match.position();
+ size_t l = match.length();
+ if (i>p) tf+=title.substr(p,i-p);
+ tf+=match.str().substr(1); // skip %
p=i+l;
}
- tf+=title.right(title.length()-p);
+ tf+=title.substr(p);
return tf;
}
@@ -6301,23 +6363,26 @@ bool patternMatch(const QFileInfo &fi,const StringVector &patList)
if (!patList.empty())
{
- QCString fn = fi.fileName().data();
- QCString fp = fi.filePath().data();
- QCString afp= fi.absFilePath().data();
+ std::string fn = fi.fileName().data();
+ std::string fp = fi.filePath().data();
+ std::string afp= fi.absFilePath().data();
- for (const auto &pat: patList)
+ for (auto pattern: patList)
{
- QCString pattern = pat.c_str();
- if (!pattern.isEmpty())
+ if (!pattern.empty())
{
- int i=pattern.find('=');
- if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name
-
- QRegExp re(pattern,caseSenseNames,TRUE);
+ size_t i=pattern.find('=');
+ if (i!=std::string::npos) pattern=pattern.substr(0,i); // strip of the extension specific filter name
- found = re.match(fn)!=-1 ||
- re.match(fp)!=-1 ||
- re.match(afp)!=-1;
+ if (!caseSenseNames)
+ {
+ pattern = QCString(pattern).lower().str();
+ fn = QCString(fn).lower().str();
+ fp = QCString(fn).lower().str();
+ afp = QCString(fn).lower().str();
+ }
+ reg::Ex re(pattern,reg::Ex::Mode::Wildcard);
+ found = re.isValid() && (reg::match(fn,re) || reg::match(fp,re) || reg::match(afp,re));
if (found) break;
//printf("Matching '%s' against pattern '%s' found=%d\n",
// fi->fileName().data(),pattern.data(),found);
@@ -6327,36 +6392,6 @@ bool patternMatch(const QFileInfo &fi,const StringVector &patList)
return found;
}
-#if 0 // move to HtmlGenerator::writeSummaryLink
-void writeSummaryLink(OutputList &ol,const char *label,const char *title,
- bool &first,const char *file)
-{
- if (first)
- {
- ol.writeString(" <div class=\"summary\">\n");
- first=FALSE;
- }
- else
- {
- ol.writeString(" &#124;\n");
- }
- if (file)
- {
- ol.writeString("<a href=\"");
- ol.writeString(file);
- ol.writeString(Doxygen::htmlFileExtension);
- }
- else
- {
- ol.writeString("<a href=\"#");
- ol.writeString(label);
- }
- ol.writeString("\">");
- ol.writeString(title);
- ol.writeString("</a>");
-}
-#endif
-
QCString externalLinkTarget(const bool parent)
{
static bool extLinksInWindow = Config_getBool(EXT_LINKS_IN_WINDOW);
@@ -6429,18 +6464,24 @@ void writeColoredImgData(const char *dir,ColoredImgDataItem data[])
*/
QCString replaceColorMarkers(const char *str)
{
- QCString result;
- QCString s=str;
- if (s.isEmpty()) return result;
- static QRegExp re("##[0-9A-Fa-f][0-9A-Fa-f]");
+ if (str==0) return QCString();
+ std::string result;
+ std::string s=str;
+ static const reg::Ex re(R"(##[0-9A-Fa-f][0-9A-Fa-f])");
+ reg::Iterator it(s,re);
+ reg::Iterator end;
static int hue = Config_getInt(HTML_COLORSTYLE_HUE);
static int sat = Config_getInt(HTML_COLORSTYLE_SAT);
static int gamma = Config_getInt(HTML_COLORSTYLE_GAMMA);
- int i,l,sl=s.length(),p=0;
- while ((i=re.match(s,p,&l))!=-1)
- {
- result+=s.mid(p,i-p);
- QCString lumStr = s.mid(i+2,l-2);
+ size_t sl=s.length();
+ size_t p=0;
+ for (; it!=end ; ++it)
+ {
+ const auto &match = *it;
+ size_t i = match.position();
+ size_t l = match.length();
+ if (i>p) result+=s.substr(p,i-p);
+ std::string lumStr = match.str().substr(2);
#define HEXTONUM(x) (((x)>='0' && (x)<='9') ? ((x)-'0') : \
((x)>='a' && (x)<='f') ? ((x)-'a'+10) : \
((x)>='A' && (x)<='F') ? ((x)-'A'+10) : 0)
@@ -6466,7 +6507,7 @@ QCString replaceColorMarkers(const char *str)
result+=colStr;
p=i+l;
}
- result+=s.right(sl-p);
+ if (p<sl) result+=s.substr(p);
return result;
}
@@ -6908,27 +6949,43 @@ bool classVisibleInIndex(const ClassDef *cd)
//----------------------------------------------------------------------------
+/** Strip the direction part from docs and return it as a string in canonical form
+ * The input \a docs string can start with e.g. "[in]", "[in, out]", "[inout]", "[out,in]"...
+ * @returns either "[in,out]", "[in]", or "[out]" or the empty string.
+ */
QCString extractDirection(QCString &docs)
{
- QRegExp re("\\[[ inout,]+\\]"); // [...]
- int l=0;
- if (re.match(docs,0,&l)==0 && l>2)
+ std::string s = docs.str();
+ static const reg::Ex re(R"(\[([ inout,]+)\])");
+ reg::Iterator it(s,re);
+ reg::Iterator end;
+ if (it!=end)
{
- // make dir the part inside [...] without separators
- QCString dir=substitute(substitute(docs.mid(1,l-2)," ",""),",","");
- int inIndex, outIndex;
- unsigned char ioMask=0;
- if (( inIndex=dir.find( "in"))!=-1) dir.remove (inIndex,2),ioMask|=(1<<0);
- if ((outIndex=dir.find("out"))!=-1) dir.remove(outIndex,3),ioMask|=(1<<1);
- if (dir.isEmpty() && ioMask!=0) // only in and/or out attributes found
+ const auto &match = *it;
+ size_t p = match.position();
+ size_t l = match.length();
+ if (p==0 && l>2)
{
- docs = docs.mid(l); // strip attributes
- if (ioMask==((1<<0)|(1<<1))) return "[in,out]";
- else if (ioMask==(1<<0)) return "[in]";
- else if (ioMask==(1<<1)) return "[out]";
+ // make dir the part inside [...] without separators
+ std::string dir = match[1].str();
+ // strip , and ' ' from dir
+ dir.erase(std::remove_if(dir.begin(),dir.end(),
+ [](const char c) { return c==' ' || c==','; }
+ ),dir.end());
+ size_t inIndex, outIndex;
+ unsigned char ioMask=0;
+ if (( inIndex=dir.find( "in"))!=std::string::npos) dir.erase( inIndex,2),ioMask|=(1<<0);
+ if ((outIndex=dir.find("out"))!=std::string::npos) dir.erase(outIndex,3),ioMask|=(1<<1);
+ if (dir.empty() && ioMask!=0) // only in and/or out attributes found
+ {
+ docs = s.substr(l); // strip attributes
+ if (ioMask==((1<<0)|(1<<1))) return "[in,out]";
+ else if (ioMask==(1<<0)) return "[in]";
+ else if (ioMask==(1<<1)) return "[out]";
+ }
}
}
- return QCString();
+ return "";
}
//-----------------------------------------------------------
@@ -7371,3 +7428,56 @@ QCString removeEmptyLines(const QCString &s)
//printf("removeEmptyLines(%s)=%s\n",s.data(),out.data());
return out.data();
}
+
+/// split input string \a s by string delimiter \a delimiter.
+/// returns a vector of non-empty strings that are between the delimiters
+StringVector split(const std::string &s,const std::string &delimiter)
+{
+ StringVector result;
+ size_t prev = 0, pos = 0, len = s.length();
+ do
+ {
+ pos = s.find(delimiter, prev);
+ if (pos == std::string::npos) pos = len;
+ if (pos>prev) result.push_back(s.substr(prev,pos-prev));
+ prev = pos + delimiter.length();
+ }
+ while (pos<len && prev<len);
+ return result;
+}
+
+/// split input string \a s by regular expression delimiter \a delimiter.
+/// returns a vector of non-empty strings that are between the delimiters
+StringVector split(const std::string &s,const reg::Ex &delimiter)
+{
+ StringVector result;
+ reg::Iterator iter(s, delimiter);
+ reg::Iterator end;
+ size_t p=0;
+ for ( ; iter != end; ++iter)
+ {
+ const auto &match = *iter;
+ size_t i=match.position();
+ size_t l=match.length();
+ if (i>p) result.push_back(s.substr(p,i-p));
+ p=i+l;
+ }
+ if (p<s.length()) result.push_back(s.substr(p));
+ return result;
+}
+
+/// find the index of a string in a vector of strings, returns -1 if the string could not be found
+int findIndex(const StringVector &sv,const std::string &s)
+{
+ auto it = std::find(sv.begin(),sv.end(),s);
+ return it!=sv.end() ? (int)(it-sv.begin()) : -1;
+}
+
+/// find the index of the first occurrence of pattern \a re in a string \a s
+/// returns -1 if the pattern could not be found
+int findIndex(const std::string &s,const reg::Ex &re)
+{
+ reg::Match match;
+ return reg::search(s,match,re) ? (int)match.position() : -1;
+}
+
diff --git a/src/util.h b/src/util.h
index d70ef96..f50e2a3 100644
--- a/src/util.h
+++ b/src/util.h
@@ -25,6 +25,7 @@
#include <memory>
#include <unordered_map>
#include <algorithm>
+#include <functional>
#include <ctype.h>
#include "types.h"
@@ -34,6 +35,7 @@
#include "containers.h"
#include "namespacedef.h"
#include "outputgen.h"
+#include "regex.h"
//--------------------------------------------------------------------
@@ -219,9 +221,9 @@ QCString substituteKeywords(const QCString &s,const char *title,
int getPrefixIndex(const QCString &name);
-QCString removeAnonymousScopes(const QCString &s);
+QCString removeAnonymousScopes(const char *s);
-QCString replaceAnonymousScopes(const QCString &s,const char *replacement=0);
+QCString replaceAnonymousScopes(const char *s,const char *replacement=0);
bool hasVisibleRoot(const BaseClassList &bcl);
bool classHasVisibleChildren(const ClassDef *cd);
@@ -263,7 +265,7 @@ void addMembersToMemberGroup(/* in,out */ MemberList *ml,
/* in,out */ MemberGroupList *pMemberGroups,
/* in */ const Definition *context);
-int extractClassNameFromType(const QCString &type,int &pos,
+int extractClassNameFromType(const char *type,int &pos,
QCString &name,QCString &templSpec,SrcLangExt=SrcLangExt_Unknown);
QCString normalizeNonTemplateArgumentsInString(
@@ -272,7 +274,7 @@ QCString normalizeNonTemplateArgumentsInString(
const ArgumentList &formalArgs);
QCString substituteTemplateArgumentsInString(
- const QCString &name,
+ const std::string &name,
const ArgumentList &formalArgs,
const std::unique_ptr<ArgumentList> &actualArgs);
@@ -351,9 +353,9 @@ void createSubDirs(QDir &d);
QCString stripPath(const char *s);
-bool containsWord(const QCString &s,const QCString &word);
+bool containsWord(const char *s,const char *word);
-bool findAndRemoveWord(QCString &s,const QCString &word);
+bool findAndRemoveWord(QCString &s,const char *word);
QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine);
@@ -380,13 +382,13 @@ std::string expandAlias(const std::string &aliasName,const std::string &aliasVal
void writeTypeConstraints(OutputList &ol,const Definition *d,const ArgumentList &al);
-QCString convertCharEntitiesToUTF8(const QCString &s);
+QCString convertCharEntitiesToUTF8(const char *s);
void stackTrace();
bool readInputFile(const char *fileName,BufStr &inBuf,
bool filter=TRUE,bool isSourceCode=FALSE);
-QCString filterTitle(const QCString &title);
+QCString filterTitle(const std::string &title);
bool patternMatch(const QFileInfo &fi,const StringVector &patList);
@@ -395,6 +397,8 @@ QCString externalRef(const QCString &relPath,const QCString &ref,bool href);
int nextUtf8CharPosition(const QCString &utf8Str,uint len,uint startPos);
const char *writeUtf8Char(FTextStream &t,const char *s);
+void writeMarkerList(OutputList &ol,const std::string &markerText,size_t numMarkers,
+ std::function<void(size_t)> replaceFunc);
/** Data associated with a HSV colored image. */
struct ColoredImgDataItem
@@ -455,6 +459,11 @@ bool openOutputFile(const char *outFile,QFile &f);
void writeExtraLatexPackages(FTextStream &t);
void writeLatexSpecialFormulaChars(FTextStream &t);
+StringVector split(const std::string &s,const std::string &delimiter);
+StringVector split(const std::string &s,const reg::Ex &delimiter);
+int findIndex(const StringVector &sv,const std::string &s);
+int findIndex(const std::string &s,const reg::Ex &re);
+
bool recognizeFixedForm(const char* contents, FortranFormat format);
FortranFormat convertFileNameFortranParserCode(QCString fn);
diff --git a/src/vhdlcode.l b/src/vhdlcode.l
index 59872f3..c363a23 100644
--- a/src/vhdlcode.l
+++ b/src/vhdlcode.l
@@ -37,7 +37,6 @@
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
-#include <qregexp.h>
#include <qdir.h>
#include <qcstringlist.h>
@@ -55,6 +54,7 @@
#include "classdef.h"
#include "filedef.h"
#include "tooltip.h"
+#include "regex.h"
#define YY_NO_INPUT 1
#define YY_NO_UNISTD_H 1
@@ -226,9 +226,8 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
<Map>[^()\n,--]* { /* write and link a port map lines */
QCString tt(yytext);
VhdlDocGen::deleteAllChars(tt,',');
- QRegExp r("=>");
- QCStringList ql=QCStringList::split(r,tt);
- if (ql.count()>=2)
+ auto ql = split(tt.str(),"=>");
+ if (ql.size()>=2)
{
unsigned int index=0;
QCString t1=ql[0];
@@ -325,7 +324,7 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
QCString qcs(yytext);
VhdlDocGen::deleteAllChars(qcs,'"');
VhdlDocGen::deleteAllChars(qcs,' ');
- if (VhdlDocGen::isNumber(qcs))
+ if (VhdlDocGen::isNumber(qcs.str()))
{
writeFont(yyscanner,"vhdllogic",yytext);
}
@@ -355,17 +354,17 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
}
<ParseType>{ENDEFUNC} {
- QRegExp regg("[\\s]");
QCString tt(yytext);
codifyLines(yyscanner,yytext,yyextra->currClass.data());
tt=tt.lower();
VhdlDocGen::deleteAllChars(tt,';');
tt.stripWhiteSpace();
- QCStringList ql=QCStringList::split(regg,tt);
- int index=ql.findIndex(QCString("if"))+1;
- index+=ql.findIndex(QCString("case"))+1;
- index+=ql.findIndex(QCString("loop"))+1;
- index+=ql.findIndex(QCString("generate"))+1;
+ static const reg::Ex regg(R"(\s+)"); // any number of whitespace
+ auto ql = split(tt.str(),regg);
+ int index=findIndex(ql,"if")+1;
+ index+=findIndex(ql,"case")+1;
+ index+=findIndex(ql,"loop")+1;
+ index+=findIndex(ql,"generate")+1;
if (index==0)
{
BEGIN(Bases);
@@ -412,7 +411,7 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
yyextra->vhdlKeyDict.find(yyextra->prevString.str())==yyextra->vhdlKeyDict.end())
{
val=val.stripWhiteSpace();
- if (VhdlDocGen::isNumber(val))
+ if (VhdlDocGen::isNumber(val.str()))
{
startFontClass(yyscanner,"vhdllogic");
codifyLines(yyscanner,yytext,yyextra->currClass.data());
@@ -847,7 +846,7 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
VhdlDocGen::deleteAllChars(qcs,'"');
VhdlDocGen::deleteAllChars(qcs,' ');
- if (VhdlDocGen::isNumber(qcs))
+ if (VhdlDocGen::isNumber(qcs.str()))
{
writeFont(yyscanner,"vhdllogic",yytext);
}
@@ -955,18 +954,18 @@ static bool checkVhdlString(yyscan_t yyscanner,QCString &name)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
if (name.isEmpty()) return false;
- static QRegExp regg("[\\s\"]");
int len=name.length();
if (name.at(0)=='"' && name.at(len-1)=='"' && len > 2)
{
- QCStringList qrl=QCStringList::split(regg,name);
+ std::string inside = name.str().substr(1,len-2);
+ static const reg::Ex regg(R"(\s+)"); // any number of whitespace
+ auto qrl=split(inside,regg);
if (VhdlDocGen::isNumber(qrl[0]))
{
yyextra->code->codify("\"");
startFontClass(yyscanner,"vhdllogic");
- QCString mid=name.mid(1,len-2); //" 1223 "
- yyextra->code->codify(mid.data());
+ yyextra->code->codify(inside.c_str());
endFontClass(yyscanner);
yyextra->code->codify("\"");
}
@@ -979,7 +978,7 @@ static bool checkVhdlString(yyscan_t yyscanner,QCString &name)
return true;
}
- if (VhdlDocGen::isNumber(name))
+ if (VhdlDocGen::isNumber(name.str()))
{
startFontClass(yyscanner,"vhdllogic");
yyextra->code->codify(name.data());
@@ -1161,13 +1160,16 @@ static void writeWord(yyscan_t yyscanner,const char *word,const char* curr_class
else
{
QCString qc(temp.data());
- if (VhdlDocGen::isNumber(qc)){
- startFontClass(yyscanner,"vhdllogic");
- yyextra->code->codify(temp.data());
- endFontClass(yyscanner);
- }
+ if (VhdlDocGen::isNumber(qc.str()))
+ {
+ startFontClass(yyscanner,"vhdllogic");
+ yyextra->code->codify(temp.data());
+ endFontClass(yyscanner);
+ }
else
- yyextra->code->codify(temp.data());
+ {
+ yyextra->code->codify(temp.data());
+ }
}
}
}
@@ -1329,7 +1331,13 @@ static void generateClassOrGlobalLink(yyscan_t yyscanner,CodeOutputInterface &ol
cd = getClass(className.data());
if (!cd && curr_class)
{
- if (QCString(curr_class).contains(QRegExp("::"+QCString(clName)+"$"))) cd = getClass(curr_class);
+ QCString cls = curr_class;
+ QCString suffix = "::";
+ suffix+=clName;
+ if (cls.right(suffix.length())==suffix)
+ {
+ cd = getClass(curr_class);
+ }
}
while (cd)
diff --git a/src/vhdldocgen.cpp b/src/vhdldocgen.cpp
index 299ae26..86110a8 100644
--- a/src/vhdldocgen.cpp
+++ b/src/vhdldocgen.cpp
@@ -25,6 +25,8 @@
#include <assert.h>
#include <string.h>
#include <map>
+#include <algorithm>
+
#include <qcstring.h>
#include <qfileinfo.h>
#include <qcstringlist.h>
@@ -59,7 +61,7 @@
#include "plantuml.h"
#include "vhdljjparser.h"
#include "VhdlParser.h"
-//#include "vhdlcode.h"
+#include "regex.h"
#include "plantuml.h"
//#define DEBUGFLOW
#define theTranslator_vhdlType theTranslator->trVhdlType
@@ -271,23 +273,19 @@ static void writeVhdlDotLink(FTextStream &t,
static QCString formatBriefNote(const QCString &brief,ClassDef * cd)
{
- QRegExp ep("[\n]");
QCString vForm;
QCString repl("<BR ALIGN=\"LEFT\"/>");
QCString file=cd->getDefFileName();
int k=cd->briefLine();
- QCStringList qsl=QCStringList::split(ep,brief);
- for(uint j=0;j<qsl.count();j++)
+ auto qsl=split(brief.str(),"\n");
+ for(const auto &line : qsl)
{
- QCString qcs=qsl[j];
- vForm+=parseCommentAsText(cd,NULL,qcs,file,k);
+ vForm+=parseCommentAsText(cd,NULL,line.c_str(),file,k);
k++;
- vForm+='\n';
+ vForm+=repl;
}
-
- vForm.replace(ep,repl.data());
return vForm;
}
@@ -316,7 +314,6 @@ static void writeColumn(FTextStream &t,const MemberDef *md,bool start)
{
QCString toolTip;
- static QRegExp reg("[%]");
bool bidir=(md!=0 &&( qstricmp(md->typeString(),"inout")==0));
if (md)
@@ -325,10 +322,8 @@ static void writeColumn(FTextStream &t,const MemberDef *md,bool start)
if (!toolTip.isEmpty())
{
QCString largs = md->argsString();
- if (!largs.isEmpty())
- largs=largs.replace(reg," ");
toolTip+=" [";
- toolTip+=largs;
+ toolTip+=substitute(largs,"%"," ");
toolTip+="]";
}
}
@@ -355,7 +350,7 @@ static void writeColumn(FTextStream &t,const MemberDef *md,bool start)
QCString largs = md->argsString();
if (!largs.isEmpty())
{
- largs=largs.replace(reg," ");
+ largs=substitute(largs,"%"," ");
codify(t,largs.data());
}
}
@@ -1013,8 +1008,9 @@ void VhdlDocGen::parseFuncProto(const char* text,QCString& name,QCString& ret,bo
else
{
s1=s1.stripWhiteSpace();
- int i=s1.find("(",0,FALSE);
- int s=s1.find(QRegExp("[ \\t]"));
+ int i=s1.find('(');
+ int s=s1.find(' ');
+ if (s==-1) s=s1.find('\t');
if (i==-1 || i<s)
s1=VhdlDocGen::getIndexWord(s1.data(),1);
else // s<i, s=start of name, i=end of name
@@ -1037,13 +1033,10 @@ void VhdlDocGen::parseFuncProto(const char* text,QCString& name,QCString& ret,bo
QCString VhdlDocGen::getIndexWord(const char* c,int index)
{
- QCStringList ql;
- QCString temp(c);
- QRegExp reg("[\\s:|]");
+ static const reg::Ex reg(R"([\s|])");
+ auto ql=split(c,reg);
- ql=QCStringList::split(reg,temp);
-
- if (ql.count() > (unsigned int)index)
+ if ((size_t)index < ql.size())
{
return ql[index];
}
@@ -1128,7 +1121,7 @@ QCString VhdlDocGen::getProcessNumber()
void VhdlDocGen::writeFormatString(const QCString& s,OutputList&ol,const MemberDef* mdef)
{
- QRegExp reg("[\\[\\]\\.\\/\\:\\<\\>\\:\\s\\,\\;\\'\\+\\-\\*\\|\\&\\=\\(\\)\"]");
+ static const reg::Ex reg(R"([\[\]./<>:\s,;'+*|&=()\"-])");
QCString qcs = s;
qcs+=QCString(" ");// parsing the last sign
QCString find=qcs;
@@ -1136,9 +1129,7 @@ void VhdlDocGen::writeFormatString(const QCString& s,OutputList&ol,const MemberD
char buf[2];
buf[1]='\0';
- int j;
- int len;
- j = reg.match(temp.data(),0,&len);
+ int j = findIndex(temp.str(),reg);
ol.startBold();
if (j>=0)
@@ -1148,7 +1139,7 @@ void VhdlDocGen::writeFormatString(const QCString& s,OutputList&ol,const MemberD
find=find.left(j);
buf[0]=temp[j];
const char *ss=VhdlDocGen::findKeyWord(find);
- bool k=isNumber(find); // is this a number
+ bool k=isNumber(find.str()); // is this a number
if (k)
{
ol.docify(" ");
@@ -1184,7 +1175,7 @@ void VhdlDocGen::writeFormatString(const QCString& s,OutputList&ol,const MemberD
{
temp=st;
}
- j = reg.match(temp.data(),0,&len);
+ j = findIndex(temp.str(),reg);
}//while
}//if
else
@@ -1197,16 +1188,10 @@ void VhdlDocGen::writeFormatString(const QCString& s,OutputList&ol,const MemberD
/*!
* returns TRUE if this string is a number
*/
-bool VhdlDocGen::isNumber(const QCString& s)
+bool VhdlDocGen::isNumber(const std::string& s)
{
- static QRegExp regg("[0-9][0-9eEfFbBcCdDaA_.#-+?xXzZ]*");
-
- if (s.isEmpty()) return FALSE;
- int j,len;
- j = regg.match(s.data(),0,&len);
- if ((j==0) && (len==(int)s.length())) return TRUE;
- return FALSE;
-
+ static const reg::Ex regg(R"([0-9][0-9eEfFbBcCdDaA_.#+?xXzZ-]*)");
+ return reg::match(s,regg);
}// isNumber
@@ -1666,7 +1651,7 @@ bool VhdlDocGen::writeVHDLTypeDocumentation(const MemberDef* mdef, const Definit
writeLink(mdef,ol);
ol.docify(" ");
- largs=largs.replace(QRegExp("#")," ");
+ largs=substitute(largs,"#"," ");
VhdlDocGen::formatString(largs,ol,mdef);
return hasParams;
}
@@ -2312,8 +2297,8 @@ void VhdlDocGen::parseUCF(const char* input, Entry* entity,QCString fileName,b
}
else
{
- QRegExp ee("[\\s=]");
- int in=temp.find(ee);
+ static const reg::Ex ee(R"([\s=])");
+ int in=findIndex(temp.str(),ee);
QCString ff=temp.left(in);
temp.stripPrefix(ff.data());
ff.append("#");
@@ -2332,14 +2317,14 @@ void VhdlDocGen::parseUCF(const char* input, Entry* entity,QCString fileName,b
static void initUCF(Entry* root,const char* type,QCString & qcs,int line,QCString & fileName,QCString & brief)
{
if (qcs.isEmpty())return;
- QRegExp reg("[\\s=]");
QCString n;
// bool bo=(qstricmp(type,qcs.data())==0);
VhdlDocGen::deleteAllChars(qcs,';');
qcs=qcs.stripWhiteSpace();
- int i= qcs.find(reg);
+ static const reg::Ex reg(R"([\s=])");
+ int i = findIndex(qcs.str(),reg);
if (i<0) return;
if (i==0)
{
@@ -2417,26 +2402,28 @@ static void writeUCFLink(const MemberDef* mdef,OutputList &ol)
// for cell_inst : [entity] work.proto [ (label|expr) ]
QCString VhdlDocGen::parseForConfig(QCString & entity,QCString & arch)
{
- int index;
QCString label;
if (!entity.contains(":")) return "";
- QRegExp exp("[:()\\s]");
- QCStringList ql=QCStringList::split(exp,entity);
- //int ii=ql.findIndex(ent);
- assert(ql.count()>=2);
+ static const reg::Ex exp(R"([:()\s])");
+ auto ql=split(entity.str(),exp);
+ if (ql.size()<2)
+ {
+ return "";
+ }
label = ql[0];
entity = ql[1];
+ int index;
if ((index=entity.findRev("."))>=0)
{
entity.remove(0,index+1);
}
- if (ql.count()==3)
+ if (ql.size()==3)
{
- arch= ql[2];
- ql=QCStringList::split(exp,arch);
- if (ql.count()>1) // expression
+ arch = ql[2];
+ ql=split(arch.str(),exp);
+ if (ql.size()>1) // expression
{
arch="";
}
@@ -2448,26 +2435,29 @@ QCString VhdlDocGen::parseForConfig(QCString & entity,QCString & arch)
QCString VhdlDocGen::parseForBinding(QCString & entity,QCString & arch)
{
- int index;
- QRegExp exp("[()\\s]");
+ static const reg::Ex exp(R"([()\s])");
- QCString label="";
- QCStringList ql=QCStringList::split(exp,entity);
+ auto ql = split(entity.str(),exp);
- if (ql.contains("open"))
+ if (findIndex(ql,"open")!=-1)
{
return "open";
}
- label=ql[0];
+ if (ql.size()<2)
+ {
+ return "";
+ }
+ std::string label=ql[0];
entity = ql[1];
+ int index;
if ((index=entity.findRev("."))>=0)
{
entity.remove(0,index+1);
}
- if (ql.count()==3)
+ if (ql.size()==3)
{
arch=ql[2];
}
@@ -2607,14 +2597,6 @@ ferr:
md->setDocumentation(cur->doc.data(),cur->docFile.data(),cur->docLine);
FileDef *fd=ar->getFileDef();
md->setBodyDef(fd);
- //QCString info="Info: Elaborating entity "+n1;
- //fd=ar->getFileDef();
- //info+=" for hierarchy ";
- //QRegExp epr("[|]");
- //QCString label=cur->type+":"+cur->write+":"+cur->name;
- //label.replace(epr,":");
- //info+=label;
- //fprintf(stderr,"\n[%s:%d:%s]\n",fd->fileName().data(),cur->startLine,info.data());
ar->insertMember(md.get());
MemberName *mn = Doxygen::functionNameLinkedMap->add(uu);
mn->push_back(std::move(md));
@@ -2721,15 +2703,15 @@ void VhdlDocGen::addBaseClass(ClassDef* cd,ClassDef *ent)
bcd.usedName.append("(2)");
return;
}
- static QRegExp reg("[0-9]+");
+ static const reg::Ex reg(R"(\d+)");
QCString s=n.left(i);
QCString r=n.right(n.length()-i);
- QCString t=r;
+ std::string t=r.str();
VhdlDocGen::deleteAllChars(r,')');
VhdlDocGen::deleteAllChars(r,'(');
r.setNum(r.toInt()+1);
- t.replace(reg,r.data());
- s.append(t.data());
+ reg::replace(t, reg, r.str());
+ s.append(t.c_str());
bcd.usedName=s;
bcd.templSpecifiers=t;
}
@@ -2913,13 +2895,12 @@ void alignText(QCString & q)
q.append(" ...");
- QRegExp reg("[\\s|]");
QCString str(q.data());
QCString temp;
while (str.length()>80)
{
- int j=str.findRev(reg,80);
+ int j=std::max(str.findRev(' ',80),str.findRev('|',80));
if (j<=0)
{
temp+=str;
@@ -2942,8 +2923,8 @@ void alignText(QCString & q)
void FlowChart::printNode(const FlowChart& flo)
{
QCString ui="-";
- QCString q,t;
- QRegExp ep("[\t\n\r]");
+ std::string q;
+ std::string t;
ui.fill('-',255);
@@ -2951,7 +2932,7 @@ void FlowChart::printNode(const FlowChart& flo)
{
if (flo.stamp>0)
{
- q=ui.left(2*flo.stamp);
+ q=ui.left(2*flo.stamp).str();
}
else
{
@@ -2964,20 +2945,21 @@ void FlowChart::printNode(const FlowChart& flo)
{
if (flo.type & COMMENT_NO)
{
- t=flo.label;
+ t=flo.label.str();
}
else
{
- t=flo.text;
+ t=flo.text.str();
}
- t=t.replace(ep,"");
- if (t.isEmpty())
+ static const reg::Ex ep(R"(\s)");
+ t = reg::replace(t,ep,std::string());
+ if (t.empty())
{
t=" ";
}
if (flo.stamp>0)
{
- q=ui.left(2*flo.stamp);
+ q=ui.left(2*flo.stamp).str();
}
else
{
@@ -2985,15 +2967,15 @@ void FlowChart::printNode(const FlowChart& flo)
}
if (flo.type & EMPTNODE)
{
- printf("\n NO: %s%s[%d,%d]",q.data(),FlowChart::getNodeType(flo.type),flo.stamp,flo.id);
+ printf("\n NO: %s%s[%d,%d]",q.c_str(),FlowChart::getNodeType(flo.type),flo.stamp,flo.id);
}
else if (flo.type & COMMENT_NO)
{
- printf("\n NO: %s%s[%d,%d]",t.data(),FlowChart::getNodeType(flo.type),flo.stamp,flo.id);
+ printf("\n NO: %s%s[%d,%d]",t.c_str(),FlowChart::getNodeType(flo.type),flo.stamp,flo.id);
}
else
{
- printf("\n NO: %s[%d,%d]",t.data(),flo.stamp,flo.id);
+ printf("\n NO: %s[%d,%d]",t.c_str(),flo.stamp,flo.id);
}
}
}
@@ -3247,9 +3229,6 @@ FlowChart::FlowChart(int typ,const char * t,const char* ex,const char* lab)
void FlowChart::addFlowChart(int type,const char* text,const char* exp, const char *label)
{
- static QRegExp reg("[;]");
- static QRegExp reg1("[\"]");
-
if (!VhdlDocGen::getFlowMember()) return;
QCString typeString(text);
@@ -3258,12 +3237,12 @@ void FlowChart::addFlowChart(int type,const char* text,const char* exp, const ch
if (text)
{
- typeString=typeString.replace(reg,"\n");
+ typeString=substitute(typeString,";","\n");
}
if (exp)
{
- expression=expression.replace(reg1,"\\\"");
+ expression=substitute(expression,"\"","\\\"");
}
if (type & (START_NO | VARIABLE_NO))
@@ -3366,23 +3345,7 @@ void FlowChart::printUmlTree()
QCString FlowChart::convertNameToFileName()
{
- static QRegExp exp ("[^][a-z_A-Z0-9]");
- QCString temp,qcs;
- const MemberDef* md=VhdlDocGen::getFlowMember();
-
- // temp.sprintf("%p",md);
- qcs=md->name();
-
- #if 0
- if (qcs.find(exp,0)>=0)
- {
- qcs.prepend("Z");
- qcs=qcs.replace(exp,"_");
- }
- #endif
-
- //QCString tt= qcs;VhdlDocGen::getRecordNumber();
- return qcs;
+ return VhdlDocGen::getFlowMember()->name();
}
const char* FlowChart::getNodeType(int c)
diff --git a/src/vhdldocgen.h b/src/vhdldocgen.h
index 46c23a8..3a55b45 100644
--- a/src/vhdldocgen.h
+++ b/src/vhdldocgen.h
@@ -207,7 +207,7 @@ class VhdlDocGen
static QCString getRecordNumber();
static QCString getClassName(const ClassDef*);
- static bool isNumber(const QCString& s);
+ static bool isNumber(const std::string& s);
static QCString getProtectionName(int prot);
static void parseUCF(const char* input,Entry* entity,QCString f,bool vendor);
diff --git a/src/vhdljjparser.cpp b/src/vhdljjparser.cpp
index b666f4c..9eaf167 100644
--- a/src/vhdljjparser.cpp
+++ b/src/vhdljjparser.cpp
@@ -10,6 +10,8 @@
*
*/
+#include <string>
+
#include <qcstring.h>
#include <qfileinfo.h>
#include "containers.h"
@@ -31,6 +33,7 @@
#include "markdown.h"
#include "VhdlParserTokenManager.h"
#include "VhdlParserErrorHandler.hpp"
+#include "regex.h"
using namespace vhdl::parser;
@@ -269,12 +272,33 @@ void VHDLOutlineParser::handleFlowComment(const char* doc)
int VHDLOutlineParser::checkInlineCode(QCString &doc)
{
- QRegExp cs("[\\\\@]code");
- QRegExp cend("[\\s ]*[\\\\@]endcode");
- QRegExp cbrief("[\\\\@]brief");
- int index = doc.find(cs);
+ static const reg::Ex csRe(R"([\\@]code)");
+ static const reg::Ex cendRe(R"(\s*[\\@]endcode)");
+ static const reg::Ex cbriefRe(R"([\\@]brief)");
+
+ // helper to simulate behavior of QString.find(const QRegExp &re,int pos)
+ auto findRe = [](const QCString &str,const reg::Ex &re,int pos=0) -> int
+ {
+ if ((int)str.length()<pos) return -1;
+ reg::Match match;
+ const std::string s = str.str();
+ if (reg::search(s,match,re,pos)) // match found
+ {
+ return (int)match.position();
+ }
+ else // not found
+ {
+ return -1;
+ }
+ };
+ auto replaceRe = [](const QCString &str,const reg::Ex &re,const QCString &replacement) -> QCString
+ {
+ return reg::replace(str.str(), re, replacement.str());
+ };
+
+ int index = findRe(doc,csRe);
- if (doc.contains(cend) > 0)
+ if (findRe(doc,cendRe)!=-1)
return 1;
if (index < 0)
@@ -282,9 +306,9 @@ int VHDLOutlineParser::checkInlineCode(QCString &doc)
VhdlParser::SharedState *s = &p->shared;
p->strComment += doc;
- p->code = p->inputString.find(cs, p->code + 1);
+ p->code = findRe(p->inputString,csRe, p->code + 1);
int com = p->inputString.find(p->strComment.data());
- int ref = p->inputString.find(cend, p->code + 1);
+ int ref = findRe(p->inputString,cendRe, p->code + 1);
int len = p->strComment.size();
int ll = com + len;
@@ -296,24 +320,24 @@ int VHDLOutlineParser::checkInlineCode(QCString &doc)
VhdlDocGen::prepareComment(p->strComment);
QCStringList ql = QCStringList::split('\n', p->strComment);
- QCString co;
- QCString na;
- for (QCString qcs : ql)
- {
- qcs = qcs.simplifyWhiteSpace();
- if (qcs.contains(cs))
- {
- int i = qcs.find('{');
- int j = qcs.find('}');
- if (i > 0 && j > 0 && j > i)
- {
- na = qcs.mid(i + 1, (j - i - 1));
- }
- continue;
- }
- qcs = qcs.replace(cbrief, "");
- co += qcs;
- co += '\n';
+ QCString co;
+ QCString na;
+ for (QCString qcs : ql)
+ {
+ qcs = qcs.simplifyWhiteSpace();
+ if (findRe(qcs,csRe)!=-1)
+ {
+ int i = qcs.find('{');
+ int j = qcs.find('}');
+ if (i > 0 && j > 0 && j > i)
+ {
+ na = qcs.mid(i + 1, (j - i - 1));
+ }
+ continue;
+ }
+ qcs = replaceRe(qcs,cbriefRe, "");
+ co += qcs;
+ co += '\n';
}
VhdlDocGen::prepareComment(co);
diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp
index db62e1b..cf032d6 100644
--- a/src/xmlgen.cpp
+++ b/src/xmlgen.cpp
@@ -796,7 +796,7 @@ static void generateXMLForMember(const MemberDef *md,FTextStream &ti,FTextStream
)
{
writeMemberTemplateLists(md,t);
- QCString typeStr = md->typeString(); //replaceAnonymousScopes(md->typeString());
+ QCString typeStr = md->typeString();
stripQualifiers(typeStr);
t << " <type>";
linkifyText(TextGeneratorXMLImpl(t),def,md->getBodyDef(),md,typeStr);
@@ -1728,7 +1728,7 @@ static void generateXMLForPage(PageDef *pd,FTextStream &ti,bool isExample)
QCString title;
if (mainPageHasTitle())
{
- title = filterTitle(convertCharEntitiesToUTF8(Doxygen::mainPage->title()));
+ title = filterTitle(convertCharEntitiesToUTF8(Doxygen::mainPage->title()).str());
}
else
{
@@ -1742,7 +1742,7 @@ static void generateXMLForPage(PageDef *pd,FTextStream &ti,bool isExample)
const SectionInfo *si = SectionManager::instance().find(pd->name());
if (si)
{
- t << " <title>" << convertToXML(convertCharEntitiesToUTF8(filterTitle(si->title())))
+ t << " <title>" << convertToXML(filterTitle(convertCharEntitiesToUTF8(si->title()).str()))
<< "</title>" << endl;
}
}