summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml31
-rw-r--r--CMakeLists.txt5
-rw-r--r--README.md39
-rwxr-xr-xaddon/doxypysql/search.py124
-rwxr-xr-xaddon/doxywizard/doxywizard.cpp2
-rw-r--r--addon/doxywizard/expert.cpp5
-rw-r--r--addon/doxywizard/input.h1
-rw-r--r--addon/doxywizard/inputstring.h1
-rw-r--r--addon/doxywizard/inputstrlist.cpp8
-rw-r--r--addon/doxywizard/inputstrlist.h1
-rw-r--r--appveyor.yml52
-rw-r--r--cmake/FindSQLite3.cmake10
-rw-r--r--doc/CMakeLists.txt1
-rw-r--r--doc/Doxyfile2
-rw-r--r--doc/arch.doc16
-rw-r--r--doc/autolink.doc2
-rw-r--r--doc/changelog.doc6
-rw-r--r--doc/commands.doc177
-rw-r--r--doc/custcmd.doc5
-rw-r--r--doc/docblocks.doc19
-rw-r--r--doc/doxygen.18
-rw-r--r--doc/doxygen_manual.tex1
-rw-r--r--doc/doxyindexer.12
-rw-r--r--doc/doxysearch.14
-rw-r--r--doc/emojisup.doc166
-rw-r--r--doc/faq.doc2
-rw-r--r--doc/features.doc4
-rw-r--r--doc/htmlcmds.doc4
-rw-r--r--doc/index.doc6
-rw-r--r--doc/install.doc21
-rw-r--r--doc/maintainers.txt4
-rw-r--r--doc/markdown.doc27
-rw-r--r--doc/output.doc2
-rw-r--r--doc/searching.doc4
-rw-r--r--doc/starting.doc2
-rw-r--r--doc/trouble.doc2
-rw-r--r--doc/xmlcmds.doc2
-rw-r--r--examples/dbusxml.cfg14
-rw-r--r--examples/dbusxml.xml78
-rw-r--r--examples/jdstyle.cfg2
-rw-r--r--qtools/CMakeLists.txt1
-rw-r--r--qtools/qcstringlist.cpp192
-rw-r--r--qtools/qcstringlist.h47
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/clangparser.cpp1
-rw-r--r--src/classdef.cpp21
-rw-r--r--src/cmdmapper.cpp3
-rw-r--r--src/cmdmapper.h5
-rw-r--r--src/code.l15
-rw-r--r--src/commentscan.h4
-rw-r--r--src/commentscan.l395
-rw-r--r--src/config.h7
-rw-r--r--src/config.xml58
-rw-r--r--src/configimpl.h20
-rw-r--r--src/configimpl.l125
-rw-r--r--src/context.cpp52
-rw-r--r--src/defargs.l17
-rw-r--r--src/defgen.cpp2
-rw-r--r--src/definition.cpp361
-rw-r--r--src/docbookgen.cpp2697
-rw-r--r--src/docbookgen.h345
-rw-r--r--src/docbookvisitor.cpp553
-rw-r--r--src/docbookvisitor.h5
-rw-r--r--src/docparser.cpp461
-rw-r--r--src/docparser.h32
-rw-r--r--src/doctokenizer.h5
-rw-r--r--src/doctokenizer.l79
-rw-r--r--src/docvisitor.h2
-rw-r--r--src/dot.cpp59
-rw-r--r--src/doxygen.cpp182
-rw-r--r--src/doxygen.h1
-rw-r--r--src/emoji.cpp3187
-rw-r--r--src/emoji.h50
-rw-r--r--src/entry.cpp6
-rw-r--r--src/entry.h17
-rw-r--r--src/filedef.cpp11
-rw-r--r--src/fortrancode.l35
-rw-r--r--src/fortranscanner.l50
-rw-r--r--src/ftvhelp.cpp3
-rw-r--r--src/htmldocvisitor.cpp128
-rw-r--r--src/htmldocvisitor.h1
-rw-r--r--src/htmlentity.cpp3
-rw-r--r--src/htmlgen.cpp26
-rw-r--r--src/htmlgen.h7
-rw-r--r--src/index.cpp38
-rw-r--r--src/latexdocvisitor.cpp82
-rw-r--r--src/latexdocvisitor.h1
-rw-r--r--src/latexgen.cpp74
-rw-r--r--src/latexgen.h4
-rw-r--r--src/layout.cpp2
-rw-r--r--src/layout.h3
-rw-r--r--src/mandocvisitor.cpp24
-rw-r--r--src/mandocvisitor.h1
-rw-r--r--src/mangen.cpp27
-rw-r--r--src/mangen.h9
-rw-r--r--src/markdown.cpp64
-rw-r--r--src/marshal.cpp10
-rw-r--r--src/memberdef.cpp70
-rw-r--r--src/memberdef.h6
-rw-r--r--src/namespacedef.cpp1
-rw-r--r--src/outputgen.h10
-rw-r--r--src/outputlist.h9
-rw-r--r--src/pagedef.cpp15
-rw-r--r--src/pagedef.h3
-rw-r--r--src/perlmodgen.cpp15
-rw-r--r--src/plantuml.cpp2
-rw-r--r--src/printdocvisitor.h24
-rw-r--r--src/pycode.l4
-rw-r--r--src/pyscanner.l180
-rw-r--r--src/qhp.cpp12
-rw-r--r--src/reflist.cpp24
-rwxr-xr-xsrc/res2cc_cmd.py3
-rw-r--r--src/rtfdocvisitor.cpp61
-rw-r--r--src/rtfdocvisitor.h11
-rw-r--r--src/rtfgen.cpp24
-rw-r--r--src/rtfgen.h4
-rw-r--r--src/scanner.l30
-rw-r--r--src/sqlite3gen.cpp2160
-rw-r--r--src/tagreader.cpp126
-rw-r--r--src/tclscanner.l120
-rw-r--r--src/template.cpp4
-rw-r--r--src/textdocvisitor.cpp13
-rw-r--r--src/textdocvisitor.h1
-rw-r--r--src/types.h10
-rw-r--r--src/util.cpp106
-rw-r--r--src/util.h7
-rw-r--r--src/vhdlcode.l100
-rw-r--r--src/vhdldocgen.cpp76
-rw-r--r--src/vhdljjparser.cpp14
-rw-r--r--src/vhdljjparser.h3
-rw-r--r--src/xmldocvisitor.cpp29
-rw-r--r--src/xmldocvisitor.h1
-rw-r--r--src/xmlgen.cpp243
-rw-r--r--src/xmlgen.h42
-rw-r--r--templates/html/doxygen.css24
-rw-r--r--templates/html/navtree.css2
-rw-r--r--templates/latex/doxygen.sty2
-rw-r--r--templates/xml/compound.xsd2
-rw-r--r--testing/005_attention.dox2
-rw-r--r--testing/009/bug.xml9
-rw-r--r--testing/009/deprecated.xml8
-rw-r--r--testing/009/reminders.xml8
-rw-r--r--testing/009/test.xml8
-rw-r--r--testing/009/todo.xml8
-rw-r--r--testing/012/citelist.xml2
-rw-r--r--testing/031/indexpage.xml1
-rw-r--r--testing/031_image.dox1
-rw-r--r--testing/043_page.dox2
-rw-r--r--testing/051/indexpage.xml2
-rw-r--r--testing/051_escape.dox2
-rw-r--r--testing/README.txt14
-rw-r--r--testing/runtests.py126
-rw-r--r--vhdlparser/VhdlParser.cc6
-rw-r--r--vhdlparser/vhdlparser.jj6
154 files changed, 10342 insertions, 3929 deletions
diff --git a/.travis.yml b/.travis.yml
index 28b8401..829e54e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,6 @@
language: cpp
os:
- - linux-ppc64le
+ - linux-ppc64le
- linux
dist: xenial
compiler:
@@ -13,6 +13,7 @@ addons:
update: true
packages:
- texlive
+ - texlive-generic-recommended
- texlive-extra-utils
- texlive-latex-extra
- texlive-font-utils
@@ -21,6 +22,34 @@ addons:
- cmake
- cmake-data
+jobs:
+ include:
+ - os: osx
+ compiler: clang
+
+before_script:
+ - if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
+ sudo mkdir -p /usr/local/man;
+ sudo chown -R "${USER}:admin" /usr/local/man;
+ pip install --quiet conan;
+ export HOMEBREW_NO_AUTO_UPDATE=1;
+ brew install ghostscript;
+
+ travis_wait brew cask install mactex-no-gui;
+ curl -O -L http://mirrors.ctan.org/support/epstopdf.zip;
+ unzip epstopdf.zip;
+ mkdir -p /Users/travis/Library/TeX/texbin/;
+ mv epstopdf/epstopdf.pl /Users/travis/Library/TeX/texbin/epstopdf;
+ chmod a+x /Users/travis/Library/TeX/texbin/epstopdf;
+ rm -rf epstopdf*;
+ export PATH=/Users/travis/Library/TeX/texbin:/Library/TeX/texbin:$PATH;
+
+ conan remote add bincrafters https://api.bintray.com/conan/bincrafters/public-conan;
+ printf "[requires] \nlibxml2/2.9.8@bincrafters/stable \nQt/5.11.1@bincrafters/stable" >> conanfile.txt;
+ conan install . -g virtualrunenv;
+ source activate_run.sh;
+ fi;
+
script:
- mkdir build
- cd build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1e0fb55..45c2f2c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,7 +86,10 @@ find_package(BISON REQUIRED)
find_package(Threads)
if (sqlite3)
- find_package(SQLite3 REQUIRED)
+ find_package(SQLite3 REQUIRED)
+ if (SQLITE3_VERSION VERSION_LESS 3.9.0)
+ message(SEND_ERROR "Doxygen requires at least sqlite3 version 3.9.0 (installed: ${SQLITE3_VERSION})")
+ endif()
endif()
find_package(Iconv REQUIRED)
diff --git a/README.md b/README.md
index 7035c6e..3e1c608 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,25 @@
Doxygen
===============
-Doxygen is the de facto standard tool for generating documentation from
-annotated C++ sources, but it also supports other popular programming
-languages such as C, Objective-C, C#, PHP, Java, Python, IDL
-(Corba, Microsoft, and UNO/OpenOffice flavors), Fortran, VHDL, Tcl,
+Doxygen is the de facto standard tool for generating documentation from
+annotated C++ sources, but it also supports other popular programming
+languages such as C, Objective-C, C#, PHP, Java, Python, IDL
+(Corba, Microsoft, and UNO/OpenOffice flavors), Fortran, VHDL, Tcl,
and to some extent D.
Doxygen can help you in three ways:
-1. It can generate an on-line documentation browser (in HTML) and/or an
- off-line reference manual (in LaTeX) from a set of documented source files.
- There is also support for generating output in RTF (MS-Word), PostScript,
- hyperlinked PDF, compressed HTML, DocBook and Unix man pages.
- The documentation is extracted directly from the sources, which makes
+1. It can generate an on-line documentation browser (in HTML) and/or an
+ off-line reference manual (in LaTeX) from a set of documented source files.
+ There is also support for generating output in RTF (MS-Word), PostScript,
+ hyperlinked PDF, compressed HTML, DocBook and Unix man pages.
+ The documentation is extracted directly from the sources, which makes
it much easier to keep the documentation consistent with the source code.
-2. You can configure doxygen to extract the code structure from undocumented
- source files. This is very useful to quickly find your way in large
- source distributions. Doxygen can also visualize the relations between
- the various elements by means of include dependency graphs, inheritance
+2. You can configure doxygen to extract the code structure from undocumented
+ source files. This is very useful to quickly find your way in large
+ source distributions. Doxygen can also visualize the relations between
+ the various elements by means of include dependency graphs, inheritance
diagrams, and collaboration diagrams, which are all generated automatically.
-3. You can also use doxygen for creating normal documentation (as I did for
+3. You can also use doxygen for creating normal documentation (as I did for
the doxygen user manual and doxygen web-site).
Download
@@ -29,15 +29,14 @@ The latest binaries and source of Doxygen can be downloaded from:
Developers
---------
-* Build Status: <a href="https://travis-ci.org/doxygen/doxygen"><img src="https://secure.travis-ci.org/doxygen/doxygen.png?branch=master"/></a>
+* Linux & macOS Build Status: <a href="https://travis-ci.org/doxygen/doxygen"><img src="https://secure.travis-ci.org/doxygen/doxygen.png?branch=master"/></a>
+* Windows Build Status: <a href="https://ci.appveyor.com/project/doxygen/doxygen"><img src="https://ci.appveyor.com/api/projects/status/github/doxygen/doxygen"/></a>
* Coverity Scan Build Status: <a href="https://scan.coverity.com/projects/2860"> <img alt="Coverity Scan Build Status" src="https://scan.coverity.com/projects/2860/badge.svg"/> </a>
* Doxygen's Doxygen Documentation: <a href="https://codedocs.xyz/doxygen/doxygen/"><img src="https://codedocs.xyz/doxygen/doxygen.svg"/></a>
-* Install
- * Quick install see (./INSTALL)
- * else http://www.doxygen.org/manual/install.html
+* Install: Please read the installation section of the manual (http://www.doxygen.org/manual/install.html)
* Project stats: https://www.openhub.net/p/doxygen
@@ -59,10 +58,10 @@ There are three mailing lists:
Source Code
----------------------------------
-In May 2013, Doxygen moved from
+In May 2013, Doxygen moved from
subversion to git hosted at GitHub
* https://github.com/doxygen/doxygen
Enjoy,
-Dimitri van Heesch (dimitri at stack.nl)
+Dimitri van Heesch (doxygen at gmail.com)
diff --git a/addon/doxypysql/search.py b/addon/doxypysql/search.py
index c185138..5f820de 100755
--- a/addon/doxypysql/search.py
+++ b/addon/doxypysql/search.py
@@ -17,19 +17,19 @@ import json
import re
class MemberType:
- Define="0"
- Function="1"
- Variable="2"
- Typedef="3"
- Enumeration="4"
- EnumValue="5"
- Signal="6"
- Slot="7"
- Friend="8"
- DCOP="9"
- Property="10"
- Event="11"
- File="12"
+ Define="macro definition"
+ Function="function"
+ Variable="variable"
+ Typedef="typedef"
+ Enumeration="enumeration"
+ EnumValue="enumvalue"
+ Signal="signal"
+ Slot="slot"
+ Friend="friend"
+ DCOP="dcop"
+ Property="property"
+ Event="event"
+ File="file"
class RequestType:
References="9901"
@@ -69,27 +69,27 @@ class Finder:
def match(self,row):
if self.row_type is int:
- return " id=?"
+ return " rowid=?"
else:
if g_use_regexp == True:
return " REGEXP (?,%s)" %row
else:
return " %s=?" %row
- def fileName(self,id_file):
- if self.cn.execute("SELECT COUNT(*) FROM files WHERE rowid=?",[id_file]).fetchone()[0] > 1:
- print >>sys.stderr,"WARNING: non-uniq fileid [%s]. Considering only the first match." % id_file
+ def fileName(self,file_id):
+ if self.cn.execute("SELECT COUNT(*) FROM path WHERE rowid=?",[file_id]).fetchone()[0] > 1:
+ sys.stderr.write("WARNING: non-uniq fileid [%s]. Considering only the first match." % file_id)
- for r in self.cn.execute("SELECT * FROM files WHERE rowid=?",[id_file]).fetchall():
+ for r in self.cn.execute("SELECT * FROM path WHERE rowid=?",[file_id]).fetchall():
return r['name']
return ""
def fileId(self,name):
- if self.cn.execute("SELECT COUNT(*) FROM files WHERE"+self.match("name"),[name]).fetchone()[0] > 1:
- print >>sys.stderr,"WARNING: non-uniq file name [%s]. Considering only the first match." % name
+ if self.cn.execute("SELECT COUNT(*) FROM path WHERE"+self.match("name"),[name]).fetchone()[0] > 1:
+ sys.stderr.write("WARNING: non-uniq file name [%s]. Considering only the first match." % name)
- for r in self.cn.execute("SELECT rowid FROM files WHERE"+self.match("name"),[name]).fetchall():
+ for r in self.cn.execute("SELECT rowid FROM path WHERE"+self.match("name"),[name]).fetchall():
return r[0]
return -1
@@ -97,23 +97,24 @@ class Finder:
def references(self):
o=[]
cur = self.cn.cursor()
- cur.execute("SELECT refid FROM memberdef WHERE"+self.match("name"),[self.name])
- refids = cur.fetchall()
+ cur.execute("SELECT rowid FROM memberdef WHERE"+self.match("name"),[self.name])
+ rowids = cur.fetchall()
- if len(refids) == 0:
+ if len(rowids) == 0:
return o
- refid = refids[0]['refid']
+ rowid = rowids[0]['rowid']
cur = self.cn.cursor()
- #TODO:SELECT rowid from refids where refid=refid
- for info in cur.execute("SELECT * FROM xrefs WHERE refid_dst LIKE '%"+refid+"%'"):
+ #TODO:SELECT rowid from refid where refid=refid
+ for info in cur.execute("SELECT * FROM xrefs WHERE dst_rowid=?", [rowid]):
item={}
cur = self.cn.cursor()
- for i2 in cur.execute("SELECT * FROM memberdef WHERE refid=?",[info['src']]):
+ for i2 in cur.execute("SELECT * FROM memberdef WHERE rowid=?",[info['src_rowid']]):
item['name']=i2['name']
- item['src']=info['src']
- item['file']=self.fileName(info['id_file'])
- item['line']=info['line']
+ item['src']=info['src_rowid']
+ # Below no longer directly supported on this entry; can be found from either memberdef
+ #item['file']=self.fileName(info['file_id'])
+ #item['line']=info['line']
o.append(item)
return o
@@ -126,7 +127,7 @@ class Finder:
item['name'] = r['name']
item['definition'] = r['definition']
item['argsstring'] = r['argsstring']
- item['file'] = self.fileName(r['id_file'])
+ item['file'] = self.fileName(r['file_id'])
item['line'] = r['line']
item['detaileddescription'] = r['detaileddescription']
o.append(item)
@@ -134,7 +135,7 @@ class Finder:
###############################################################################
def file(self):
o=[]
- for r in self.cn.execute("SELECT rowid,* FROM files WHERE"+self.match("name"),[self.name]).fetchall():
+ for r in self.cn.execute("SELECT rowid,name FROM local_file WHERE"+self.match("name"),[self.name]).fetchall():
item={}
item['name'] = r['name']
item['id'] = r['rowid']
@@ -151,7 +152,7 @@ class Finder:
if r['argsstring']:
item['argsstring'] = r['argsstring']
item['definition'] = r['initializer']
- item['file'] = self.fileName(r['id_file'])
+ item['file'] = self.fileName(r['file_id'])
item['line'] = r['line']
o.append(item)
return o
@@ -163,7 +164,7 @@ class Finder:
item={}
item['name'] = r['name']
item['definition'] = r['definition']
- item['file'] = self.fileName(r['id_file'])
+ item['file'] = self.fileName(r['file_id'])
item['line'] = r['line']
o.append(item)
return o
@@ -175,16 +176,16 @@ class Finder:
item={}
item['name'] = r['name']
item['definition'] = r['definition']
- item['file'] = self.fileName(r['id_file'])
+ item['file'] = self.fileName(r['file_id'])
item['line'] = r['line']
o.append(item)
return o
###############################################################################
def params(self):
o=[]
- c=self.cn.execute('SELECT id FROM memberdef WHERE'+self.match("name"),[self.name])
+ c=self.cn.execute('SELECT rowid FROM memberdef WHERE'+self.match("name"),[self.name])
for r in c.fetchall():
- #a=("SELECT * FROM params where id=(SELECT id_param FROM memberdef_params where id_memberdef=?",[id_memberdef])
+ #a=("SELECT * FROM param where id=(SELECT param_id FROM memberdef_param where memberdef_id=?",[memberdef_id])
item={}
item['id'] = r['id']
o.append(item)
@@ -202,20 +203,20 @@ class Finder:
def includers(self):
o=[]
fid = self.fileId(self.name)
- c=self.cn.execute('SELECT * FROM includes WHERE id_dst=?',[fid])
+ c=self.cn.execute('SELECT * FROM includes WHERE dst_id=?',[fid])
for r in c.fetchall():
item={}
- item['name'] = self.fileName(r['id_src'])
+ item['name'] = self.fileName(r['src_id'])
o.append(item)
return o
###############################################################################
def includees(self):
o=[]
fid = self.fileId(self.name)
- c=self.cn.execute('SELECT * FROM includes WHERE id_src=?',[fid])
+ c=self.cn.execute('SELECT * FROM includes WHERE src_id=?',[fid])
for r in c.fetchall():
item={}
- item['name'] = self.fileName(r['id_dst'])
+ item['name'] = self.fileName(r['dst_id'])
o.append(item)
return o
###############################################################################
@@ -227,7 +228,7 @@ class Finder:
item['name'] = r['name']
item['definition'] = r['definition']
item['argsstring'] = r['argsstring']
- item['file'] = self.fileName(r['id_file'])
+ item['file'] = self.fileName(r['file_id'])
item['line'] = r['line']
#item['documentation'] = r['documentation']
o.append(item)
@@ -235,19 +236,19 @@ class Finder:
###############################################################################
def baseClasses(self):
o=[]
- c=self.cn.execute('SELECT base FROM basecompoundref WHERE'+self.match("derived"),[self.name])
+ c=self.cn.execute('SELECT compounddef.name FROM compounddef JOIN compoundref ON compounddef.rowid=compoundref.base_rowid WHERE compoundref.derived_rowid IN (SELECT rowid FROM compounddef WHERE'+self.match("name")+')',[self.name])
for r in c.fetchall():
item={}
- item['name'] = r['base']
+ item['name'] = r['name']
o.append(item)
return o
###############################################################################
def subClasses(self):
o=[]
- c=self.cn.execute('SELECT derived FROM basecompoundref WHERE'+self.match("base"),[self.name])
+ c=self.cn.execute('SELECT compounddef.name FROM compounddef JOIN compoundref ON compounddef.rowid=compoundref.derived_rowid WHERE compoundref.base_rowid IN (SELECT rowid FROM compounddef WHERE'+self.match("name")+')',[self.name])
for r in c.fetchall():
item={}
- item['name'] = r['derived']
+ item['name'] = r['name']
o.append(item)
return o
###############################################################################
@@ -268,21 +269,23 @@ def process(f,kind):
}
return request_processors[kind]()
###############################################################################
+
+# the -H option isn't documented. It's one of the more recent additions, but it's treating refids as if they would be a string. I'm just taking a stab at updating it for now, converting to use rowid, and making other edits necessary to get it to run.
def processHref(cn,ref):
j={}
# is it in memberdef ?
table="memberdef"
- if ( cn.execute("SELECT count(*) from %s WHERE refid=?"%table,[ref] ).fetchone()[0] > 0 ):
- for r in cn.execute("SELECT kind,id FROM %s WHERE refid='%s'" % (table,ref) ).fetchall():
- f=Finder(cn,r['id'],int)
+ if ( cn.execute("SELECT count(*) from %s WHERE rowid=?"%table,[ref] ).fetchone()[0] > 0 ):
+ for r in cn.execute("SELECT kind,rowid FROM %s WHERE rowid=?" % table,[ref]).fetchall():
+ f=Finder(cn,r['rowid'],int)
j=process(f,str(r['kind']))
# is it in compounddef ?
table="compounddef"
- if ( cn.execute("SELECT count(*) from %s WHERE refid=?"%table,[ref]).fetchone()[0] > 0 ):
- for r in cn.execute("SELECT id FROM %s WHERE refid=?"%table,[ref] ).fetchall():
- f=Finder(cn,r['id'],int)
+ if ( cn.execute("SELECT count(*) from %s WHERE rowid=?"%table,[ref]).fetchone()[0] > 0 ):
+ for r in cn.execute("SELECT rowid FROM %s WHERE rowid=?"%table,[ref] ).fetchall():
+ f=Finder(cn,r[0],int)
j=process(f,RequestType.Struct)
return j
@@ -290,7 +293,7 @@ def processHref(cn,ref):
def serveCgi():
import cgi
- print 'Content-Type: application/json\n'
+ print('Content-Type: application/json\n')
fieldStorage = cgi.FieldStorage()
form = dict((key, fieldStorage.getvalue(key)) for key in fieldStorage.keys())
@@ -298,17 +301,17 @@ def serveCgi():
if 'href' in form:
ref = form['href']
else:
- print '{"result": null, "error": "no refid given"}'
+ print('{"result": null, "error": "no refid given"}')
sys.exit(0)
cn=openDb('doxygen_sqlite3.db')
j = processHref(cn,ref)
- print json.dumps({"result":j,"error":None})
+ print(json.dumps({"result":j,"error":None}))
###############################################################################
def usage():
- print >>sys.stderr,"""Usage: search.py [Options]
+ sys.stderr.write("""Usage: search.py [Options]
Options:
-h, --help
-d <D> Use database <D> for queries.
@@ -323,7 +326,7 @@ Options:
-M <C> Get all members of class <C>.
-S <C> Get the sub classes of class <C>.
-R Consider the search <term> to be a regex.
-"""
+""")
###############################################################################
def serveCli(argv):
try:
@@ -362,6 +365,8 @@ def serveCli(argv):
elif a in ('-f'):
kind=MemberType.Function
elif a in ('-F'):
+ # undocumented
+ # seems to fit with the lower case "search" patterns?
kind=MemberType.File
elif a in ('-m'):
kind=MemberType.Define
@@ -370,6 +375,7 @@ def serveCli(argv):
elif a in ('-v'):
kind=MemberType.Variable
elif a in ('-H'):
+ # undocumented
ref = o
cn=openDb(dbname)
@@ -378,7 +384,7 @@ def serveCli(argv):
j=processHref(cn,ref)
else:
j=process(f,kind)
- print json.dumps(j,indent=4)
+ print(json.dumps(j,indent=4))
def main(argv):
diff --git a/addon/doxywizard/doxywizard.cpp b/addon/doxywizard/doxywizard.cpp
index 492912b..4e0d1aa 100755
--- a/addon/doxywizard/doxywizard.cpp
+++ b/addon/doxywizard/doxywizard.cpp
@@ -267,7 +267,7 @@ void MainWindow::saveConfig(const QString &fileName)
{
if (fileName.isEmpty()) return;
QFile f(fileName);
- if (!f.open(QIODevice::WriteOnly))
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Text ))
{
QMessageBox::warning(this,
tr("Error saving"),
diff --git a/addon/doxywizard/expert.cpp b/addon/doxywizard/expert.cpp
index 66a0955..44dea78 100644
--- a/addon/doxywizard/expert.cpp
+++ b/addon/doxywizard/expert.cpp
@@ -765,9 +765,10 @@ void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec,
t << convertToComment(option->templateDocs());
t << endl;
}
- t << name.leftJustified(MAX_OPTION_LENGTH) << "= ";
- if (option)
+ t << name.leftJustified(MAX_OPTION_LENGTH) << "=";
+ if (option && !option->isEmpty())
{
+ t << " ";
option->writeValue(t,codec);
}
t << endl;
diff --git a/addon/doxywizard/input.h b/addon/doxywizard/input.h
index 9e0a1bf..5d86cc8 100644
--- a/addon/doxywizard/input.h
+++ b/addon/doxywizard/input.h
@@ -30,6 +30,7 @@ class Input
virtual void reset() = 0;
virtual void writeValue(QTextStream &t,QTextCodec *codec) = 0;
virtual void setTemplateDocs(const QString &docs) = 0;
+ virtual bool isEmpty() { return false; };
};
diff --git a/addon/doxywizard/inputstring.h b/addon/doxywizard/inputstring.h
index dba31f6..6234256 100644
--- a/addon/doxywizard/inputstring.h
+++ b/addon/doxywizard/inputstring.h
@@ -60,6 +60,7 @@ class InputString : public QObject, public Input
void updateDependencies() {}
void writeValue(QTextStream &t,QTextCodec *codec);
void setTemplateDocs(const QString &docs) { m_tdocs = docs; }
+ bool isEmpty() { return m_str.isEmpty(); }
public slots:
void reset();
diff --git a/addon/doxywizard/inputstrlist.cpp b/addon/doxywizard/inputstrlist.cpp
index 660ce40..822bc4c 100644
--- a/addon/doxywizard/inputstrlist.cpp
+++ b/addon/doxywizard/inputstrlist.cpp
@@ -260,3 +260,11 @@ void InputStrList::writeValue(QTextStream &t,QTextCodec *codec)
}
}
+bool InputStrList::isEmpty()
+{
+ foreach (QString s, m_strList)
+ {
+ if (!s.isEmpty()) return false;
+ }
+ return true;
+}
diff --git a/addon/doxywizard/inputstrlist.h b/addon/doxywizard/inputstrlist.h
index 53f3bcc..c374092 100644
--- a/addon/doxywizard/inputstrlist.h
+++ b/addon/doxywizard/inputstrlist.h
@@ -55,6 +55,7 @@ class InputStrList : public QObject, public Input
void updateDependencies() {}
void writeValue(QTextStream &t,QTextCodec *codec);
void setTemplateDocs(const QString &docs) { m_tdocs = docs; }
+ bool isEmpty();
public slots:
void reset();
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..1119f38
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,52 @@
+image: Visual Studio 2017
+
+configuration:
+ - Release
+ - Debug
+
+platform:
+ - x64
+ - Win32
+
+environment:
+ # VS VERSION IN CMAKE STYLE
+ matrix:
+ - VSVERSION: "15 2017"
+ - VSVERSION: "14 2015"
+
+init:
+ - cmake --version
+ - perl --version
+ - msbuild /version
+
+install:
+ - ps: Invoke-WebRequest https://github.com/lexxmark/winflexbison/releases/download/v2.5.15/win_flex_bison-2.5.15.zip -OutFile flex.zip
+ - 7z x flex.zip -oC:\deps\flex
+ - ps: Invoke-WebRequest https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs924/gs924w32.exe -OutFile gswin32c.exe
+ - gswin32c /S /D=C:\deps\ghostscript
+ - ps: if($env:platform -eq "x64") { Invoke-WebRequest https://miktex.org/download/win/miktexsetup-x64.zip -OutFile miktexsetup.zip }
+ - ps: if($env:platform -eq "Win32") { Invoke-WebRequest https://miktex.org/download/win/miktexsetup-x86.zip -OutFile miktexsetup.zip }
+ - 7z x miktexsetup.zip -oC:\tmpmiktex
+ - C:\tmpmiktex\miktexsetup --local-package-repository=C:\temp\miktex --package-set=basic download
+ - C:\tmpmiktex\miktexsetup --verbose --local-package-repository=C:\temp\miktex --package-set=basic install
+ - refreshenv
+ - pip install conan
+ - conan install libxml2/2.9.8@bincrafters/stable -g virtualrunenv
+ - activate_run.bat
+ - set "PATH=%PATH%;C:\deps\ghostscript\bin;C:\deps\flex"
+
+before_build:
+ - if "%platform%"=="Win32" ( set "CMAKE_GENERATOR_NAME=Visual Studio %VSVERSION%" )
+ - if "%platform%"=="x64" ( set "CMAKE_GENERATOR_NAME=Visual Studio %VSVERSION% Win64")
+ - mkdir build
+ - cd build
+ - cmake -G "%CMAKE_GENERATOR_NAME%" ..
+
+build:
+ project: "build\\PACKAGE.vcxproj"
+ parallel: false
+
+test_script:
+ - msbuild "testing\tests.vcxproj" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+ - cmake -G "%CMAKE_GENERATOR_NAME%" -D build_doc=ON ..
+# - msbuild "doc\docs.vcxproj" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
diff --git a/cmake/FindSQLite3.cmake b/cmake/FindSQLite3.cmake
index 77b8eb4..45cc212 100644
--- a/cmake/FindSQLite3.cmake
+++ b/cmake/FindSQLite3.cmake
@@ -71,8 +71,16 @@ else (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS)
endif (SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES)
if (SQLITE3_FOUND)
+
+ # Extract version from header file
+ find_file(SQLITE3_HEADER "sqlite3.h" HINTS ${SQLITE3_INCLUDE_DIRS})
+ if(SQLITE3_HEADER)
+ file(STRINGS "${SQLITE3_HEADER}" _DEF_TMP REGEX "^#define SQLITE_VERSION +\\\"[^\\\"]+\\\"")
+ string (REGEX REPLACE ".*\\\"(([0-9]+[.]?)+).*" "\\1" SQLITE3_VERSION "${_DEF_TMP}")
+ endif (SQLITE3_HEADER)
+
if (NOT Sqlite3_FIND_QUIETLY)
- message(STATUS "Found Sqlite3: ${SQLITE3_LIBRARIES}")
+ message(STATUS "Found Sqlite3: ${SQLITE3_LIBRARIES} (found version \"${SQLITE3_VERSION}\")")
endif (NOT Sqlite3_FIND_QUIETLY)
else (SQLITE3_FOUND)
if (Sqlite3_FIND_REQUIRED)
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index b95afd8..463d3d7 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -80,6 +80,7 @@ set(DOC_FILES
starting.doc
trouble.doc
xmlcmds.doc
+ emojisup.doc
language.tpl
maintainers.txt
translator.py
diff --git a/doc/Doxyfile b/doc/Doxyfile
index ceb6385..bdd1098 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -38,7 +38,7 @@ INPUT = index.doc install.doc starting.doc docblocks.doc markdown.do
autolink.doc output.doc searching.doc extsearch.doc customize.doc custcmd.doc \
external.doc faq.doc trouble.doc features.doc \
doxygen_usage.doc doxywizard_usage.doc \
- config.doc commands.doc htmlcmds.doc xmlcmds.doc language.doc \
+ config.doc commands.doc htmlcmds.doc xmlcmds.doc emojisup.doc language.doc \
perlmod.doc perlmod_tree.doc arch.doc changelog.doc
FILE_PATTERNS = *.cpp *.h *.doc
EXAMPLE_PATH = ../examples
diff --git a/doc/arch.doc b/doc/arch.doc
index ed9d579..bd51a1b 100644
--- a/doc/arch.doc
+++ b/doc/arch.doc
@@ -248,7 +248,21 @@ Note that by running doxygen with `-d lex` you get information about which
<h3>Testing</h3>
Doxygen has a small set of tests available to test, some, code integrity.
-The tests can be run by means of the command `make tests`. When only one or a few tests are required one can set the variable \c TEST_FLAGS when running the test e.g. `make TEST_FLAGS="--id 5" tests` or for multiple tests `make TEST_FLAGS="--id 5 --id 7" tests`.
+The tests can be run by means of the command `make tests`. When only one or a
+few tests are required one can set the variable \c TEST_FLAGS when running the
+test e.g. `make TEST_FLAGS="--id 5" tests` or for multiple tests
+`make TEST_FLAGS="--id 5 --id 7" tests`. For a full set of possibilities give the
+command `make TEST_FLAGS="--help" tests`. It is also possible to specify the
+`TEST_FLAGS` as an environment variable (works also for testing through Visual
+Studio projects), e.g. `setenv TEST_FLAGS "--id 5 --id 7"` and `make tests`.
+
+<h3>Doxyfile differences</h3>
+
+In case one has to communicate through e.g. a forum the configuration settings that
+are different from the standard doxygen configuration file settings one can run the
+doxygen command: with the `-x` option and the name of the configuration file (default
+is `Doxyfile`). The output will be a list of the not default settings (in `Doxyfile`
+format).
\htmlonly
Return to the <a href="index.html">index</a>.
diff --git a/doc/autolink.doc b/doc/autolink.doc
index ff468e4..bf9fe57 100644
--- a/doc/autolink.doc
+++ b/doc/autolink.doc
@@ -80,7 +80,7 @@
are required to identify the target, i.e. 'func(int) const' and 'func(int)'
target different member functions.
\par Note 3:
- For JavaDoc compatibility a \# may be used instead of a :: in
+ For Javadoc compatibility a \# may be used instead of a :: in
the patterns above.
\par Note 4:
In the documentation of a class containing a member foo,
diff --git a/doc/changelog.doc b/doc/changelog.doc
index 0b245b6..ca00728 100644
--- a/doc/changelog.doc
+++ b/doc/changelog.doc
@@ -718,7 +718,7 @@
<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5569">5569</a> - Fix a potential null pointer dereference in src/searchindex.cpp [<a href="http://github.com/doxygen/doxygen/commit/e21aaadb920775f431a27957542da80e39d0c947">view</a>]</li>
<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5570">5570</a> - Fix wrong pointer initialization in src/definition.cpp [<a href="http://github.com/doxygen/doxygen/commit/cb5d8e6198fe0d0852fb06d6fa18b8ae2682e2c0">view</a>]</li>
<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5571">5571</a> - Fix potential modulo by zero in src/template.cpp [<a href="http://github.com/doxygen/doxygen/commit/c4007c3abea9c8494bf32181a1352b5366bede69">view</a>]</li>
-<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5572">5572</a> - Reached end of file while still insided a (nested) comment in Markdown [<a href="http://github.com/doxygen/doxygen/commit/c7f7c954ec1356e7f361da0d655c72ca0012a0cf">view</a>]</li>
+<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5572">5572</a> - Reached end of file while still inside a (nested) comment in Markdown [<a href="http://github.com/doxygen/doxygen/commit/c7f7c954ec1356e7f361da0d655c72ca0012a0cf">view</a>]</li>
<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5573">5573</a> - Fix a terminating null character after fread in src/filedef.cpp [<a href="http://github.com/doxygen/doxygen/commit/a4003db44dfb624c03b7e0a518e368d3e4b8c1ca">view</a>]</li>
<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5574">5574</a> - Remove not needed variable initialization in src/classdef.cpp [<a href="http://github.com/doxygen/doxygen/commit/5f01852bbfd3c81320ee4aa8cd45875a80b50ee1">view</a>]</li>
<li>Bug <a href="https://github.com/doxygen/doxygen/issues/5575">5575</a> - Remove not needed pointer initialization in src/entry.cpp [<a href="http://github.com/doxygen/doxygen/commit/88832b15f1256846b1228ac411d270c6d092a50b">view</a>]</li>
@@ -2182,7 +2182,7 @@ make sure you add the following:
<h3>New features</h3>
<ul>
<li> Added support for
- <a href="http://daringfireball.net/projects/markdown/">Markdown</a>
+ <a href="https://daringfireball.net/projects/markdown/">Markdown</a>
formatting.
This is enabled by default, but can be disabled by
setting MARKDOWN_SUPPORT to NO. When enabled the following is
@@ -2803,7 +2803,7 @@ make sure you add the following:
<li> id <a href="https://github.com/doxygen/doxygen/issues/3190">3190</a>: dropped support for a4wide paper format for LaTeX, since
it is on the LaTeX taboo list.</li>
<li> id <a href="https://github.com/doxygen/doxygen/issues/3261">3261</a>: Behaviour of CLASS_DIAGRAM=NO in combination with
- HAVE_DOT=YES, was not propely documented.</li>
+ HAVE_DOT=YES, was not properly documented.</li>
<li> id <a href="https://github.com/doxygen/doxygen/issues/3332">3332</a>: Python comments for next class or method could end up in
code of a method/class when enabling INLINE_SOURCES.</li>
<li> id <a href="https://github.com/doxygen/doxygen/issues/3688">3688</a>: Fixed problem handling nested classes in Python.</li>
diff --git a/doc/commands.doc b/doc/commands.doc
index a9973ce..f04b543 100644
--- a/doc/commands.doc
+++ b/doc/commands.doc
@@ -106,6 +106,8 @@ documentation:
\refitem cmdheaderfile \\headerfile
\refitem cmdhidecallergraph \\hidecallergraph
\refitem cmdhidecallgraph \\hidecallgraph
+\refitem cmdhiderefby \\hiderefby
+\refitem cmdhiderefs \\hiderefs
\refitem cmdhideinitializer \\hideinitializer
\refitem cmdhtmlinclude \\htmlinclude
\refitem cmdhtmlonly \\htmlonly
@@ -174,6 +176,8 @@ documentation:
\refitem cmdsee \\see
\refitem cmdshort \\short
\refitem cmdshowinitializer \\showinitializer
+\refitem cmdshowrefby \\showrefby
+\refitem cmdshowrefs \\showrefs
\refitem cmdsince \\since
\refitem cmdskip \\skip
\refitem cmdskipline \\skipline
@@ -214,6 +218,7 @@ documentation:
\refitem cmdperc \\\%
\refitem cmdquot \\\"
\refitem cmdchardot \\\.
+\refitem cmdcolon \:
\refitem cmddcolon \::
\refitem cmdpipe \\|
\refitem cmdndash \\\--
@@ -306,7 +311,7 @@ Structural indicators
When this command is put in a comment block of a function or method
and \ref cfg_have_dot "HAVE_DOT" is set to \c YES, then doxygen will
generate a caller graph for that function (provided the implementation of the
- function or method calls other documented functions). The caller graph will be
+ function or method is called by other documented functions). The caller graph will be
generated regardless of the value of \ref cfg_caller_graph "CALLER_GRAPH".
\note The completeness (and correctness) of the caller graph depends on the
doxygen code parser which is not perfect.
@@ -333,6 +338,74 @@ Structural indicators
option \ref cfg_caller_graph "CALLER_GRAPH"
<hr>
+\section cmdshowrefby \\showrefby
+
+ \addindex \\showrefby
+ When this command is put in a comment block of a function, method or variable,
+ then doxygen will generate an overview for that function, method, variable of
+ the, documented, funcions and methods that call / use it.
+ The overview will be generated regardless of the value of
+ \ref cfg_referenced_by_relation "REFERENCED_BY_RELATION".
+ \note The completeness (and correctness) of the overview depends on the
+ doxygen code parser which is not perfect.
+
+ \sa section \ref cmdshowrefs "\\showrefs",
+ section \ref cmdhiderefby "\\hiderefby",
+ section \ref cmdhiderefs "\\hiderefs" and
+ option \ref cfg_referenced_by_relation "REFERENCED_BY_RELATION"
+
+<hr>
+\section cmdhiderefby \\hiderefby
+
+ \addindex \\hiderefby
+ When this command is put in a comment block of a function, method or variable
+ then doxygen will not generate an overview for that function, method or
+ variable of the functions and methods that call / use it.
+ The overview will not be generated regardless of the value of
+ \ref cfg_referenced_by_relation "REFERENCED_BY_RELATION".
+ \note The completeness (and correctness) of the overview depends on the
+ doxygen code parser which is not perfect.
+
+ \sa section \ref cmdshowrefs "\\showrefs",
+ section \ref cmdshowrefby "\\showrefby",
+ section \ref cmdhiderefs "\\hiderefs" and
+ option \ref cfg_referenced_by_relation "REFERENCED_BY_RELATION"
+
+<hr>
+\section cmdshowrefs \\showrefs
+
+ \addindex \\showrefs
+ When this command is put in a comment block of a function or method,
+ then doxygen will generate an overview for that function or method of the
+ functions and methods that call it.
+ The overview will be generated regardless of the value of
+ \ref cfg_references_relation "REFERENCES_RELATION".
+ \note The completeness (and correctness) of the overview depends on the
+ doxygen code parser which is not perfect.
+
+ \sa section \ref cmdshowrefby "\\showrefby",
+ section \ref cmdhiderefby "\\hiderefby",
+ section \ref cmdhiderefs "\\hiderefs" and
+ option \ref cfg_references_relation "REFERENCES_RELATION"
+
+<hr>
+\section cmdhiderefs \\hiderefs
+
+ \addindex \\hiderefs
+ When this command is put in a comment block of a function or method
+ and then doxygen will not generate an overview for that function or method of
+ the functions and methods that call it.
+ The overview will not be generated regardless of the value of
+ \ref cfg_references_relation "REFERENCES_RELATION".
+ \note The completeness (and correctness) of the overview depends on the
+ doxygen code parser which is not perfect.
+
+ \sa section \ref cmdshowrefs "\\showrefs",
+ section \ref cmdshowrefby "\\showrefby",
+ section \ref cmdhiderefby "\\hiderefby" and
+ option \ref cfg_references_relation "REFERENCES_RELATION"
+
+<hr>
\section cmdcategory \\category <name> [<header-file>] [<header-name>]
\addindex \\category
@@ -442,14 +515,15 @@ Structural indicators
\endlatexonly
</p><hr>
-\section cmdexample \\example <file-name>
+\section cmdexample \\example[{lineno}] <file-name>
\addindex \\example
Indicates that a comment block contains documentation for a source code
- example. The name of the source file is \<file-name\>. The text of
- this file will be included in the documentation, just after the
- documentation contained in the comment block. All examples are placed
- in a list. The source code is scanned for documented members and classes.
+ example. The name of the source file is \<file-name\>.
+ The contents of this file will be included in the documentation, just after the
+ documentation contained in the comment block.
+ You can add option `{lineno}` to enable line numbers for the example if desired.
+ All examples are placed in a list. The source code is scanned for documented members and classes.
If any are found, the names are cross-referenced with the documentation.
Source files or directories can be specified using the
\ref cfg_example_path "EXAMPLE_PATH"
@@ -1887,7 +1961,7 @@ Commands to create links
\section cmdaddindex \\addindex (text)
\addindex \\addindex
- This command adds (text) to the \LaTeX index.
+ This command adds (text) to the \LaTeX , DocBook and RTF index.
<hr>
\section cmdanchor \\anchor <word>
@@ -2033,7 +2107,7 @@ Make sure you have first read \ref intro "the introduction".
\addindex \\tableofcontents
Creates a table of contents at the top of a page, listing all
sections and subsections in the page. The `option` can be `HTML` or `LaTeX`
- or `XML`. When a `level` is specified this means the maximum nesting level
+ or `XML` or `DocBook`. When a `level` is specified this means the maximum nesting level
that is shown. The value of `level` should be in the range 1..5, values outside
this range are considered to be 5. In case no `level` is specified `level` is
set to 5 (show all)
@@ -2151,16 +2225,12 @@ Commands for displaying examples
for the corresponding \mbox{\LaTeX} documentation that is generated by doxygen.
\endlatexonly
- Alternatively, the \ref cmdsnippet "\\snippet" command can be used to
- include only a fragment of a source file. For this to work the
- fragment has to be marked.
-
\sa sections \ref cmdline "\\line", \ref cmdskip "\\skip",
\ref cmdskipline "\\skipline", \ref cmduntil "\\until", and
\ref cmdinclude "\\include".
</p><hr>
-\section cmdinclude \\include <file-name>
+\section cmdinclude \\include[{lineno|doc}] <file-name>
\addindex \\include
This command can be used to include a source file as a block of code.
@@ -2194,33 +2264,38 @@ Commands for displaying examples
\note Doxygen's special commands do not work inside blocks of code.
It is allowed to nest C-style comments inside a code block though.
+ You can add option `{lineno}` to enable line numbers for the included code if desired.
+
+ You can add option `{doc}` to treat the file as documentation rather than code.
+
+ \note Some that when using the `{doc}` option,
+ commands like \ref cmdcond "\\cond" and \ref cmdif "\\if" don't work with
+ this command due to the moment of parsing.
+
+ \note The included documentation should not have comment signs in it as they will appear
+ in the documentation as well.
+
\sa sections \ref cmdexample "\\example", \ref cmddontinclude "\\dontinclude",
- \ref cmdverbatim "\\verbatim" and \ref cmdincludedoc "\\includedoc".
+ \ref cmdverbatim "\\verbatim", \ref cmdincludedoc "\\includedoc", and
+ \ref cmdsnippet "\\snippet".
<hr>
\section cmdincludelineno \\includelineno <file-name>
\addindex \\includelineno
- This command works the same way as \ref cmdinclude "\\include", but will add line
- numbers to the included file.
+ This command is obsolete and is still supported for backward compatibility reasons,
+ it works the same way as \ref cmdinclude "\\include{lineno}"
- \sa sections \ref cmdinclude "\\include" and \ref cmdsnippetlineno "\\snippetlineno".
+ \sa sections \ref cmdinclude "\\include{lineno}".
<hr>
\section cmdincludedoc \\includedoc <file-name>
\addindex \\includedoc
- This command works the same way as \ref cmdinclude "\\include", but it will include
- the content of the file as if it were at the place where this command is called.
- The result is that the content is parsed by doxygen and placed in the documentation.
-
- \note Some commands like \ref cmdcond "\\cond" and \ref cmdif "\\if" don't work with
- this command due to the moment of parsing.
-
- \note The included documentation should not have comment signs in it as they will appear
- in the documentation as well.
+ This command is obsolete and is still supported for backward compatibility reasons,
+ it works the same way as \ref cmdinclude "\\include{doc}"
- \sa section \ref cmdinclude "\\include".
+ \sa section \ref cmdinclude "\\include{doc}".
<hr>
\section cmdline \\line ( pattern )
@@ -2278,7 +2353,7 @@ Commands for displaying examples
See section \ref cmddontinclude "\\dontinclude" for an example.
<hr>
-\section cmdsnippet \\snippet <file-name> ( block_id )
+\section cmdsnippet \\snippet[{lineno|doc}] <file-name> ( block_id )
\addindex \\snippet
Where the \ref cmdinclude "\\include" command can be used to include
@@ -2321,34 +2396,37 @@ Commands for displaying examples
Note also that the [block_id] markers should appear exactly twice in the
source file.
+ You can add option `{lineno}` to enable line numbers for the snippet if desired.
+
+ You can add option `{doc}` to treat the file as documentation rather than code.
+
+ \note Some that when using the `{doc}` option,
+ commands like \ref cmdcond "\\cond" and \ref cmdif "\\if" don't work with
+ this command due to the moment of parsing.
+
+ \note The included documentation should not have comment signs in it as they will appear
+ in the documentation as well.
+
see section \ref cmddontinclude "\\dontinclude" for an alternative way
to include fragments of a source file that does not require markers.
- \sa section \ref cmdsnippetdoc "\\snippetdoc" and \ref cmdsnippetlineno "\\snippetlineno".
<hr>
\section cmdsnippetlineno \\snippetlineno <file-name> ( block_id )
\addindex \\snippetlineno
- This command works the same way as \ref cmdsnippet "\\snippet", but will add line
- numbers to the included snippet.
+ This command is obsolete and is still supported for backward compatibility reasons,
+ it works the same way as \ref cmdsnippet "\\snippet{lineno}"
- \sa sections \ref cmdsnippet "\\snippet" and \ref cmdincludelineno "\\includelineno".
+ \sa sections \ref cmdsnippet "\\snippet{lineno}"
<hr>
\section cmdsnippetdoc \\snippetdoc <file-name> ( block_id )
\addindex \\snippetdoc
- This command works the same way as \ref cmdsnippet "\\snippet", but it will include
- the content of the file between the `block-id`s as if it were at the place where this command is called.
- The result is that the content is parsed by doxygen and placed in the documentation.
-
- \note Some commands like \ref cmdcond "\\cond" and \ref cmdif "\\if" don't work with
- this command due to the moment of parsing.
-
- \note The included documentation should not have comment signs in it as they will appear
- in the documentation as well.
+ This command is obsolete and is still supported for backward compatibility reasons,
+ it works the same way as \ref cmdsnippet "\\snippet{doc}"
- \sa section \ref cmdsnippet "\\snippet" and \ref cmdincludedoc "\\includedoc".
+ \sa section \ref cmdsnippet "\\snippet{doc}" and \ref cmdinclude "\\include{doc}".
<hr>
\section cmduntil \\until ( pattern )
@@ -2603,7 +2681,7 @@ only copy the detailed documentation, not the brief description.
\addindex \\docbookonly
Starts a block of text that will be verbatim included in the
- generated docbook documentation only. The block ends with a
+ generated DocBook documentation only. The block ends with a
\ref cmdenddocbookonly "\\enddocbookonly" command.
\sa section \ref cmdmanonly "\\manonly",
@@ -3077,7 +3155,7 @@ class Receiver
spaces. The quotes are stripped before the caption is displayed.
The fourth argument is also optional and can be used to specify the
- width or height of the image. This can be useful for \LaTeX or docbook output
+ width or height of the image. This can be useful for \LaTeX or DocBook output
(i.e. format=<code>latex</code> or format=<code>docbook</code>).
\anchor image_sizeindicator \par Size indication
The \c sizeindication can specify the width or height to be used (or a combination).
@@ -3279,7 +3357,7 @@ class Receiver
\addindex \\\@
This command writes an at-sign (\c \@) to the output.
The at-sign has to be escaped in some cases
- because doxygen uses it to detect JavaDoc commands.
+ because doxygen uses it to detect Javadoc commands.
<hr>
\section cmdtilde \\~[LanguageId]
@@ -3361,6 +3439,14 @@ class Receiver
the start of a line.
<hr>
+\section cmdcolon \:
+
+ \addindex \\:
+ This command writes a single colon (\c \:) to the output. This
+ character sequence has to be escaped in some cases, because it is used
+ to define `emoji` see also \ref emojisup "Emoji support".
+
+<hr>
\section cmddcolon \\::
\addindex \\::
@@ -3423,4 +3509,3 @@ Go to the <a href="htmlcmds.html">next</a> section or return to the
\endhtmlonly
*/
-
diff --git a/doc/custcmd.doc b/doc/custcmd.doc
index acc0224..02805da 100644
--- a/doc/custcmd.doc
+++ b/doc/custcmd.doc
@@ -44,6 +44,11 @@ Note that you can put `\n`'s in the value part of an alias to insert newlines
(in the resulting output). You can put `^^` in the value part of an alias to
insert a newline as if a physical newline was in the original file.
+Note when you need a literal `{` or `}` or `,` in the value part of an alias you have to
+escape them by means of a backslash (`\`), this can lead to conflicts with the
+commands \c \\{ and \c \\} for these it is advised to use the version \c @@{ and \c @@} or
+use a double escape (\c \\\\{ and \c \\\\})
+
Also note that you can redefine existing special commands if you wish.
Some commands, such as \ref cmdxrefitem "\\xrefitem" are designed to be used in
diff --git a/doc/docblocks.doc b/doc/docblocks.doc
index f02e55b..a9cb05a 100644
--- a/doc/docblocks.doc
+++ b/doc/docblocks.doc
@@ -55,7 +55,7 @@ used to provide tooltips at places where an item is referenced.
There are several ways to mark a comment block as a detailed description:
<ol>
-<li> You can use the JavaDoc style, which consist of a C-style comment
+<li> You can use the Javadoc style, which consist of a C-style comment
block starting with two *'s, like this:
\verbatim
@@ -143,7 +143,7 @@ Here is an example:
<li>If \ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" is set to \c YES
in the configuration file,
- then using JavaDoc style comment
+ then using Javadoc style comment
blocks will automatically start a brief description which ends at the
first dot followed by a space or new line. Here is an example:
@@ -299,8 +299,8 @@ sentence of the detailed descriptions
tag to \c NO). Both the brief and the detailed descriptions are optional
for the Qt style.
-By default a JavaDoc style documentation block behaves the same way as a
-Qt style documentation block. This is not according the JavaDoc specification
+By default a Javadoc style documentation block behaves the same way as a
+Qt style documentation block. This is not according the Javadoc specification
however, where the first sentence of the documentation block is automatically
treated as a brief description. To enable this behavior you should set
\ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" to YES in the configuration
@@ -312,7 +312,7 @@ Here is an example:
\endverbatim
Here is the same piece of code as shown above, this time documented using the
-JavaDoc style and \ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" set to YES:
+Javadoc style and \ref cfg_javadoc_autobrief "JAVADOC_AUTOBRIEF" set to YES:
\include jdstyle.cpp
\htmlonly
</p>
@@ -348,7 +348,7 @@ duplication of information. So in practice you should \e avoid the use of
structural commands \e unless other requirements force you to do so.
Structural commands (like \ref cmd_intro "all other commands") start with a backslash
-(<tt>\\</tt>), or an at-sign (<tt>\@</tt>) if you prefer JavaDoc style,
+(<tt>\\</tt>), or an at-sign (<tt>\@</tt>) if you prefer Javadoc style,
followed by a command name and one or more parameters.
For instance, if you want to document the class \c Test in the example
above, you could have also put the following documentation block somewhere
@@ -632,7 +632,7 @@ and is ideal for a short description.
For longer descriptions you often will find the
need for some more structure, like a block of verbatim text, a list, or a
simple table. For this doxygen supports the
-<a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a>
+<a href="https://daringfireball.net/projects/markdown/syntax">Markdown</a>
syntax, including parts of the
<a href="https://michelf.ca/projects/php-markdown/extra/">Markdown Extra</a>
extension.
@@ -648,8 +648,9 @@ forms of additional markup on top of Markdown formatting.
1. <a href="https://en.wikipedia.org/wiki/Javadoc">Javadoc</a> like markup.
See \ref commands for a complete overview of all commands supported by doxygen.
-2. <a href="https://en.wikipedia.org/wiki/C_Sharp_(programming_language)#XML_documentation_system">XML</a> markup
- as specified in the C# standard. See \ref xmlcmds for the XML commands supported by doxygen.
+2. <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/recommended-tags-for-documentation-comments">XML</a> markup
+ as specified in the <a href="http://standards.iso.org/ittf/PubliclyAvailableStandards/c042926_ISO_IEC_23270_2006(E).zip">C# standard</a>.
+ See \ref xmlcmds for the XML commands supported by doxygen.
If this is still not enough doxygen also supports a \ref htmlcmds "subset" of
the <a href="https://en.wikipedia.org/wiki/HTML">HTML</a> markup language.
diff --git a/doc/doxygen.1 b/doc/doxygen.1
index 1deb7b6..a9c6b38 100644
--- a/doc/doxygen.1
+++ b/doc/doxygen.1
@@ -3,7 +3,7 @@
doxygen \- documentation system for various programming languages
.SH DESCRIPTION
Doxygen is a documentation system for C++, C, Java, Objective-C, IDL
-(Corba and Microsoft flavors) and to some extent PHP, C#, and D.
+(Corba and Microsoft flavors), Fortran, Python, VHDL and to some extent PHP, C#, and D.
.PP
You can use doxygen in a number of ways:
.TP
@@ -25,7 +25,7 @@ If - is used for configName doxygen will read from standard input.
.TP
4) Use doxygen to generate a template file controlling the layout of the generated documentation:
.IP
-doxygen -l layoutFileName.xml
+doxygen -l [layoutFileName.xml]
.TP
5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.
.TP
@@ -41,6 +41,10 @@ LaTeX: doxygen \fB\-w\fR latex headerFile footerFile styleSheetFile [configFile]
.TP
RTF:
doxygen \fB\-e\fR rtf extensionsFile
+.TP
+7) Use doxygen to compare the used configuration file with the template configuration file
+.TP
+doxygen \fB\-x\fR [configFile]
.PP
If \fB\-s\fR is specified the comments in the config file will be omitted.
If configName is omitted `Doxyfile' will be used as a default.
diff --git a/doc/doxygen_manual.tex b/doc/doxygen_manual.tex
index 95e1ed6..e749560 100644
--- a/doc/doxygen_manual.tex
+++ b/doc/doxygen_manual.tex
@@ -121,6 +121,7 @@ Written by Dimitri van Heesch\\[2ex]
\chapter{Special Commands}\label{commands}\hypertarget{commands}{}\input{commands}
\chapter{HTML commands}\label{htmlcmds}\hypertarget{htmlcmds}{}\input{htmlcmds}
\chapter{XML commands}\label{xmlcmds}\hypertarget{xmlcmds}{}\input{xmlcmds}
+\chapter{Emoji support}\label{emojisup}\hypertarget{emojisup}{}\input{emojisup}
\part{Developers Manual}
\chapter{Doxygen's internals}\label{arch}\hypertarget{arch}{}\input{arch}
\chapter{Perl Module Output format}\label{perlmod}\hypertarget{perlmod}{}\input{perlmod}
diff --git a/doc/doxyindexer.1 b/doc/doxyindexer.1
index ae4b282..b0d46d0 100644
--- a/doc/doxyindexer.1
+++ b/doc/doxyindexer.1
@@ -3,7 +3,7 @@
doxyindexer \- creates a search index from raw search data
.SH SYNOPSIS
.B doxyindexer
-[\fI-o output_dir\fR] \fIsearchdata.xml \fR[\fIsearchdata2.xml\fR...] ]
+[\fI-o output_dir\fR] \fIsearchdata.xml \fR[\fIsearchdata2.xml\fR...]
.SH DESCRIPTION
Generates a search index called \fBdoxysearch.db\fR from one or more
search data files produced by doxygen. Use
diff --git a/doc/doxysearch.1 b/doc/doxysearch.1
index a00124f..a26107b 100644
--- a/doc/doxysearch.1
+++ b/doc/doxysearch.1
@@ -2,10 +2,10 @@
.SH NAME
doxysearch.cgi \- search engine used for searching in doxygen documentation.
.SH SYNOPSIS
-.B doxyindexer.cgi
+.B doxysearch.cgi
.SH DESCRIPTION
CGI binary that is used by doxygen generated HTML output to search for words.
The tool uses the search index called \fBdoxysearch.db\fR produced by
doxyindexer.
.SH SEE ALSO
-doxygen(1), doxysearch(1), doxywizard(1).
+doxygen(1), doxyindexer(1), doxywizard(1).
diff --git a/doc/emojisup.doc b/doc/emojisup.doc
new file mode 100644
index 0000000..75a90fb
--- /dev/null
+++ b/doc/emojisup.doc
@@ -0,0 +1,166 @@
+/******************************************************************************
+ *
+ *
+ *
+ * Copyright (C) 1997-2018 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.
+ *
+ */
+/*! \page emojisup Emoji support
+
+The [Unicode consortium](http://www.unicode.org/) has defined a set of
+[emoji](https://en.wikipedia.org/wiki/Emoji) with the corresponding unicode
+sequences and a so called "CLDR short name". The current version a v11.0 and can be found at
+[Full Emoji List, v11.0](https://unicode.org/emoji/charts/full-emoji-list.html) furthermore there is the list with
+[Full Emoji Modifier Sequences, v11.0](http://www.unicode.org/emoji/charts/full-emoji-modifiers.html).
+
+A common way to denote an emoji is by means of `:<text>:`,
+doxygen supports the emoji as mentioned in the above mentioned unicode emoji lists in this way
+by means of the "CLDR short name" with the exception that in case a colon (`:`) is in the
+"CLDR short name" this colon has to be removed.
+Furthermore doxygen supports the list of emoji as used by github (based on the list
+https://api.github.com/emojis). In this list also a reference is given to the unicode codes (just the
+first and last) and these unicodes are mapped onto the official unicode sequences.
+In case the "CLDR short name" and the "github name" are the same the reference from the
+"CLDR short name" has precedence.
+
+Implementation
+
+For the different doxygen output types there is an output defined:
+- Unicode code sequence, the actual representation is depending on the possibilities of the fonts loaded:
+ - HTML
+ - XML
+ - DocBook
+ - RTF, converted to UTF-16 representation.
+- Image
+ - \LaTeX, in case the image can be found (see \ref emojiimage "Emoji image retrieval") otherwise the plain emoji text (i.e. `:<text>:`) is displayed
+- plain emoji text (i.e. `:<text>:`)
+ - man
+ - perl
+
+\anchor emojiimage Emoji image retrieval
+
+In the lists
+[Full Emoji List, v11.0](https://unicode.org/emoji/charts/full-emoji-list.html) and
+[Full Emoji Modifier Sequences, v11.0](http://www.unicode.org/emoji/charts/full-emoji-modifiers.html).
+define images for the different vendors. These images can be retrieved by means of the following procedure (based on the code from Henning Pohl, https://github.com/henningpohl/latex-emoji):
+\code{.py}
+from bs4 import BeautifulSoup
+import base64
+import os
+import requests
+
+# http://www.unicode.org/emoji/charts/index.html
+# http://www.unicode.org/emoji/charts/full-emoji-list.html
+PAGE_URL = 'http://www.unicode.org/emoji/charts/full-emoji-list.html'
+PAGE_URL_SKIN = 'http://www.unicode.org/emoji/charts/full-emoji-modifiers.html'
+PAGE = 'full-emoji-list.html'
+PAGE_SKIN = 'full-emoji-modifiers.html'
+
+
+def get_header_names(header):
+ cols = header.find_all('th')
+ cols = [c.get_text() for c in cols]
+ cols = [c.replace('*','') for c in cols]
+ cols = [c.lower() for c in cols]
+ return cols
+
+def extract_image(column):
+ if 'miss' in column['class']:
+ return None
+
+ if 'miss7' in column['class']:
+ return None
+
+ data = column.img['src']
+ data_start = data.find("base64,")
+ if data_start == -1:
+ return None
+
+ data = base64.b64decode(data[data_start + len("base64,"):])
+ return data
+
+def save_image(folder, imgSrc, filename):
+ if os.path.exists(folder) is False:
+ os.mkdir(folder)
+
+ filename = os.path.join(folder, filename)
+ if os.path.exists(filename):
+ return
+
+ img = extract_image(imgSrc)
+ if img is not None:
+ with open(filename, 'wb') as out:
+ out.write(img)
+
+def scrape(page_url, page):
+ # Possibilities to obtain the basic data:
+ # - use request.get directly
+ soup = BeautifulSoup(requests.get(page_url).text, "html5lib")
+ # - download file (e.g. with wget http://www.unicode.org/emoji/charts/full-emoji-list.html)
+ # with open(page) as fp:
+ # soup = BeautifulSoup(fp,"html5lib")
+
+ table = soup('table')[0]
+
+ # for version 11.0
+ # first row: smileys
+ # second row: face smileys
+ # third row: row with vendors, i.e. the one we want
+ header = table.find_all('tr')[2]
+ keys = get_header_names(header)
+
+ for row in header.find_next_siblings('tr'):
+ fields = {k:c for k, c in zip(keys, row.find_all('td')) }
+ if 'code' not in fields:
+ continue
+
+ codes = fields['code'].text.replace('U+', '').split(' ')
+ filename = "-".join(codes) + ".png"
+
+ save_image('ios', fields['appl'], filename)
+ save_image('android', fields['goog'], filename)
+ save_image('twitter', fields['twtr'], filename)
+ save_image('windows', fields['wind'], filename)
+ save_image('one', fields['one'], filename)
+ save_image('facebook', fields['fb'], filename)
+ save_image('samsung', fields['sams'], filename)
+ #save_image('gmail', fields['gmail'], filename)
+ #save_image('softbank', fields['sb'], filename)
+ #save_image('docomo', fields['dcm'], filename)
+ #save_image('kddi', fields['kddi'], filename)
+ #save_image('bw', fields['chart'], filename)
+
+if __name__ == '__main__':
+ scrape(PAGE_URL, PAGE)
+ scrape(PAGE_URL_SKIN, PAGE_SKIN)
+\endcode
+This results in a number of directories with the supported images. By means of the doxygen configuration parameter
+\ref cfg_latex_emoji_directory "LATEX_EMOJI_DIRECTORY" the requested directory can be selected.
+
+It is also possible to use images from other sources or mix images from different sources, the only requirement is that the filename represents the unicode of the emoji. e.g. if we have the emoji <tt>\:grinning face with big eyes\:</tt> (also known as <tt>\:smiley\:</tt>) the coresponding unicode is `U+1F603` and the name of the file is `1F603.png`.<br>
+For a more complex emoji like <tt>\:keycap 1\:</tt> (also known as <tt>\:one\:</tt>) the coresponding unicode sequence is `U+0031U+FE0FU+20E3` and the name of the file is `0031-FE0F-20E3.png`.
+
+
+Note that when you want to use a colon (`:`) in your text it might be necessary to escape the colon (see \ref cmdcolon "\\:") as it might conflict with a, possible, emoji sequence.
+
+
+For a overview of the supported emoji one can issue the comand:<br>
+`doxygen.exe -f emoji <outputFileName>`
+
+
+\htmlonly
+Go to the <a href="langhowto.html">next</a> section or return to the
+ <a href="index.html">index</a>.
+\endhtmlonly
+
+*/
+
diff --git a/doc/faq.doc b/doc/faq.doc
index e9c93d8..f48e109 100644
--- a/doc/faq.doc
+++ b/doc/faq.doc
@@ -216,7 +216,7 @@ If you don't mind spending some time on it, there are several options:
- If the grammar of X is somewhat different than you can write an input
filter that translates X into something similar enough to C/C++ for
doxygen to understand (this approach is taken for VB, Object Pascal, and
- Javascript, see http://www.stack.nl/~dimitri/doxygen/download.html#helpers).
+ Javascript, see http://www.doxygen.org/download.html#helpers).
- If the grammar is completely different one could write a parser for X and
write a backend that produces a similar syntax tree as is done by
\c src/scanner.l (and also by \c src/tagreader.cpp while reading tag files).
diff --git a/doc/features.doc b/doc/features.doc
index f6aa7c1..8b19898 100644
--- a/doc/features.doc
+++ b/doc/features.doc
@@ -33,7 +33,7 @@
<li>Supports documentation of files, namespaces, packages, classes,
structs, unions, templates, variables, functions, typedefs, enums and
defines.
-<li>JavaDoc (1.1), qdoc3 (partially), and ECMA-334 (C# spec.) compatible.
+<li>Javadoc (1.1), qdoc3 (partially), and ECMA-334 (C# spec.) compatible.
<li>Comes with a GUI frontend (Doxywizard) to ease editing the options and
run doxygen. The GUI is available on Windows, Linux, and MacOSX.
<li>Automatically generates class and collaboration diagrams in HTML (as clickable
@@ -100,7 +100,7 @@
Although doxygen can now be used in any project written in a language that is
supported by doxygen, initially it was specifically designed to be used for projects
that make use of Qt Software's
-<A HREF="http://qt-project.org/">Qt toolkit</A>. I have tried to
+<A HREF="https://www.qt.io/developers/">Qt toolkit</A>. I have tried to
make doxygen `Qt-compatible'. That is: Doxygen can read the documentation contained in
the Qt source code and create a class browser that looks quite similar to the
one that is generated by Qt Software. Doxygen understands the C++ extensions
diff --git a/doc/htmlcmds.doc b/doc/htmlcmds.doc
index b8324f8..d483237 100644
--- a/doc/htmlcmds.doc
+++ b/doc/htmlcmds.doc
@@ -83,6 +83,8 @@ of a HTML tag are passed on to the HTML output only
<li><tt>\</SMALL\></tt> Ends a <tt>\<SMALL\></tt> section.
<li><tt>\<SPAN></tt> Starts an inline text fragment with a specific style (HTML only)
<li><tt>\</SPAN></tt> Ends an inline text fragment with a specific style (HTML only)
+<li><tt>\<STRIKE\></tt> Starts a section of strike through text.
+<li><tt>\</STRIKE\></tt> Ends a section of strike through text.
<li><tt>\<STRONG\></tt> Starts a section of bold text.
<li><tt>\</STRONG\></tt> Ends a section of bold text.
<li><tt>\<SUB\></tt> Starts a piece of text displayed in subscript.
@@ -101,6 +103,8 @@ of a HTML tag are passed on to the HTML output only
<li><tt>\</TT\></tt> Ends a <tt>\<TT\></tt> section.
<li><tt>\<KBD\></tt> Starts a piece of text displayed in a typewriter font.
<li><tt>\</KBD\></tt> Ends a <tt>\<KBD\></tt> section.
+<li><tt>\<U\></tt> Starts a section of underlined text.
+<li><tt>\</U\></tt> Ends a section of underlined text.
<li><tt>\<UL\></tt> Starts an unnumbered item list.
<li><tt>\</UL\></tt> Ends an unnumbered item list.
<li><tt>\<VAR\></tt> Starts a piece of text displayed in an italic font.
diff --git a/doc/index.doc b/doc/index.doc
index 5bb7b2b..9afe624 100644
--- a/doc/index.doc
+++ b/doc/index.doc
@@ -102,6 +102,8 @@ The second part forms a reference manual:
can be used within the documentation.
<li>Section \ref xmlcmds shows an overview of the C# style XML commands that
can be used within the documentation.
+<li>Section \ref emojisup shows an introduction how emoji can be used within
+ the documentation.
</ul>
The third part provides information for developers:
@@ -119,7 +121,7 @@ The third part provides information for developers:
\addindex GPL
Copyright &copy; 1997-2016 by
-<a href="mailto:dimitri@stack.nl">Dimitri van Heesch</a>.<p>
+<a href="mailto:doxygen@gmail.com">Dimitri van Heesch</a>.<p>
Permission to use, copy, modify, and distribute this software and its
documentation under the terms of the GNU General Public License is hereby
@@ -143,7 +145,7 @@ of real-life projects using doxygen.
These are part of a larger
<a href="http://www.doxygen.org/projects.html">list of projects</a>
that use doxygen.
-If you know other projects, let <a href="mailto:dimitri@stack.nl?subject=New%20project%20using%20Doxygen">me</a>
+If you know other projects, let <a href="mailto:doxygen@gmail.com?subject=New%20project%20using%20Doxygen">me</a>
know and I'll add them.
<h2>Future work</h2>
diff --git a/doc/install.doc b/doc/install.doc
index 497a0c0..d64b259 100644
--- a/doc/install.doc
+++ b/doc/install.doc
@@ -36,6 +36,7 @@ following to build the executable:
\addindex make
\addindex strip
\addindex python
+<li>You need \c python (version 2.6 or higher, see https://www.python.org).
<li>In order to generate a \c Makefile for your platform, you need
<a href="https://cmake.org/">cmake</a> version 2.8.12 or later.
\addindex cmake
@@ -46,9 +47,9 @@ tools should be installed.
<ul>
<li>Qt Software's GUI toolkit
- <a href="http://qt-project.org/">Qt</A>
+ <a href="https://www.qt.io/developers/">Qt</A>
\addindex Qt
- version 4.3 or higher (but currently, Qt 5.x is not yet supported).
+ version 4.3 or higher (including Qt 5).
This is needed to build the GUI front-end doxywizard.
<li>A \LaTeX distribution: for instance
<a href="http://www.tug.org/interest.html#free">TeX Live</a>
@@ -151,6 +152,7 @@ standard installation procedure that is required for these packages.
From version 1.8.10 onwards, build files need to be generated by cmake.
cmake can be downloaded from https://cmake.org/download/
+\addindex cmake
At the moment only the express version of Visual Studio 2013 is tested,
but other version might also work.
@@ -160,9 +162,12 @@ Alternatively, you can compile doxygen
<a href="https://en.wikipedia.org/wiki/Cygwin">Cygwin</a>
or <a href="http://www.mingw.org/">MinGW</a>.
+\addindex flex
+\addindex bison
The next step is to install modern versions of \c bison and \c flex
(see https://sourceforge.net/projects/winflexbison/. After installation and adding them to
your `path` rename `win_flex.exe` to `flex.exe` and `win_bison.exe` to `bison.exe`)
+\addindex python
Furthermore you have to install \c python (version 2.6 or higher, see https://www.python.org).
These packages are needed during the compilation process.
@@ -174,7 +179,7 @@ cd c:\tools
tar zxvf doxygen-x.y.z.src.tar.gz
\endverbatim
to unpack the sources (you can obtain \c tar from e.g. http://gnuwin32.sourceforge.net/packages.html).
-Alternatively you can use an unpack program, like 7-Zip (see http://www.7-zip.org)
+Alternatively you can use an unpack program, like 7-Zip (see https://www.7-zip.org/)
or use the build in unpack feature of modern Windows systems).
Now your environment is setup to generate the required project files for \c doxygen.
@@ -186,8 +191,8 @@ cd build
cmake -G "Visual Studio 12 2013" ..
\endverbatim
-Note that compiling Doxywizard currently requires Qt version 4
-(see http://qt-project.org/).
+Note that compiling Doxywizard requires Qt 4.3 or newer
+(see https://www.qt.io/developers/).
Also read the next section for additional tools you may need to install to run
doxygen with certain features enabled.
@@ -206,12 +211,12 @@ If you want to produce compressed HTML files (see \ref
cfg_generate_htmlhelp "GENERATE_HTMLHELP") in the configuration file, then
you need the Microsoft HTML help workshop.
You can download it from
-<a href="http://www.microsoft.com/en-us/download/details.aspx?id=21138">Microsoft</a>.
+<a href="https://www.microsoft.com/en-us/download/details.aspx?id=21138">Microsoft</a>.
If you want to produce Qt Compressed Help files (see \ref
cfg_qhg_location "QHG_LOCATION") in the configuration file, then
you need qhelpgenerator which is part of Qt.
-You can download Qt from <a href="http://qt-project.org/downloads">Qt Software Downloads</a>.
+You can download Qt from <a href="https://www.qt.io/download">Qt Software Downloads</a>.
In order to generate PDF output or use scientific formulas you will also need to
install <a href="https://en.wikipedia.org/wiki/LaTeX">LaTeX</a> and
@@ -219,7 +224,7 @@ install <a href="https://en.wikipedia.org/wiki/LaTeX">LaTeX</a> and
For \LaTeX a number of distributions exists. Popular ones that should work with
doxygen are <a href="https://miktex.org/">MikTex</a>
-and <a href="http://www.tug.org/protext/">proTeXt</a>.
+and <a href="https://www.tug.org/protext/">proTeXt</a>.
Ghostscript can be <a href="https://sourceforge.net/projects/ghostscript/">downloaded</a>
from Sourceforge.
diff --git a/doc/maintainers.txt b/doc/maintainers.txt
index 3fa4fff..7ea40ac 100644
--- a/doc/maintainers.txt
+++ b/doc/maintainers.txt
@@ -50,10 +50,10 @@ Poul-Erik Hansen: pouhan at gnotometrics dot dk
Erik Søe Sørensen: eriksoe+doxygen at daimi dot au dot dk
TranslatorDutch
-Dimitri van Heesch: dimitri at stack dot nl
+Dimitri van Heesch: doxygen at gmail dot com
TranslatorEnglish
-Dimitri van Heesch: dimitri at stack dot nl
+Dimitri van Heesch: doxygen at gmail dot com
TranslatorEsperanto
Ander Martínez: ander dot basaundi at gmail dot com
diff --git a/doc/markdown.doc b/doc/markdown.doc
index 92612ca..5edbaf9 100644
--- a/doc/markdown.doc
+++ b/doc/markdown.doc
@@ -41,7 +41,7 @@ the extensions that doxygen supports.
Finally section \ref markdown_dox discusses some specifics for doxygen's
implementation of the Markdown standard.
-[markdown]: http://daringfireball.net/projects/markdown/
+[markdown]: https://daringfireball.net/projects/markdown/
[mdextra]: https://michelf.ca/projects/php-markdown/extra/
[github]: https://github.github.com/github-flavored-markdown/
@@ -173,7 +173,18 @@ Examples:
* __double underscores__
See section \ref mddox_emph_spans for more info how doxygen handles
-emphasis spans slightly different than standard Markdown.
+emphasis / strikethrough spans slightly different than standard / Markdown GitHub Flavored Markdown.
+
+\subsection md_strikethrough Strikethrough
+
+To strikethrough a text fragment you start and end the fragment with two tildes.
+
+Examples:
+
+* ~~double tilde~~
+
+See section \ref mddox_emph_spans for more info how doxygen handles
+emphasis / strikethrough spans slightly different than standard Markdown / GitHub Flavored Markdown.
\subsection md_codespan code spans
@@ -567,22 +578,22 @@ For Item1 the indentation is 4 (when treating the list marker as whitespace),
so the next paragraph "More text..." starts at the same indentation level
and is therefore not seen as a code block.
-\subsection mddox_emph_spans Emphasis limits
+\subsection mddox_emph_spans Emphasis and strikethrough limits
-Unlike standard Markdown, doxygen will not touch internal underscores or
-stars, so the following will appear as-is:
+Unlike standard Markdown and Github Flavored Markdown doxygen will not touch internal underscores or
+stars or tildes, so the following will appear as-is:
a_nice_identifier
-Furthermore, a `*` or `_` only starts an emphasis if
+Furthermore, a `*` or `_` only starts an emphasis and a `~` only starts a strikethrough if
- it is followed by an alphanumerical character, and
- it is preceded by a space, newline, or one the following characters `<{([,:;`
-An emphasis ends if
+An emphasis or a strikethrough ends if
- it is not followed by an alphanumerical character, and
- it is not preceded by a space, newline, or one the following characters `({[<=+-\@`
-Lastly, the span of the emphasis is limited to a single paragraph.
+Lastly, the span of the emphasis or strikethrough is limited to a single paragraph.
\subsection mddox_code_spans Code Spans Limits
diff --git a/doc/output.doc b/doc/output.doc
index 3a24a60..6d1a567 100644
--- a/doc/output.doc
+++ b/doc/output.doc
@@ -32,7 +32,7 @@ The following output formats are \e directly supported by doxygen:
Word. If you have success with other programs, please let me know.
<dt><b>XML</b>
<dd>Generated if \ref cfg_generate_xml "GENERATE_XML" is set to \c YES in the configuration file.<p>
-<dt><b>Docbook</b>
+<dt><b>DocBook</b>
<dd>Generated if \ref cfg_generate_docbook "GENERATE_DOCBOOOK" is set to \c YES in the configuration file.<p>
</dl>
diff --git a/doc/searching.doc b/doc/searching.doc
index cb6b84a..9bc518a 100644
--- a/doc/searching.doc
+++ b/doc/searching.doc
@@ -126,7 +126,7 @@ has its own advantages and disadvantages:
options you may want to set. After doxygen has finished you will find
a Makefile in the HTML output directory. Running "make install" on this
Makefile will compile and install the doc set.
- See <a href="https://developer.apple.com/library/mac/#featuredarticles/DoxygenXcode/_index.html">this
+ See <a href="https://developer.apple.com/library/archive/featuredarticles/DoxygenXcode/_index.html">this
article</a> for more info.
Advantage of this method is that it nicely integrates with the Xcode
@@ -139,7 +139,7 @@ has its own advantages and disadvantages:
<h2>6. Qt Compressed Help</h2>
If you develop for or want to install the Qt application framework,
you will get an application
- called <a href="http://qt-project.org/doc/qt-4.8/assistant-manual.html">Qt assistant</a>.
+ called <a href="http://doc.qt.io/archives/qt-4.8/assistant-manual.html">Qt assistant</a>.
This is a help viewer for Qt Compressed Help files (<code>.qch</code>).
To enable this feature set \ref cfg_generate_qhp "GENERATE_QHP" to \c YES.
diff --git a/doc/starting.doc b/doc/starting.doc
index 0765a3b..64d3be0 100644
--- a/doc/starting.doc
+++ b/doc/starting.doc
@@ -263,7 +263,7 @@ capabilities of the man page format, so some information
\subsection docbook_out DocBook output
\addindex docbook
Doxygen can also generate output in the
-<a href="http://docbook.org/">DocBook</a> format. How to process the
+<a href="https://docbook.org/">DocBook</a> format. How to process the
DocBook output is beyond the scope of this manual.
\section step3 Step 3: Documenting the sources
diff --git a/doc/trouble.doc b/doc/trouble.doc
index 6b05cd3..c490ae1 100644
--- a/doc/trouble.doc
+++ b/doc/trouble.doc
@@ -128,7 +128,7 @@ please use PATCH as a keyword in the bug entry form.
If you have ideas how to fix existing bugs and limitations please discuss them on
the <a href="http://sourceforge.net/mail/?group_id=5971">developers mailing list</a>
-(subscription required). Patches can also be sent directly to dimitri@stack.nl if
+(subscription required). Patches can also be sent directly to doxygen@gmail.com if
you prefer not to send them via the bug tracker or mailing list.
For patches please use
diff --git a/doc/xmlcmds.doc b/doc/xmlcmds.doc
index 848858d..b59095b 100644
--- a/doc/xmlcmds.doc
+++ b/doc/xmlcmds.doc
@@ -104,7 +104,7 @@ class Engine
\htmlonly
-Go to the <a href="langhowto.html">next</a> section or return to the
+Go to the <a href="emojisup.html">next</a> section or return to the
<a href="index.html">index</a>.
\endhtmlonly
diff --git a/examples/dbusxml.cfg b/examples/dbusxml.cfg
deleted file mode 100644
index d964ea2..0000000
--- a/examples/dbusxml.cfg
+++ /dev/null
@@ -1,14 +0,0 @@
-PROJECT_NAME = "DBusXMLDocs"
-OUTPUT_DIRECTORY = ../html/examples/dbusxml
-GENERATE_LATEX = YES
-GENERATE_MAN = NO
-GENERATE_RTF = NO
-CASE_SENSE_NAMES = NO
-INPUT = dbusxml.xml
-QUIET = YES
-JAVADOC_AUTOBRIEF = YES
-EXTRACT_ALL = YES
-SEARCHENGINE = NO
-EXTENSION_MAPPING = xml=dbusxml
-COMPACT_LATEX = YES
-LATEX_HIDE_INDICES = YES
diff --git a/examples/dbusxml.xml b/examples/dbusxml.xml
deleted file mode 100644
index 4ab7f78..0000000
--- a/examples/dbusxml.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" ?>
-<!-- Comment -->
-<!--*< File comment -->
-<node name="/SomeNode" xmlns:dx="http://psiamp.org/dtd/doxygen_dbusxml.dtd">
- <!--* test struct outside a namespace and interface -->
- <dx:struct name="StructOutsideNamespace">
- <!--* member 1 -->
- <dx:member name="member1" type="s"/>
- <!--* complex member 1 -->
- <dx:member name="complexMember1" type="(ssu)"/>
- </dx:struct>
-
- <!--* Test flag set -->
- <dx:flagset name="flagset">
- <!--* Flag 1 of flagset. -->
- <dx:value name="FLAG1"/>
- </dx:flagset>
-
- <!--* namespace comment -->
- <dx:namespace name="SomeNamespace">
- <!--* struct inside a namespace -->
- <dx:struct name="StructInNamespace">
- <!--* member 2 -->
- <dx:member name="member2" type="s"/>
- </dx:struct>
- </dx:namespace>
- <!--* Documentation on the interface -->
- <interface name="nl.stack.doxygen.test.interface">
- <!--* Test Enum documentation -->
- <dx:enum name="TestEnum">
- <!--* key 1 with value 13 -->
- <dx:value name="KEY1" value="13"/>
- <!--* key 2 without a value -->
- <dx:value name="KEY2"/>
- </dx:enum>
-
- <!--* struct inside a interface -->
- <dx:struct name="StructInInterface">
- <!--* member 3 -->
- <dx:member name="member3" type="s"/>
- <!--* Struct in a struct -->
- <dx:struct name="StructInAStruct">
- <!--* member4 -->
- <dx:member name="member4" type="s"/>
- </dx:struct>
- <!--* struct member -->
- <dx:member name="structMembor" type="(s)" named-type="StructInAStruct"/>
- </dx:struct>
- <!--* Document method
-
- Some extended documentation for the method.
-
- @param[in] input blah.
- @param[out] output blub
- -->
- <method name="method">
- <arg direction="in" name="input" type="(s(s))" named-type="::nl::stack::doxygen::test::interface::StructInInterface"/>
- <arg direction="out" type="v" name="output"/>
- </method>
-
- <signal name="signal">
- <!--*< Documentation for signal.
-
- @param parameter some parameter.
- -->
- <arg name="parameter" type="s"/>
- </signal>
-
- <!--* property documentation -->
- <property name="property" type="s" access="readwrite"/>
-
- <!--* property documentation read-only -->
- <property name="propertyRead" type="s" access="read"/>
- <!--* property documentation write-only -->
- <property name="propertyWrite" type="s" access="write"/>
- </interface>
-</node>
-<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/examples/jdstyle.cfg b/examples/jdstyle.cfg
index 0ddc0d9..d94089d 100644
--- a/examples/jdstyle.cfg
+++ b/examples/jdstyle.cfg
@@ -1,4 +1,4 @@
-PROJECT_NAME = "JavaDoc Style"
+PROJECT_NAME = "Javadoc Style"
OUTPUT_DIRECTORY = ../html/examples/jdstyle
GENERATE_LATEX = YES
GENERATE_MAN = NO
diff --git a/qtools/CMakeLists.txt b/qtools/CMakeLists.txt
index 17f8eb4..cc64de1 100644
--- a/qtools/CMakeLists.txt
+++ b/qtools/CMakeLists.txt
@@ -22,6 +22,7 @@ qstring.cpp
qtextstream.cpp
qtextcodec.cpp
qstringlist.cpp
+qcstringlist.cpp
qxml.cpp
qmap.cpp
qthread.cpp
diff --git a/qtools/qcstringlist.cpp b/qtools/qcstringlist.cpp
new file mode 100644
index 0000000..5725971
--- /dev/null
+++ b/qtools/qcstringlist.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 1997-2018 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.
+**
+** Implementation of QCStringList
+**
+**********************************************************************/
+
+#include "qcstringlist.h"
+
+#include "qstrlist.h"
+#include "qdatastream.h"
+#include "qtl.h"
+
+/*!
+ Splits the string \a str using \a sep as separator. Returns the
+ list of strings. If \a allowEmptyEntries is TRUE, also empty
+ entries are inserted into the list, else not. So if you have
+ a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e'
+ would be returned if \a allowEmptyEntries is FALSE, but
+ a list containing 'abc', '', 'd', 'e' and '' would be returned if
+ \a allowEmptyEntries is TRUE.
+ If \a str doesn't contain \a sep, a stringlist
+ with one item, which is the same as \a str, is returned.
+
+ \sa join()
+*/
+
+QCStringList QCStringList::split( char sep, const QCString &str, bool allowEmptyEntries )
+{
+ char cs[2] = { sep, '\0' };
+ return split( cs, str, allowEmptyEntries );
+}
+
+/*!
+ Splits the string \a str using \a sep as separator. Returns the
+ list of strings. If \a allowEmptyEntries is TRUE, also empty
+ entries are inserted into the list, else not. So if you have
+ a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e'
+ would be returned if \a allowEmptyEntries is FALSE, but
+ a list containing 'abc', '', 'd', 'e' and '' would be returned if
+ \a allowEmptyEntries is TRUE.
+ If \a str doesn't contain \a sep, a stringlist
+ with one item, which is the same as \a str, is returned.
+
+ \sa join()
+*/
+
+QCStringList QCStringList::split( const QCString &sep, const QCString &str, bool allowEmptyEntries )
+{
+ QCStringList lst;
+
+ int j = 0;
+ int i = str.find( sep, j );
+
+ while ( i != -1 ) {
+ if ( str.mid( j, i - j ).length() > 0 )
+ lst << str.mid( j, i - j );
+ else if ( allowEmptyEntries )
+ lst << QCString();
+ j = i + sep.length();
+ i = str.find( sep, j );
+ }
+
+ int l = str.length() - 1;
+ if ( str.mid( j, l - j + 1 ).length() > 0 )
+ lst << str.mid( j, l - j + 1 );
+ else if ( allowEmptyEntries )
+ lst << QCString();
+
+ return lst;
+}
+
+/*!
+ Splits the string \a str using the regular expression \a sep as separator. Returns the
+ list of strings. If \a allowEmptyEntries is TRUE, also empty
+ entries are inserted into the list, else not. So if you have
+ a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e'
+ would be returned if \a allowEmptyEntries is FALSE, but
+ a list containing 'abc', '', 'd', 'e' and '' would be returned if
+ \a allowEmptyEntries is TRUE.
+ If \a str doesn't contain \a sep, a stringlist
+ with one item, which is the same as \a str, is returned.
+
+ \sa join()
+*/
+
+QCStringList QCStringList::split( const QRegExp &sep, const QCString &str, bool allowEmptyEntries )
+{
+ QCStringList lst;
+
+ int j = 0;
+ int len = 0;
+ int i = sep.match( str.data(), j, &len );
+
+ while ( i != -1 ) {
+ if ( str.mid( j, i - j ).length() > 0 )
+ lst << str.mid( j, i - j );
+ else if ( allowEmptyEntries )
+ lst << QCString();
+ j = i + len;
+ i = sep.match( str.data(), j, &len );
+ }
+
+ int l = str.length() - 1;
+ if ( str.mid( j, l - j + 1 ).length() > 0 )
+ lst << str.mid( j, l - j + 1 );
+ else if ( allowEmptyEntries )
+ lst << QCString();
+
+ return lst;
+}
+
+/*!
+ Returns a list of all strings containing the substring \a str.
+
+ If \a cs is TRUE, the grep is done case sensitively, else not.
+*/
+
+QCStringList QCStringList::grep( const QCString &str, bool cs ) const
+{
+ QCStringList res;
+ for ( QCStringList::ConstIterator it = begin(); it != end(); ++it )
+ if ( (*it).contains( str, cs ) )
+ res << *it;
+
+ return res;
+}
+
+/*!
+ Returns a list of all strings containing a substring that matches
+ the regular expression \a expr.
+*/
+
+QCStringList QCStringList::grep( const QRegExp &expr ) const
+{
+ QCStringList res;
+ for ( QCStringList::ConstIterator it = begin(); it != end(); ++it )
+ if ( (*it).contains( expr ) )
+ res << *it;
+
+ return res;
+}
+
+/*!
+ Joins the stringlist into a single string with each element
+ separated by \a sep.
+
+ \sa split()
+*/
+QCString QCStringList::join( const QCString &sep ) const
+{
+ QCString res;
+ bool alredy = FALSE;
+ for ( QCStringList::ConstIterator it = begin(); it != end(); ++it ) {
+ if ( alredy )
+ res += sep;
+ alredy = TRUE;
+ res += *it;
+ }
+
+ return res;
+}
+
+Q_EXPORT QDataStream &operator>>( QDataStream & s, QCStringList& l )
+{
+ return s >> (QValueList<QCString>&)l;
+}
+
+Q_EXPORT QDataStream &operator<<( QDataStream & s, const QCStringList& l )
+{
+ return s << (const QValueList<QCString>&)l;
+}
+
+/*!
+ Converts from a QStrList (ASCII) to a QCStringList (Unicode).
+*/
+QCStringList QCStringList::fromStrList(const QStrList& ascii)
+{
+ QCStringList res;
+ const char * s;
+ for ( QStrListIterator it(ascii); (s=it.current()); ++it )
+ res << s;
+ return res;
+}
+
diff --git a/qtools/qcstringlist.h b/qtools/qcstringlist.h
new file mode 100644
index 0000000..604a196
--- /dev/null
+++ b/qtools/qcstringlist.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 1997-2018 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.
+**
+** Note: this is a variant of the qstringlist.h but for QCString's
+**
+**********************************************************************/
+#ifndef QCSTRINGLIST_H
+#define QCSTRINGLIST_H
+
+#include "qvaluelist.h"
+#include "qcstring.h"
+#include "qregexp.h"
+
+class QStrList;
+class QDataStream;
+
+class QCStringList : public QValueList<QCString>
+{
+public:
+ QCStringList() { }
+ QCStringList( const QCStringList& l ) : QValueList<QCString>(l) { }
+ QCStringList( const QValueList<QCString>& l ) : QValueList<QCString>(l) { }
+ QCStringList( const QCString& i ) { append(i); }
+ QCStringList( const char* i ) { append(i); }
+
+ static QCStringList fromStrList(const QStrList&);
+
+ static QCStringList split( const QCString &sep, const QCString &str, bool allowEmptyEntries = FALSE );
+ static QCStringList split( char sep, const QCString &str, bool allowEmptyEntries = FALSE );
+ static QCStringList split( const QRegExp &sep, const QCString &str, bool allowEmptyEntries = FALSE );
+ QCString join( const QCString &sep ) const;
+
+ QCStringList grep( const QCString &str, bool cs = TRUE ) const;
+ QCStringList grep( const QRegExp &expr ) const;
+};
+
+extern Q_EXPORT QDataStream &operator>>( QDataStream &, QCStringList& );
+extern Q_EXPORT QDataStream &operator<<( QDataStream &, const QCStringList& );
+
+#endif // QCSTRINGLIST_H
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b57d360..4dc31fa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -183,6 +183,7 @@ add_library(_doxygen STATIC
dot.cpp
doxygen.cpp
eclipsehelp.cpp
+ emoji.cpp
entry.cpp
filedef.cpp
filename.cpp
diff --git a/src/clangparser.cpp b/src/clangparser.cpp
index 78b8faa..18dd404 100644
--- a/src/clangparser.cpp
+++ b/src/clangparser.cpp
@@ -964,6 +964,7 @@ void ClangParser::writeSources(CodeOutputInterface &,FileDef *)
ClangParser::ClangParser()
{
+ p = NULL;
}
ClangParser::~ClangParser()
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 657968e..28308db 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -671,6 +671,10 @@ void ClassDef::internalInsertMember(MemberDef *md,
case MemberType_Variable:
addMemberToList(MemberListType_variableMembers,md,FALSE);
break;
+ case MemberType_Define:
+ warn(md->getDefFileName(),md->getDefLine()-1,"A define (%s) cannot be made a member of %s",
+ md->name().data(), this->name().data());
+ break;
default:
err("Unexpected member type %d found!\n",md->memberType());
}
@@ -1013,13 +1017,13 @@ void ClassDef::writeDetailedDocumentationBody(OutputList &ol)
// write examples
if (hasExamples() && m_impl->exampleSDict)
{
- ol.startSimpleSect(BaseOutputDocInterface::Examples,0,0,theTranslator->trExamples()+": ");
+ ol.startExamples();
ol.startDescForItem();
//ol.startParagraph();
writeExample(ol,m_impl->exampleSDict);
//ol.endParagraph();
ol.endDescForItem();
- ol.endSimpleSect();
+ ol.endExamples();
}
//ol.newParagraph();
writeSourceDef(ol,name());
@@ -1110,7 +1114,15 @@ void ClassDef::showUsedFiles(OutputList &ol)
ol.writeRuler();
- ol.parseText(generatedFromFiles());
+ ol.pushGeneratorState();
+ ol.disableAllBut(OutputGenerator::Docbook);
+ ol.startParagraph();
+ ol.parseText(generatedFromFiles());
+ ol.endParagraph();
+ ol.popGeneratorState();
+ ol.disable(OutputGenerator::Docbook);
+ ol.parseText(generatedFromFiles());
+ ol.enable(OutputGenerator::Docbook);
bool first=TRUE;
QListIterator<FileDef> li(m_impl->files);
@@ -1223,7 +1235,7 @@ void ClassDef::writeInheritanceGraph(OutputList &ol)
}
}
else if (Config_getBool(CLASS_DIAGRAMS) && count>0)
- // write class diagram using build-in generator
+ // write class diagram using built-in generator
{
ClassDiagram diagram(this); // create a diagram of this class.
ol.startClassDiagram();
@@ -1839,6 +1851,7 @@ void ClassDef::writeMoreLink(OutputList &ol,const QCString &anchor)
// LaTeX + RTF
ol.disable(OutputGenerator::Html);
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
if (!(usePDFLatex && pdfHyperlinks))
{
ol.disable(OutputGenerator::Latex);
diff --git a/src/cmdmapper.cpp b/src/cmdmapper.cpp
index 2c8effc..acbbe44 100644
--- a/src/cmdmapper.cpp
+++ b/src/cmdmapper.cpp
@@ -120,6 +120,7 @@ CommandMap cmdMap[] =
{ ".", CMD_PUNT },
{ "+", CMD_PLUS },
{ "-", CMD_MINUS },
+ { ":", CMD_COLON },
{ "::", CMD_DCOLON },
{ "\"", CMD_QUOTE },
{ "_internalref", CMD_INTERNALREF },
@@ -193,6 +194,8 @@ CommandMap htmlTagMap[] =
{ "span", HTML_SPAN },
{ "div", HTML_DIV },
{ "blockquote", HTML_BLOCKQUOTE },
+ { "strike", HTML_STRIKE },
+ { "u", HTML_UNDERLINE },
{ "c", XML_C },
// { "code", XML_CODE }, <= ambiguous <code> is also a HTML tag
diff --git a/src/cmdmapper.h b/src/cmdmapper.h
index 8cb529d..c1747ee 100644
--- a/src/cmdmapper.h
+++ b/src/cmdmapper.h
@@ -136,7 +136,8 @@ enum CommandType
CMD_MINUS = 106,
CMD_INCLUDEDOC = 107,
CMD_SNIPPETDOC = 108,
- CMD_SNIPWITHLINES= 109
+ CMD_SNIPWITHLINES= 109,
+ CMD_COLON = 110
};
enum HtmlTagType
@@ -175,6 +176,8 @@ enum HtmlTagType
HTML_SPAN = 31,
HTML_DIV = 32,
HTML_BLOCKQUOTE= 33,
+ HTML_STRIKE = 34,
+ HTML_UNDERLINE = 35,
XML_CmdMask = 0x100,
diff --git a/src/code.l b/src/code.l
index 2c9b0ae..e6dd8ba 100644
--- a/src/code.l
+++ b/src/code.l
@@ -983,7 +983,7 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName
}
}
NamespaceDef *nd = getResolvedNamespace(className);
- if (nd)
+ if (nd && nd->isLinkableInProject())
{
g_theCallContext.setScope(nd);
addToSearchIndex(className);
@@ -1324,7 +1324,9 @@ static void generateFunctionLink(CodeOutputInterface &ol,const char *funcName)
//CodeClassDef *ccd=0;
ClassDef *ccd=0;
QCString locScope=g_classScope;
- QCString locFunc=removeRedundantWhiteSpace(funcName);
+ QString qq=removeRedundantWhiteSpace(funcName);
+ if (g_insidePHP && qq.startsWith("self::")) qq=qq.mid(4);
+ QCString locFunc(qq.data());
QCString funcScope;
QCString funcWithScope=locFunc;
QCString funcWithFullScope=locFunc;
@@ -2170,8 +2172,12 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_code->codify(yytext);
endFontClass();
}
+<ClassName>{ID}("."{ID})* |
<ClassName>{ID}("::"{ID})* {
- g_curClassName=yytext;
+ if(g_insideCS)
+ g_curClassName=substitute(yytext,".","::");
+ else
+ g_curClassName=yytext;
addType();
if (g_curClassName=="alignas")
{
@@ -2596,7 +2602,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
generatePHPVariableLink(*g_code,yytext);
g_name+=yytext+7;
}
-<Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\"\>]*">"("::"{ID})*/{B}* { // A<T> *pt;
+<Body,TemplCast>{SCOPENAME}{B}*"<"[^\n\/\-\.\{\"\>\(]*">"("::"{ID})*/{B}* { // A<T> *pt;
int i=QCString(yytext).find('<');
QCString kw = QCString(yytext).left(i).stripWhiteSpace();
if (kw.right(5)=="_cast" && YY_START==Body)
@@ -2627,6 +2633,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
addType();
g_name=varname;
}
+<Body>{SCOPETNAME}{B}*"<"[^\n\/\-\.\{\"\>]*">"/{BN}*"(" |
<Body>{SCOPETNAME}/{BN}*"(" { // a() or c::a() or t<A,B>::a() or A\B\foo()
addType();
generateFunctionLink(*g_code,yytext);
diff --git a/src/commentscan.h b/src/commentscan.h
index e202f0a..d324969 100644
--- a/src/commentscan.h
+++ b/src/commentscan.h
@@ -40,7 +40,7 @@ class ParserInterface;
* @param[in,out] lineNr The line number at which the comment block was found.
* When the function returns it will be set to the last line parsed.
* @param[in] isBrief TRUE iff this comment block represents a brief description.
- * @param[in] isJavaDocStyle TRUE iff this comment block is in "JavaDoc" style.
+ * @param[in] isJavadocStyle TRUE iff this comment block is in "Javadoc" style.
* This means that it starts as a brief description until the end of
* the sentences is found and then proceeds as a detailed description.
* @param[in] isInbody TRUE iff this comment block is located in the body of
@@ -65,7 +65,7 @@ bool parseCommentBlock(ParserInterface *parser,
const QCString &fileName,
int &lineNr,
bool isBrief,
- bool isJavaDocStyle,
+ bool isJavadocStyle,
bool isInbody,
Protection &prot,
int &position,
diff --git a/src/commentscan.l b/src/commentscan.l
index e40d80f..e317a86 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -30,8 +30,7 @@
#include <qstack.h>
#include <qregexp.h>
#include <qfile.h>
-#include <qstringlist.h>
-
+#include <qcstringlist.h>
#include "scanner.h"
#include "entry.h"
#include "doxygen.h"
@@ -55,81 +54,85 @@
#define YY_NO_UNISTD_H 1
// forward declarations
-static bool handleBrief(const QCString &, const QCString &);
-static bool handleFn(const QCString &, const QCString &);
-static bool handleDef(const QCString &, const QCString &);
-static bool handleOverload(const QCString &, const QCString &);
-static bool handleEnum(const QCString &, const QCString &);
-static bool handleDefGroup(const QCString &, const QCString &);
-static bool handleAddToGroup(const QCString &, const QCString &);
-static bool handleWeakGroup(const QCString &, const QCString &);
-static bool handleNamespace(const QCString &, const QCString &);
-static bool handlePackage(const QCString &, const QCString &);
-static bool handleClass(const QCString &, const QCString &);
-static bool handleHeaderFile(const QCString &, const QCString &);
-static bool handleProtocol(const QCString &, const QCString &);
-static bool handleCategory(const QCString &, const QCString &);
-static bool handleUnion(const QCString &, const QCString &);
-static bool handleStruct(const QCString &, const QCString &);
-static bool handleInterface(const QCString &, const QCString &);
-static bool handleIdlException(const QCString &, const QCString &);
-static bool handlePage(const QCString &, const QCString &);
-static bool handleMainpage(const QCString &, const QCString &);
-static bool handleFile(const QCString &, const QCString &);
-static bool handleDir(const QCString &, const QCString &);
-static bool handleExample(const QCString &, const QCString &);
-static bool handleDetails(const QCString &, const QCString &);
-static bool handleName(const QCString &, const QCString &);
-static bool handleTodo(const QCString &, const QCString &);
-static bool handleTest(const QCString &, const QCString &);
-static bool handleBug(const QCString &, const QCString &);
-static bool handleSubpage(const QCString &s, const QCString &);
-static bool handleDeprecated(const QCString &, const QCString &);
-static bool handleXRefItem(const QCString &, const QCString &);
-static bool handleRelated(const QCString &, const QCString &);
-static bool handleRelatedAlso(const QCString &, const QCString &);
-static bool handleMemberOf(const QCString &, const QCString &);
-static bool handleRefItem(const QCString &, const QCString &);
-static bool handleSection(const QCString &, const QCString &);
-static bool handleAnchor(const QCString &, const QCString &);
-static bool handleCite(const QCString &, const QCString &);
-static bool handleFormatBlock(const QCString &, const QCString &);
-static bool handleAddIndex(const QCString &, const QCString &);
-static bool handleIf(const QCString &, const QCString &);
-static bool handleIfNot(const QCString &, const QCString &);
-static bool handleElseIf(const QCString &, const QCString &);
-static bool handleElse(const QCString &, const QCString &);
-static bool handleEndIf(const QCString &, const QCString &);
-static bool handleIngroup(const QCString &, const QCString &);
-static bool handleNoSubGrouping(const QCString &, const QCString &);
-static bool handleShowInitializer(const QCString &, const QCString &);
-static bool handleHideInitializer(const QCString &, const QCString &);
-static bool handleCallgraph(const QCString &, const QCString &);
-static bool handleHideCallgraph(const QCString &, const QCString &);
-static bool handleCallergraph(const QCString &, const QCString &);
-static bool handleHideCallergraph(const QCString &, const QCString &);
-static bool handleInternal(const QCString &, const QCString &);
-static bool handleLineBr(const QCString &, const QCString &);
-static bool handleStatic(const QCString &, const QCString &);
-static bool handlePure(const QCString &, const QCString &);
-static bool handlePrivate(const QCString &, const QCString &);
-static bool handlePrivateSection(const QCString &, const QCString &);
-static bool handleProtected(const QCString &, const QCString &);
-static bool handleProtectedSection(const QCString &, const QCString &);
-static bool handlePublic(const QCString &s, const QCString &);
-static bool handlePublicSection(const QCString &s, const QCString &);
-static bool handleToc(const QCString &s, const QCString &);
-static bool handleInherit(const QCString &, const QCString &);
-static bool handleExtends(const QCString &, const QCString &);
-static bool handleCopyDoc(const QCString &, const QCString &);
-static bool handleCopyBrief(const QCString &, const QCString &);
-static bool handleCopyDetails(const QCString &, const QCString &);
-static bool handleParBlock(const QCString &, const QCString &);
-static bool handleEndParBlock(const QCString &, const QCString &);
-static bool handleParam(const QCString &, const QCString &);
-static bool handleRetval(const QCString &, const QCString &);
-
-typedef bool (*DocCmdFunc)(const QCString &name, const QCString &opt);
+static bool handleBrief(const QCString &, const QCStringList &);
+static bool handleFn(const QCString &, const QCStringList &);
+static bool handleDef(const QCString &, const QCStringList &);
+static bool handleOverload(const QCString &, const QCStringList &);
+static bool handleEnum(const QCString &, const QCStringList &);
+static bool handleDefGroup(const QCString &, const QCStringList &);
+static bool handleAddToGroup(const QCString &, const QCStringList &);
+static bool handleWeakGroup(const QCString &, const QCStringList &);
+static bool handleNamespace(const QCString &, const QCStringList &);
+static bool handlePackage(const QCString &, const QCStringList &);
+static bool handleClass(const QCString &, const QCStringList &);
+static bool handleHeaderFile(const QCString &, const QCStringList &);
+static bool handleProtocol(const QCString &, const QCStringList &);
+static bool handleCategory(const QCString &, const QCStringList &);
+static bool handleUnion(const QCString &, const QCStringList &);
+static bool handleStruct(const QCString &, const QCStringList &);
+static bool handleInterface(const QCString &, const QCStringList &);
+static bool handleIdlException(const QCString &, const QCStringList &);
+static bool handlePage(const QCString &, const QCStringList &);
+static bool handleMainpage(const QCString &, const QCStringList &);
+static bool handleFile(const QCString &, const QCStringList &);
+static bool handleDir(const QCString &, const QCStringList &);
+static bool handleExample(const QCString &, const QCStringList &);
+static bool handleDetails(const QCString &, const QCStringList &);
+static bool handleName(const QCString &, const QCStringList &);
+static bool handleTodo(const QCString &, const QCStringList &);
+static bool handleTest(const QCString &, const QCStringList &);
+static bool handleBug(const QCString &, const QCStringList &);
+static bool handleSubpage(const QCString &s, const QCStringList &);
+static bool handleDeprecated(const QCString &, const QCStringList &);
+static bool handleXRefItem(const QCString &, const QCStringList &);
+static bool handleRelated(const QCString &, const QCStringList &);
+static bool handleRelatedAlso(const QCString &, const QCStringList &);
+static bool handleMemberOf(const QCString &, const QCStringList &);
+static bool handleRefItem(const QCString &, const QCStringList &);
+static bool handleSection(const QCString &, const QCStringList &);
+static bool handleAnchor(const QCString &, const QCStringList &);
+static bool handleCite(const QCString &, const QCStringList &);
+static bool handleFormatBlock(const QCString &, const QCStringList &);
+static bool handleAddIndex(const QCString &, const QCStringList &);
+static bool handleIf(const QCString &, const QCStringList &);
+static bool handleIfNot(const QCString &, const QCStringList &);
+static bool handleElseIf(const QCString &, const QCStringList &);
+static bool handleElse(const QCString &, const QCStringList &);
+static bool handleEndIf(const QCString &, const QCStringList &);
+static bool handleIngroup(const QCString &, const QCStringList &);
+static bool handleNoSubGrouping(const QCString &, const QCStringList &);
+static bool handleShowInitializer(const QCString &, const QCStringList &);
+static bool handleHideInitializer(const QCString &, const QCStringList &);
+static bool handleCallgraph(const QCString &, const QCStringList &);
+static bool handleHideCallgraph(const QCString &, const QCStringList &);
+static bool handleCallergraph(const QCString &, const QCStringList &);
+static bool handleHideCallergraph(const QCString &, const QCStringList &);
+static bool handleReferencedByRelation(const QCString &, const QCStringList &);
+static bool handleHideReferencedByRelation(const QCString &, const QCStringList &);
+static bool handleReferencesRelation(const QCString &, const QCStringList &);
+static bool handleHideReferencesRelation(const QCString &, const QCStringList &);
+static bool handleInternal(const QCString &, const QCStringList &);
+static bool handleLineBr(const QCString &, const QCStringList &);
+static bool handleStatic(const QCString &, const QCStringList &);
+static bool handlePure(const QCString &, const QCStringList &);
+static bool handlePrivate(const QCString &, const QCStringList &);
+static bool handlePrivateSection(const QCString &, const QCStringList &);
+static bool handleProtected(const QCString &, const QCStringList &);
+static bool handleProtectedSection(const QCString &, const QCStringList &);
+static bool handlePublic(const QCString &s, const QCStringList &);
+static bool handlePublicSection(const QCString &s, const QCStringList &);
+static bool handleToc(const QCString &s, const QCStringList &);
+static bool handleInherit(const QCString &, const QCStringList &);
+static bool handleExtends(const QCString &, const QCStringList &);
+static bool handleCopyDoc(const QCString &, const QCStringList &);
+static bool handleCopyBrief(const QCString &, const QCStringList &);
+static bool handleCopyDetails(const QCString &, const QCStringList &);
+static bool handleParBlock(const QCString &, const QCStringList &);
+static bool handleEndParBlock(const QCString &, const QCStringList &);
+static bool handleParam(const QCString &, const QCStringList &);
+static bool handleRetval(const QCString &, const QCStringList &);
+
+typedef bool (*DocCmdFunc)(const QCString &name, const QCStringList &optList);
struct DocCmdMap
{
@@ -215,6 +218,10 @@ static DocCmdMap docCmdMap[] =
{ "hidecallgraph", &handleHideCallgraph, FALSE },
{ "callergraph", &handleCallergraph, FALSE },
{ "hidecallergraph", &handleHideCallergraph, FALSE },
+ { "showrefby", &handleReferencedByRelation, FALSE },
+ { "hiderefby", &handleHideReferencedByRelation, FALSE },
+ { "showrefs", &handleReferencesRelation, FALSE },
+ { "hiderefs", &handleHideReferencesRelation, FALSE },
{ "internal", &handleInternal, TRUE },
{ "_linebr", &handleLineBr, FALSE },
{ "static", &handleStatic, FALSE },
@@ -1006,7 +1013,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
* words and whitespace and other characters (#,?!, etc).
* grouping commands (e.g. @{ and @})
* language switch (e.g. \~english or \~).
- * mail address (e.g. dimitri@stack.nl).
+ * mail address (e.g. doxygen@gmail.com).
* quoted text, such as "foo@bar"
* XML commands, <summary></summary><remarks></remarks>
*/
@@ -1106,16 +1113,18 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
// the {B}* in the front was added for bug620924
QCString fullMatch = QCString(yytext);
int idx = fullMatch.find('{');
+ int idxEnd = fullMatch.find("}",idx+1);
QCString cmdName;
- QCString optName;
- if (idx == -1)
+ QCStringList optList;
+ if (idx == -1) // no options
{
cmdName = QCString(yytext).stripWhiteSpace().data()+1; // to remove {CMD}
}
- else
+ else // options present
{
cmdName = fullMatch.left(idx).stripWhiteSpace().data()+1; // to remove {CMD}
- optName = fullMatch.right(fullMatch.length() - idx).stripWhiteSpace().data();
+ QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
+ optList = QCStringList::split(',',optStr);
}
DocCmdMapper::Cmd *cmdPtr = DocCmdMapper::map(cmdName);
if (cmdPtr) // special action is required
@@ -1130,7 +1139,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
setOutput(OutputDoc);
}
//if (i>0) addOutput(QCString(yytext).left(i)); // removed for bug 689341
- if (cmdPtr->func && cmdPtr->func(cmdName, optName))
+ if (cmdPtr->func && cmdPtr->func(cmdName, optList))
{
// implicit split of the comment block into two
// entries. Restart the next block at the start
@@ -1588,8 +1597,12 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
<PageDocArg1>. { // ignore other stuff
}
<PageDocArg2>.*"\n" { // second argument; page title
- yyLineNr++;
- current->args = yytext;
+ yyLineNr++;
+ // bug 748927
+ QCString tmp = yytext;
+ tmp = substitute(substitute(tmp,"@<","&lt;"),"@>","&gt;");
+ tmp = substitute(substitute(tmp,"\\<","&lt;"),"\\>","&gt;");
+ current->args = tmp;
addOutput('\n');
BEGIN( Comment );
}
@@ -2293,14 +2306,14 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
//----------------------------------------------------------------------------
-static bool handleBrief(const QCString &, const QCString &)
+static bool handleBrief(const QCString &, const QCStringList &)
{
//printf("handleBrief\n");
setOutput(OutputBrief);
return FALSE;
}
-static bool handleFn(const QCString &, const QCString &)
+static bool handleFn(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::MEMBERDOC_SEC);
functionProto.resize(0);
@@ -2309,7 +2322,7 @@ static bool handleFn(const QCString &, const QCString &)
return stop;
}
-static bool handleDef(const QCString &, const QCString &)
+static bool handleDef(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::DEFINEDOC_SEC);
functionProto.resize(0);
@@ -2317,21 +2330,21 @@ static bool handleDef(const QCString &, const QCString &)
return stop;
}
-static bool handleOverload(const QCString &, const QCString &)
+static bool handleOverload(const QCString &, const QCStringList &)
{
functionProto.resize(0);
BEGIN(OverloadParam);
return FALSE;
}
-static bool handleEnum(const QCString &, const QCString &)
+static bool handleEnum(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::ENUMDOC_SEC);
BEGIN(EnumDocArg1);
return stop;
}
-static bool handleDefGroup(const QCString &, const QCString &)
+static bool handleDefGroup(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
current->groupDocType = Entry::GROUPDOC_NORMAL;
@@ -2339,7 +2352,7 @@ static bool handleDefGroup(const QCString &, const QCString &)
return stop;
}
-static bool handleAddToGroup(const QCString &, const QCString &)
+static bool handleAddToGroup(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
current->groupDocType = Entry::GROUPDOC_ADD;
@@ -2347,7 +2360,7 @@ static bool handleAddToGroup(const QCString &, const QCString &)
return stop;
}
-static bool handleWeakGroup(const QCString &, const QCString &)
+static bool handleWeakGroup(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
current->groupDocType = Entry::GROUPDOC_WEAK;
@@ -2355,83 +2368,83 @@ static bool handleWeakGroup(const QCString &, const QCString &)
return stop;
}
-static bool handleNamespace(const QCString &, const QCString &)
+static bool handleNamespace(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::NAMESPACEDOC_SEC);
BEGIN( NameSpaceDocArg1 );
return stop;
}
-static bool handlePackage(const QCString &, const QCString &)
+static bool handlePackage(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::PACKAGEDOC_SEC);
BEGIN( PackageDocArg1 );
return stop;
}
-static bool handleClass(const QCString &, const QCString &)
+static bool handleClass(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::CLASSDOC_SEC);
BEGIN( ClassDocArg1 );
return stop;
}
-static bool handleHeaderFile(const QCString &, const QCString &)
+static bool handleHeaderFile(const QCString &, const QCStringList &)
{
BEGIN( ClassDocArg2 );
return FALSE;
}
-static bool handleProtocol(const QCString &, const QCString &)
+static bool handleProtocol(const QCString &, const QCStringList &)
{ // Obj-C protocol
bool stop=makeStructuralIndicator(Entry::PROTOCOLDOC_SEC);
BEGIN( ClassDocArg1 );
return stop;
}
-static bool handleCategory(const QCString &, const QCString &)
+static bool handleCategory(const QCString &, const QCStringList &)
{ // Obj-C category
bool stop=makeStructuralIndicator(Entry::CATEGORYDOC_SEC);
BEGIN( CategoryDocArg1 );
return stop;
}
-static bool handleUnion(const QCString &, const QCString &)
+static bool handleUnion(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::UNIONDOC_SEC);
BEGIN( ClassDocArg1 );
return stop;
}
-static bool handleStruct(const QCString &, const QCString &)
+static bool handleStruct(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::STRUCTDOC_SEC);
BEGIN( ClassDocArg1 );
return stop;
}
-static bool handleInterface(const QCString &, const QCString &)
+static bool handleInterface(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::INTERFACEDOC_SEC);
BEGIN( ClassDocArg1 );
return stop;
}
-static bool handleIdlException(const QCString &, const QCString &)
+static bool handleIdlException(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::EXCEPTIONDOC_SEC);
BEGIN( ClassDocArg1 );
return stop;
}
-static bool handlePage(const QCString &, const QCString &)
+static bool handlePage(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::PAGEDOC_SEC);
BEGIN( PageDocArg1 );
return stop;
}
-static bool handleMainpage(const QCString &, const QCString &)
+static bool handleMainpage(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::MAINPAGEDOC_SEC);
if (!stop)
@@ -2442,7 +2455,7 @@ static bool handleMainpage(const QCString &, const QCString &)
return stop;
}
-static bool handleFile(const QCString &, const QCString &)
+static bool handleFile(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::FILEDOC_SEC);
if (!stop)
@@ -2453,7 +2466,7 @@ static bool handleFile(const QCString &, const QCString &)
return stop;
}
-static bool handleParam(const QCString &, const QCString &)
+static bool handleParam(const QCString &, const QCStringList &)
{
// we need process param and retval arguments to escape leading underscores in case of
// markdown processing, see bug775493
@@ -2462,14 +2475,14 @@ static bool handleParam(const QCString &, const QCString &)
return FALSE;
}
-static bool handleRetval(const QCString &, const QCString &)
+static bool handleRetval(const QCString &, const QCStringList &)
{
addOutput("@retval ");
BEGIN( ParamArg1 );
return FALSE;
}
-static bool handleDir(const QCString &, const QCString &)
+static bool handleDir(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::DIRDOC_SEC);
if (!stop) current->name = yyFileName;
@@ -2477,15 +2490,30 @@ static bool handleDir(const QCString &, const QCString &)
return stop;
}
-static bool handleExample(const QCString &, const QCString &)
+static bool handleExample(const QCString &cmd, const QCStringList &optList)
{
- bool stop=makeStructuralIndicator(Entry::EXAMPLE_SEC);
+ Entry::Sections section=Entry::EXAMPLE_SEC;
+ QCStringList::ConstIterator it;
+ for ( it = optList.begin(); it != optList.end(); ++it )
+ {
+ QCString opt = (*it).stripWhiteSpace().lower();
+ if (opt=="lineno")
+ {
+ section=Entry::EXAMPLE_LINENO_SEC;
+ }
+ else
+ {
+ warn(yyFileName,yyLineNr,
+ "unsupported option '%s' for command '\\%s'",qPrint(opt),qPrint(cmd));
+ }
+ }
+ bool stop=makeStructuralIndicator(section);
if (!stop) current->name = yyFileName;
BEGIN( FileDocArg1 );
return stop;
}
-static bool handleDetails(const QCString &, const QCString &)
+static bool handleDetails(const QCString &, const QCStringList &)
{
if (inContext!=OutputBrief)
{
@@ -2496,7 +2524,7 @@ static bool handleDetails(const QCString &, const QCString &)
return FALSE;
}
-static bool handleName(const QCString &, const QCString &)
+static bool handleName(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::MEMBERGRP_SEC);
if (!stop)
@@ -2511,7 +2539,7 @@ static bool handleName(const QCString &, const QCString &)
return stop;
}
-static bool handleTodo(const QCString &, const QCString &)
+static bool handleTodo(const QCString &, const QCStringList &)
{
newXRefKind = XRef_Todo;
setOutput(OutputXRef);
@@ -2519,7 +2547,7 @@ static bool handleTodo(const QCString &, const QCString &)
return FALSE;
}
-static bool handleTest(const QCString &, const QCString &)
+static bool handleTest(const QCString &, const QCStringList &)
{
newXRefKind = XRef_Test;
setOutput(OutputXRef);
@@ -2527,7 +2555,7 @@ static bool handleTest(const QCString &, const QCString &)
return FALSE;
}
-static bool handleBug(const QCString &, const QCString &)
+static bool handleBug(const QCString &, const QCStringList &)
{
newXRefKind = XRef_Bug;
setOutput(OutputXRef);
@@ -2535,7 +2563,7 @@ static bool handleBug(const QCString &, const QCString &)
return FALSE;
}
-static bool handleDeprecated(const QCString &, const QCString &)
+static bool handleDeprecated(const QCString &, const QCStringList &)
{
newXRefKind = XRef_Deprecated;
setOutput(OutputXRef);
@@ -2543,14 +2571,14 @@ static bool handleDeprecated(const QCString &, const QCString &)
return FALSE;
}
-static bool handleXRefItem(const QCString &, const QCString &)
+static bool handleXRefItem(const QCString &, const QCStringList &)
{
newXRefKind = XRef_Item;
BEGIN(XRefItemParam1);
return FALSE;
}
-static bool handleParBlock(const QCString &, const QCString &)
+static bool handleParBlock(const QCString &, const QCStringList &)
{
if (g_insideParBlock)
{
@@ -2567,7 +2595,7 @@ static bool handleParBlock(const QCString &, const QCString &)
return FALSE;
}
-static bool handleEndParBlock(const QCString &, const QCString &)
+static bool handleEndParBlock(const QCString &, const QCStringList &)
{
if (!g_insideParBlock)
{
@@ -2580,7 +2608,7 @@ static bool handleEndParBlock(const QCString &, const QCString &)
return FALSE;
}
-static bool handleRelated(const QCString &, const QCString &)
+static bool handleRelated(const QCString &, const QCStringList &)
{
if (!current->relates.isEmpty())
{
@@ -2592,7 +2620,7 @@ static bool handleRelated(const QCString &, const QCString &)
return FALSE;
}
-static bool handleRelatedAlso(const QCString &, const QCString &)
+static bool handleRelatedAlso(const QCString &, const QCStringList &)
{
if (!current->relates.isEmpty())
{
@@ -2604,7 +2632,7 @@ static bool handleRelatedAlso(const QCString &, const QCString &)
return FALSE;
}
-static bool handleMemberOf(const QCString &, const QCString &)
+static bool handleMemberOf(const QCString &, const QCStringList &)
{
if (!current->relates.isEmpty())
{
@@ -2616,14 +2644,14 @@ static bool handleMemberOf(const QCString &, const QCString &)
return FALSE;
}
-static bool handleRefItem(const QCString &, const QCString &)
+static bool handleRefItem(const QCString &, const QCStringList &)
{
addOutput("@refitem ");
BEGIN(LineParam);
return FALSE;
}
-static bool handleSection(const QCString &s, const QCString &)
+static bool handleSection(const QCString &s, const QCStringList &)
{
setOutput(OutputDoc);
addOutput("@"+s+" ");
@@ -2635,7 +2663,7 @@ static bool handleSection(const QCString &s, const QCString &)
return FALSE;
}
-static bool handleSubpage(const QCString &s, const QCString &)
+static bool handleSubpage(const QCString &s, const QCStringList &)
{
if (current->section!=Entry::EMPTY_SEC &&
current->section!=Entry::PAGEDOC_SEC &&
@@ -2655,14 +2683,14 @@ static bool handleSubpage(const QCString &s, const QCString &)
return FALSE;
}
-static bool handleAnchor(const QCString &s, const QCString &)
+static bool handleAnchor(const QCString &s, const QCStringList &)
{
addOutput("@"+s+" ");
BEGIN(AnchorLabel);
return FALSE;
}
-static bool handleCite(const QCString &s, const QCString &)
+static bool handleCite(const QCString &s, const QCStringList &)
{
if (!g_spaceBeforeCmd.isEmpty())
{
@@ -2674,9 +2702,16 @@ static bool handleCite(const QCString &s, const QCString &)
return FALSE;
}
-static bool handleFormatBlock(const QCString &s, const QCString &opt)
+static bool handleFormatBlock(const QCString &s, const QCStringList &optList)
{
- addOutput("@"+s+" "+opt);
+ if (optList.isEmpty())
+ {
+ addOutput("@"+s+" ");
+ }
+ else
+ {
+ addOutput("@"+s+"{"+optList.join(",")+"} ");
+ }
//printf("handleFormatBlock(%s) with option(%s)\n",s.data(),opt.data());
blockName=s;
g_commentCount=0;
@@ -2684,14 +2719,14 @@ static bool handleFormatBlock(const QCString &s, const QCString &opt)
return FALSE;
}
-static bool handleAddIndex(const QCString &, const QCString &)
+static bool handleAddIndex(const QCString &, const QCStringList &)
{
addOutput("@addindex ");
BEGIN(LineParam);
return FALSE;
}
-static bool handleIf(const QCString &, const QCString &)
+static bool handleIf(const QCString &, const QCStringList &)
{
enabledSectionFound=FALSE;
guardType = Guard_If;
@@ -2700,7 +2735,7 @@ static bool handleIf(const QCString &, const QCString &)
return FALSE;
}
-static bool handleIfNot(const QCString &, const QCString &)
+static bool handleIfNot(const QCString &, const QCStringList &)
{
enabledSectionFound=FALSE;
guardType = Guard_IfNot;
@@ -2709,7 +2744,7 @@ static bool handleIfNot(const QCString &, const QCString &)
return FALSE;
}
-static bool handleElseIf(const QCString &, const QCString &)
+static bool handleElseIf(const QCString &, const QCStringList &)
{
if (guards.isEmpty())
{
@@ -2724,7 +2759,7 @@ static bool handleElseIf(const QCString &, const QCString &)
return FALSE;
}
-static bool handleElse(const QCString &, const QCString &)
+static bool handleElse(const QCString &, const QCStringList &)
{
if (guards.isEmpty())
{
@@ -2738,7 +2773,7 @@ static bool handleElse(const QCString &, const QCString &)
return FALSE;
}
-static bool handleEndIf(const QCString &, const QCString &)
+static bool handleEndIf(const QCString &, const QCStringList &)
{
if (guards.isEmpty())
{
@@ -2759,56 +2794,80 @@ static bool handleEndIf(const QCString &, const QCString &)
return FALSE;
}
-static bool handleIngroup(const QCString &, const QCString &)
+static bool handleIngroup(const QCString &, const QCStringList &)
{
inGroupParamFound=FALSE;
BEGIN( InGroupParam );
return FALSE;
}
-static bool handleNoSubGrouping(const QCString &, const QCString &)
+static bool handleNoSubGrouping(const QCString &, const QCStringList &)
{
current->subGrouping = FALSE;
return FALSE;
}
-static bool handleShowInitializer(const QCString &, const QCString &)
+static bool handleShowInitializer(const QCString &, const QCStringList &)
{
current->initLines = 100000; // ON
return FALSE;
}
-static bool handleHideInitializer(const QCString &, const QCString &)
+static bool handleHideInitializer(const QCString &, const QCStringList &)
{
current->initLines = 0; // OFF
return FALSE;
}
-static bool handleCallgraph(const QCString &, const QCString &)
+static bool handleCallgraph(const QCString &, const QCStringList &)
{
current->callGraph = TRUE; // ON
return FALSE;
}
-static bool handleHideCallgraph(const QCString &, const QCString &)
+static bool handleHideCallgraph(const QCString &, const QCStringList &)
{
current->callGraph = FALSE; // OFF
return FALSE;
}
-static bool handleCallergraph(const QCString &, const QCString &)
+static bool handleCallergraph(const QCString &, const QCStringList &)
{
current->callerGraph = TRUE; // ON
return FALSE;
}
-static bool handleHideCallergraph(const QCString &, const QCString &)
+static bool handleHideCallergraph(const QCString &, const QCStringList &)
{
current->callerGraph = FALSE; // OFF
return FALSE;
}
-static bool handleInternal(const QCString &, const QCString &)
+static bool handleReferencedByRelation(const QCString &, const QCStringList &)
+{
+ current->referencedByRelation = TRUE; // ON
+ return FALSE;
+}
+
+static bool handleHideReferencedByRelation(const QCString &, const QCStringList &)
+{
+ current->referencedByRelation = FALSE; // OFF
+ return FALSE;
+}
+
+static bool handleReferencesRelation(const QCString &, const QCStringList &)
+{
+ current->referencesRelation = TRUE; // ON
+ return FALSE;
+}
+
+static bool handleHideReferencesRelation(const QCString &, const QCStringList &)
+{
+ current->referencesRelation = FALSE; // OFF
+ return FALSE;
+}
+
+static bool handleInternal(const QCString &, const QCStringList &)
{
if (!Config_getBool(INTERNAL_DOCS))
{
@@ -2830,74 +2889,71 @@ static bool handleInternal(const QCString &, const QCString &)
return FALSE;
}
-static bool handleLineBr(const QCString &, const QCString &)
+static bool handleLineBr(const QCString &, const QCStringList &)
{
addOutput('\n');
return FALSE;
}
-static bool handleStatic(const QCString &, const QCString &)
+static bool handleStatic(const QCString &, const QCStringList &)
{
endBrief();
current->stat = TRUE;
return FALSE;
}
-static bool handlePure(const QCString &, const QCString &)
+static bool handlePure(const QCString &, const QCStringList &)
{
endBrief();
current->virt = Pure;
return FALSE;
}
-static bool handlePrivate(const QCString &, const QCString &)
+static bool handlePrivate(const QCString &, const QCStringList &)
{
current->protection = Private;
return FALSE;
}
-static bool handlePrivateSection(const QCString &, const QCString &)
+static bool handlePrivateSection(const QCString &, const QCStringList &)
{
current->protection = protection = Private;
return FALSE;
}
-static bool handleProtected(const QCString &, const QCString &)
+static bool handleProtected(const QCString &, const QCStringList &)
{
current->protection = Protected;
return FALSE;
}
-static bool handleProtectedSection(const QCString &, const QCString &)
+static bool handleProtectedSection(const QCString &, const QCStringList &)
{
current->protection = protection = Protected ;
return FALSE;
}
-static bool handlePublic(const QCString &, const QCString &)
+static bool handlePublic(const QCString &, const QCStringList &)
{
current->protection = Public;
return FALSE;
}
-static bool handlePublicSection(const QCString &, const QCString &)
+static bool handlePublicSection(const QCString &, const QCStringList &)
{
current->protection = protection = Public;
return FALSE;
}
-static bool handleToc(const QCString &, const QCString &opt)
+static bool handleToc(const QCString &, const QCStringList &optList)
{
if (current->section==Entry::PAGEDOC_SEC ||
current->section==Entry::MAINPAGEDOC_SEC)
{
- QString optName = opt.stripWhiteSpace(); // to be sure
- optName = optName.left(optName.length() - 1).right(optName.length() - 2);
- QStringList optList=QStringList::split(",",optName,FALSE);
- QStringList::Iterator it;
+ QCStringList::ConstIterator it;
for ( it = optList.begin(); it != optList.end(); ++it )
{
- QString opt = (*it).stripWhiteSpace().lower();
+ QCString opt = (*it).stripWhiteSpace().lower();
char dum;
int level = 5;
int i = opt.find(':');
@@ -2929,7 +2985,14 @@ static bool handleToc(const QCString &, const QCString &opt)
{
current->localToc.enableXml(level);
}
- else warn(yyFileName,yyLineNr,"Unknown option specified with \\tableofcontents: `%s'", (*it).stripWhiteSpace().data());
+ else if (opt == "docbook")
+ {
+ current->localToc.enableDocbook(level);
+ }
+ else
+ {
+ warn(yyFileName,yyLineNr,"Unknown option specified with \\tableofcontents: `%s'", (*it).stripWhiteSpace().data());
+ }
}
}
if (current->localToc.nothingEnabled())
@@ -2940,19 +3003,19 @@ static bool handleToc(const QCString &, const QCString &opt)
return FALSE;
}
-static bool handleInherit(const QCString &, const QCString &)
+static bool handleInherit(const QCString &, const QCStringList &)
{
BEGIN(InheritParam);
return FALSE;
}
-static bool handleExtends(const QCString &, const QCString &)
+static bool handleExtends(const QCString &, const QCStringList &)
{
BEGIN(ExtendsParam);
return FALSE;
}
-static bool handleCopyBrief(const QCString &, const QCString &)
+static bool handleCopyBrief(const QCString &, const QCStringList &)
{
if (current->brief.isEmpty() && current->doc.isEmpty())
{ // if we don't have a brief or detailed description yet,
@@ -2969,7 +3032,7 @@ static bool handleCopyBrief(const QCString &, const QCString &)
return FALSE;
}
-static bool handleCopyDetails(const QCString &, const QCString &)
+static bool handleCopyDetails(const QCString &, const QCStringList &)
{
setOutput(OutputDoc);
if (!g_spaceBeforeCmd.isEmpty())
@@ -2981,7 +3044,7 @@ static bool handleCopyDetails(const QCString &, const QCString &)
return FALSE;
}
-static bool handleCopyDoc(const QCString &, const QCString &)
+static bool handleCopyDoc(const QCString &, const QCStringList &)
{
setOutput(OutputBrief);
if (!g_spaceBeforeCmd.isEmpty())
diff --git a/src/config.h b/src/config.h
index e86e950..102774e 100644
--- a/src/config.h
+++ b/src/config.h
@@ -51,6 +51,11 @@ namespace Config
*/
void writeTemplate(FTextStream &t,bool shortList,bool updateOnly=FALSE);
+ /*! Writes a the differences between the current configuration and the
+ * template configuration to stream \a t.
+ */
+ void compareDoxyfile(FTextStream &t);
+
/*! Parses a configuration file with name \a fn.
* \returns TRUE if successful, FALSE if the file could not be
* opened or read.
@@ -61,7 +66,7 @@ namespace Config
* and replaces environment variables.
* \param clearHeaderAndFooter set to TRUE when writing header and footer templates.
*/
- void postProcess(bool clearHeaderAndFooter);
+ void postProcess(bool clearHeaderAndFooter, bool compare = FALSE);
/*! Check the validity of the parsed options and correct or warn the user where needed. */
void checkAndCorrect();
diff --git a/src/config.xml b/src/config.xml
index 2e0f430..98ce23f 100644
--- a/src/config.xml
+++ b/src/config.xml
@@ -110,7 +110,7 @@ SEARCHENGINE = NO
\endverbatim
To generate the documentation for the
-<a href="http://www.stack.nl/~dimitri/qdbttabular/index.html">QdbtTabular</a> package
+<a href="https://sourceforge.net/projects/qdbttabular/">QdbtTabular</a> package
I have used the following configuration file:
\verbatim
PROJECT_NAME = QdbtTabular
@@ -551,6 +551,30 @@ Go to the <a href="commands.html">next</a> section or return to the
a physical newline was in the original file.
]]>
</docs>
+ <docs doxyfile='0' documentation='0'>
+<![CDATA[
+ When you need a literal `{` or `}` or `,` in the value part of an alias you have to
+ escape them by means of a backslash, this can lead to conflicts with the
+ commands \c \\{ and \c \\} for these it is advised to use the version \c @{ and \c @} or
+ use a double escape (\c \\\\{ and \c \\\\})
+]]>
+ </docs>
+ <docs doxywizard='0' documentation='0'>
+<![CDATA[
+ When you need a literal `{` or `}` or `,` in the value part of an alias you have to
+ escape them by means of a backslash (\c \\), this can lead to conflicts with the
+ commands \c \\{ and \c \\} for these it is advised to use the version \c @{ and \c @} or
+ use a double escape (\c \\\\{ and \c \\\\})
+]]>
+ </docs>
+ <docs doxyfile='0' doxywizard='0'>
+<![CDATA[
+ When you need a literal `{` or `}` or `,` in the value part of an alias you have to
+ escape them by means of a backslash (`\`), this can lead to conflicts with the
+ commands \c \\{ and \c \\} for these it is advised to use the version \c @@{ and \c @@} or
+ use a double escape (\c \\\\{ and \c \\\\})
+]]>
+ </docs>
</option>
<option type='list' id='TCL_SUBST' format='string'>
<docs>
@@ -626,7 +650,7 @@ Go to the <a href="commands.html">next</a> section or return to the
<![CDATA[
If the \c MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all
comments according to the Markdown format, which allows for more readable
- documentation. See http://daringfireball.net/projects/markdown/ for details.
+ documentation. See https://daringfireball.net/projects/markdown/ for details.
The output of markdown processing is further processed by doxygen, so you
can mix doxygen, HTML, and XML commands with Markdown formatting.
Disable only in case of backward compatibilities issues.
@@ -2015,15 +2039,15 @@ hr.footer {
<![CDATA[
If the \c GENERATE_DOCSET tag is set to \c YES, additional index files
will be generated that can be used as input for
- <a href="https://developer.apple.com/tools/xcode/">Apple's Xcode 3
+ <a href="https://developer.apple.com/xcode/">Apple's Xcode 3
integrated development environment</a>, introduced with OSX 10.5 (Leopard).
To create a documentation set, doxygen will generate a Makefile in the
HTML output directory. Running \c make will produce the docset in that
directory and running <code>make install</code> will install the docset in
<code>~/Library/Developer/Shared/Documentation/DocSets</code>
so that Xcode will find it at startup. See
- https://developer.apple.com/tools/creatingdocsetswithdoxygen.html for
- more information.
+ https://developer.apple.com/library/archive/featuredarticles/DoxygenXcode/_index.html
+ for more information.
]]>
</docs>
</option>
@@ -2071,7 +2095,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
doxygen generates three additional HTML index files:
\c index.hhp, \c index.hhc, and \c index.hhk. The \c index.hhp is a
project file that can be read by
- <a href="http://www.microsoft.com/en-us/download/details.aspx?id=21138">
+ <a href="https://www.microsoft.com/en-us/download/details.aspx?id=21138">
Microsoft's HTML Help Workshop</a>
on Windows.
<br>
@@ -2167,7 +2191,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
<![CDATA[
The \c QHP_NAMESPACE tag specifies the namespace to use when generating
Qt Help Project output. For more information please see
- <a href="http://doc.qt.io/qt-4.8/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
+ <a href="http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace">Qt Help Project / Namespace</a>.
]]>
</docs>
</option>
@@ -2176,7 +2200,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
<![CDATA[
The \c QHP_VIRTUAL_FOLDER tag specifies the namespace to use when
generating Qt Help Project output. For more information please see
- <a href="http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
+ <a href="http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders">Qt Help Project / Virtual Folders</a>.
]]>
</docs>
</option>
@@ -2184,7 +2208,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
<docs>
<![CDATA[
If the \c QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom filter to add. For more information please see
- <a href="http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+ <a href="http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
]]>
</docs>
</option>
@@ -2193,7 +2217,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
<![CDATA[
The \c QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the custom filter to add.
For more information please see
- <a href="http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+ <a href="http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
]]>
</docs>
</option>
@@ -2201,7 +2225,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
<docs>
<![CDATA[
The \c QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's filter section matches.
- <a href="http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+ <a href="http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
]]>
</docs>
</option>
@@ -2351,7 +2375,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
<value name="NativeMML" desc="(i.e. MathML)"/>
<value name="SVG"/>
</option>
- <option type='string' id='MATHJAX_RELPATH' format='string' defval='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/' depends='USE_MATHJAX'>
+ <option type='string' id='MATHJAX_RELPATH' format='string' defval='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/' depends='USE_MATHJAX'>
<docs>
<![CDATA[
When MathJax is enabled you need to specify the location relative to the
@@ -2745,6 +2769,16 @@ or
]]>
</docs>
</option>
+ <option type='string' id='LATEX_EMOJI_DIRECTORY' format='dir' defval='' depends='GENERATE_LATEX'>
+ <docs>
+<![CDATA[
+ The \c LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+ path from which the emoji images will be read.
+ If a relative path is entered, it will be relative to the \ref cfg_latex_output "LATEX_OUTPUT"
+ directory. If left blank the \ref cfg_latex_output "LATEX_OUTPUT" directory will be used.
+]]>
+ </docs>
+ </option>
</group>
<group name='RTF' docs='Configuration options related to the RTF output'>
<option type='bool' id='GENERATE_RTF' defval='0'>
diff --git a/src/configimpl.h b/src/configimpl.h
index c901198..1594d47 100644
--- a/src/configimpl.h
+++ b/src/configimpl.h
@@ -73,7 +73,9 @@ class ConfigOption
protected:
virtual void writeTemplate(FTextStream &t,bool sl,bool upd) = 0;
+ virtual void compareDoxyfile(FTextStream &t) = 0;
virtual void convertStrToVal() {}
+ virtual void emptyValueToDefault() {}
virtual void substEnvVars() = 0;
virtual void init() {}
@@ -103,6 +105,7 @@ class ConfigInfo : public ConfigOption
m_doc = doc;
}
void writeTemplate(FTextStream &t, bool sl,bool);
+ void compareDoxyfile(FTextStream &){};
void substEnvVars() {}
};
@@ -124,6 +127,7 @@ class ConfigList : public ConfigOption
WidgetType widgetType() const { return m_widgetType; }
QStrList *valueRef() { return &m_value; }
void writeTemplate(FTextStream &t,bool sl,bool);
+ void compareDoxyfile(FTextStream &t);
void substEnvVars();
void init() { m_value = m_defaultValue; }
private:
@@ -153,6 +157,7 @@ class ConfigEnum : public ConfigOption
QCString *valueRef() { return &m_value; }
void substEnvVars();
void writeTemplate(FTextStream &t,bool sl,bool);
+ void compareDoxyfile(FTextStream &t);
void init() { m_value = m_defValue.copy(); }
private:
@@ -182,8 +187,10 @@ class ConfigString : public ConfigOption
void setDefaultValue(const char *v) { m_defValue = v; }
QCString *valueRef() { return &m_value; }
void writeTemplate(FTextStream &t,bool sl,bool);
+ void compareDoxyfile(FTextStream &t);
void substEnvVars();
void init() { m_value = m_defValue.copy(); }
+ void emptyValueToDefault() { if(m_value.isEmpty()) m_value=m_defValue; };
private:
QCString m_value;
@@ -213,6 +220,7 @@ class ConfigInt : public ConfigOption
void convertStrToVal();
void substEnvVars();
void writeTemplate(FTextStream &t,bool sl,bool upd);
+ void compareDoxyfile(FTextStream &t);
void init() { m_value = m_defValue; }
private:
int m_value;
@@ -241,6 +249,7 @@ class ConfigBool : public ConfigOption
void substEnvVars();
void setValueString(const QCString &v) { m_valueString = v; }
void writeTemplate(FTextStream &t,bool sl,bool upd);
+ void compareDoxyfile(FTextStream &t);
void init() { m_value = m_defValue; }
private:
bool m_value;
@@ -256,6 +265,7 @@ class ConfigObsolete : public ConfigOption
ConfigObsolete(const char *name) : ConfigOption(O_Obsolete)
{ m_name = name; }
void writeTemplate(FTextStream &,bool,bool);
+ void compareDoxyfile(FTextStream &) {}
void substEnvVars() {}
};
@@ -267,6 +277,7 @@ class ConfigDisabled : public ConfigOption
ConfigDisabled(const char *name) : ConfigOption(O_Disabled)
{ m_name = name; }
void writeTemplate(FTextStream &,bool,bool);
+ void compareDoxyfile(FTextStream &) {}
void substEnvVars() {}
};
@@ -466,6 +477,11 @@ class ConfigImpl
*/
void writeTemplate(FTextStream &t,bool shortIndex,bool updateOnly);
+ /*! Writes a the differences between the current configuration and the
+ * template configuration to stream \a t.
+ */
+ void compareDoxyfile(FTextStream &t);
+
void setHeader(const char *header) { m_header = header; }
/////////////////////////////
@@ -477,6 +493,10 @@ class ConfigImpl
*/
void convertStrToVal();
+ /*! Sets default value in case value is empty
+ */
+ void emptyValueToDefault();
+
/*! Replaces references to environment variable by the actual value
* of the environment variable.
*/
diff --git a/src/configimpl.l b/src/configimpl.l
index df032a6..ed5b052 100644
--- a/src/configimpl.l
+++ b/src/configimpl.l
@@ -315,6 +315,77 @@ void ConfigList::writeTemplate(FTextStream &t,bool sl,bool)
t << "\n";
}
+void ConfigList::compareDoxyfile(FTextStream &t)
+{
+ const char *p = m_value.first();
+ const char *q = m_defaultValue.first();
+ int defCnt = 0;
+ int valCnt = 0;
+
+ // count non empty elements
+ while (p)
+ {
+ QCString s=p;
+ if (!s.stripWhiteSpace().isEmpty()) valCnt += 1;
+ p = m_value.next();
+ }
+
+ while (q)
+ {
+ QCString s=q;
+ if (!s.stripWhiteSpace().isEmpty()) defCnt += 1;
+ q = m_defaultValue.next();
+ }
+ if ( valCnt != defCnt)
+ {
+ writeTemplate(t,TRUE,TRUE);
+ return;
+ }
+
+ // get first non empry element
+ q = m_defaultValue.first();
+ p = m_value.first();
+ QCString sp = p;
+ while (p && sp.stripWhiteSpace().isEmpty())
+ {
+ p = m_value.next();
+ sp = p;
+ }
+ QCString sq = q;
+ while (q && sq.stripWhiteSpace().isEmpty())
+ {
+ q = m_value.next();
+ sq = q;
+ }
+ while (p)
+ {
+ // skip empty elements
+ sp = p;
+ while (p && sp.stripWhiteSpace().isEmpty())
+ {
+ p = m_value.next();
+ sp = p;
+ }
+ sq = q;
+ while (q && sq.stripWhiteSpace().isEmpty())
+ {
+ q = m_value.next();
+ sq = q;
+ }
+ // be sure we have still an element (p and q have same number of 'filled' elements)
+ if (p)
+ {
+ if (sp.stripWhiteSpace() != sq.stripWhiteSpace())
+ {
+ writeTemplate(t,TRUE,TRUE);
+ return;
+ }
+ p = m_value.next();
+ q = m_defaultValue.next();
+ }
+ }
+}
+
void ConfigEnum::writeTemplate(FTextStream &t,bool sl,bool)
{
if (!sl)
@@ -332,6 +403,11 @@ void ConfigEnum::writeTemplate(FTextStream &t,bool sl,bool)
t << "\n";
}
+void ConfigEnum::compareDoxyfile(FTextStream &t)
+{
+ if (m_value != m_defValue) writeTemplate(t,TRUE,TRUE);
+}
+
void ConfigString::writeTemplate(FTextStream &t,bool sl,bool)
{
if (!sl)
@@ -349,6 +425,11 @@ void ConfigString::writeTemplate(FTextStream &t,bool sl,bool)
t << "\n";
}
+void ConfigString::compareDoxyfile(FTextStream &t)
+{
+ if (m_value.stripWhiteSpace() != m_defValue.stripWhiteSpace()) writeTemplate(t,TRUE,TRUE);
+}
+
void ConfigInt::writeTemplate(FTextStream &t,bool sl,bool upd)
{
if (!sl)
@@ -373,6 +454,11 @@ void ConfigInt::writeTemplate(FTextStream &t,bool sl,bool upd)
t << "\n";
}
+void ConfigInt::compareDoxyfile(FTextStream &t)
+{
+ if (m_value != m_defValue) writeTemplate(t,TRUE,TRUE);
+}
+
void ConfigBool::writeTemplate(FTextStream &t,bool sl,bool upd)
{
if (!sl)
@@ -397,6 +483,11 @@ void ConfigBool::writeTemplate(FTextStream &t,bool sl,bool upd)
t << "\n";
}
+void ConfigBool::compareDoxyfile(FTextStream &t)
+{
+ if (m_value != m_defValue) writeTemplate(t,TRUE,TRUE);
+}
+
void ConfigObsolete::writeTemplate(FTextStream &,bool,bool) {}
void ConfigDisabled::writeTemplate(FTextStream &,bool,bool) {}
@@ -777,7 +868,7 @@ static void readIncludeFile(const char *incName)
}
BEGIN(Start);
}
-<GetStrList>[ \t]+ {
+<GetStrList>[ \t,]+ {
if (!elemStr.isEmpty())
{
//printf("elemStr2=`%s'\n",elemStr.data());
@@ -831,7 +922,7 @@ static void readIncludeFile(const char *incName)
bs.data(),yyLineNr,yyFileName.data());
}
}
-<GetStrList>[^ \#\"\t\r\n]+ {
+<GetStrList>[^ \#\"\t\r\n,]+ {
elemStr+=configStringRecode(yytext,encoding,"UTF-8");
}
<SkipComment>\n { yyLineNr++; BEGIN(Start); }
@@ -871,6 +962,18 @@ void ConfigImpl::writeTemplate(FTextStream &t,bool sl,bool upd)
}
}
+void ConfigImpl::compareDoxyfile(FTextStream &t)
+{
+ t << "# Difference with default Doxyfile " << versionString << endl;
+ QListIterator<ConfigOption> it = iterator();
+ ConfigOption *option;
+ for (;(option=it.current());++it)
+ {
+ option->m_userComment = "";
+ option->compareDoxyfile(t);
+ }
+}
+
void ConfigImpl::convertStrToVal()
{
QListIterator<ConfigOption> it = iterator();
@@ -880,6 +983,15 @@ void ConfigImpl::convertStrToVal()
option->convertStrToVal();
}
}
+void ConfigImpl::emptyValueToDefault()
+{
+ QListIterator<ConfigOption> it = iterator();
+ ConfigOption *option;
+ for (;(option=it.current());++it)
+ {
+ option->emptyValueToDefault();
+ }
+}
static void substEnvVarsInString(QCString &s)
{
@@ -1749,14 +1861,21 @@ void Config::writeTemplate(FTextStream &t,bool shortList,bool update)
ConfigImpl::instance()->writeTemplate(t,shortList,update);
}
+void Config::compareDoxyfile(FTextStream &t)
+{
+ postProcess(FALSE, TRUE);
+ ConfigImpl::instance()->compareDoxyfile(t);
+}
+
bool Config::parse(const char *fileName,bool update)
{
return ConfigImpl::instance()->parse(fileName,update);
}
-void Config::postProcess(bool clearHeaderAndFooter)
+void Config::postProcess(bool clearHeaderAndFooter, bool compare)
{
ConfigImpl::instance()->substituteEnvironmentVars();
+ if (!compare)ConfigImpl::instance()->emptyValueToDefault();
ConfigImpl::instance()->convertStrToVal();
// avoid bootstrapping issues when the config file already
diff --git a/src/context.cpp b/src/context.cpp
index c9a6bb3..12c8c34 100644
--- a/src/context.cpp
+++ b/src/context.cpp
@@ -856,6 +856,14 @@ class TranslateContext::Private
{
return theTranslator->trCallerGraph();
}
+ TemplateVariant referencedByRelation() const
+ {
+ return theTranslator->trReferencedBy();
+ }
+ TemplateVariant referencesRelation() const
+ {
+ return theTranslator->trReferences();
+ }
TemplateVariant inheritedFrom() const
{
return theTranslator->trInheritedFrom("@0","@1");
@@ -1112,6 +1120,10 @@ class TranslateContext::Private
s_inst.addProperty("callGraph", &Private::callGraph);
//%% string callerGraph
s_inst.addProperty("callerGraph", &Private::callerGraph);
+ //%% string referencedByRelation
+ s_inst.addProperty("referencedByRelation", &Private::referencedByRelation);
+ //%% string referencesRelation
+ s_inst.addProperty("referencesRelation", &Private::referencesRelation);
//%% markerstring inheritedFrom
s_inst.addProperty("inheritedFrom", &Private::inheritedFrom);
//%% string addtionalInheritedMembers
@@ -3994,6 +4006,10 @@ class MemberContext::Private : public DefinitionContext<MemberContext::Private>
s_inst.addProperty("callGraph", &Private::callGraph);
s_inst.addProperty("hasCallerGraph", &Private::hasCallerGraph);
s_inst.addProperty("callerGraph", &Private::callerGraph);
+ s_inst.addProperty("hasReferencedByRelation", &Private::hasReferencedByRelation);
+ s_inst.addProperty("referencedByRelation", &Private::referencedByRelation);
+ s_inst.addProperty("hasReferencesRelation", &Private::hasReferencesRelation);
+ s_inst.addProperty("referencesRelation", &Private::referencesRelation);
s_inst.addProperty("fieldType", &Private::fieldType);
s_inst.addProperty("type", &Private::type);
s_inst.addProperty("detailsVisibleFor", &Private::detailsVisibleFor);
@@ -4918,6 +4934,10 @@ class MemberContext::Private : public DefinitionContext<MemberContext::Private>
}
return TemplateVariant(FALSE);
}
+ TemplateVariant hasReferencedByRelation() const
+ {
+ return TemplateVariant(m_memberDef->hasReferencedByRelation());
+ }
TemplateVariant callGraph() const
{
if (hasCallGraph().toBool())
@@ -4958,6 +4978,14 @@ class MemberContext::Private : public DefinitionContext<MemberContext::Private>
return TemplateVariant("");
}
}
+ TemplateVariant referencedByRelation() const
+ {
+ if (hasReferencedByRelation().toBool())
+ {
+ err("context.cpp: output format not yet supported");
+ }
+ return TemplateVariant("");
+ }
DotCallGraph *getCallerGraph() const
{
Cachable &cache = getCache();
@@ -4978,6 +5006,10 @@ class MemberContext::Private : public DefinitionContext<MemberContext::Private>
}
return TemplateVariant(FALSE);
}
+ TemplateVariant hasReferencesRelation() const
+ {
+ return TemplateVariant(m_memberDef->hasReferencesRelation());
+ }
TemplateVariant callerGraph() const
{
if (hasCallerGraph().toBool())
@@ -5018,6 +5050,14 @@ class MemberContext::Private : public DefinitionContext<MemberContext::Private>
return TemplateVariant("");
}
}
+ TemplateVariant referencesRelation() const
+ {
+ if (hasReferencesRelation().toBool())
+ {
+ err("context.cpp: output format not yet supported");
+ }
+ return TemplateVariant("");
+ }
TemplateVariant type() const
{
return m_memberDef->typeString();
@@ -6978,7 +7018,8 @@ class NamespaceTreeContext::Private
SharedPtr<NestingContext> m_namespaceTree;
struct Cachable
{
- Cachable() : maxDepthComputed(FALSE), preferredDepthComputed(FALSE) {}
+ Cachable() : maxDepth(0), maxDepthComputed(FALSE),
+ preferredDepth(0), preferredDepthComputed(FALSE) {}
int maxDepth;
bool maxDepthComputed;
int preferredDepth;
@@ -7352,7 +7393,8 @@ class PageTreeContext::Private
SharedPtr<NestingContext> m_pageTree;
struct Cachable
{
- Cachable() : maxDepthComputed(FALSE), preferredDepthComputed(FALSE) {}
+ Cachable() : maxDepth(0), maxDepthComputed(FALSE),
+ preferredDepth(0), preferredDepthComputed(FALSE) {}
int maxDepth;
bool maxDepthComputed;
int preferredDepth;
@@ -7604,7 +7646,8 @@ class ModuleTreeContext::Private
SharedPtr<NestingContext> m_moduleTree;
struct Cachable
{
- Cachable() : maxDepthComputed(FALSE), preferredDepthComputed(FALSE) {}
+ Cachable() : maxDepth(0), maxDepthComputed(FALSE),
+ preferredDepth(0), preferredDepthComputed(FALSE) {}
int maxDepth;
bool maxDepthComputed;
int preferredDepth;
@@ -7807,7 +7850,8 @@ class ExampleTreeContext::Private
SharedPtr<NestingContext> m_exampleTree;
struct Cachable
{
- Cachable() : maxDepthComputed(FALSE), preferredDepthComputed(FALSE) {}
+ Cachable() : maxDepth(0), maxDepthComputed(FALSE),
+ preferredDepth(0), preferredDepthComputed(FALSE) {}
int maxDepth;
bool maxDepthComputed;
int preferredDepth;
diff --git a/src/defargs.l b/src/defargs.l
index 7f1e1bb..52052fa 100644
--- a/src/defargs.l
+++ b/src/defargs.l
@@ -52,6 +52,7 @@
#include <assert.h>
#include <ctype.h>
#include <qregexp.h>
+#include <qcstringlist.h>
#include "defargs.h"
#include "entry.h"
@@ -102,6 +103,19 @@ static int yyread(char *buf,int max_size)
return c;
}
+/* bug_520975 */
+static bool checkSpecialType(QCString &typ, QCString &nam)
+{
+ if (nam == "unsigned" || nam == "signed" ||
+ nam == "volatile" || nam == "const") return TRUE;
+ QCStringList qsl=QCStringList::split(' ',typ);
+ for (uint j=0;j<qsl.count();j++)
+ {
+ if (!(qsl[j] == "unsigned" || qsl[j] == "signed" ||
+ qsl[j] == "volatile" || qsl[j] == "const")) return FALSE;
+ }
+ return TRUE;
+}
%}
B [ \t]
@@ -384,8 +398,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
a->type.mid(sv)=="union" ||
a->type.mid(sv)=="class" ||
a->type.mid(sv)=="typename" ||
- a->type=="const" ||
- a->type=="volatile"
+ checkSpecialType(a->type, a->name)
)
{
a->type = a->type + " " + a->name;
diff --git a/src/defgen.cpp b/src/defgen.cpp
index cd69ab2..3ab311c 100644
--- a/src/defgen.cpp
+++ b/src/defgen.cpp
@@ -146,7 +146,7 @@ void generateDEFForMember(MemberDef *md,
stringToArgumentList(md->argsString(),declAl);
QCString fcnPrefix = " " + memPrefix + "param-";
- if (declAl->count()>0)
+ if (defAl && declAl->count()>0)
{
ArgumentListIterator declAli(*declAl);
ArgumentListIterator defAli(*defAl);
diff --git a/src/definition.cpp b/src/definition.cpp
index cbfad94..936565d 100644
--- a/src/definition.cpp
+++ b/src/definition.cpp
@@ -42,6 +42,7 @@
#include "filedef.h"
#include "dirdef.h"
#include "pagedef.h"
+#include "bufstr.h"
#define START_MARKER 0x4445465B // DEF[
#define END_MARKER 0x4445465D // DEF]
@@ -304,6 +305,7 @@ Definition::Definition(const Definition &d) : DefinitionIntf(), m_cookie(0)
{
m_name = d.m_name;
m_defLine = d.m_defLine;
+ m_defColumn = d.m_defColumn;
m_impl = new DefinitionImpl;
*m_impl = *d.m_impl;
m_impl->sectionDict = 0;
@@ -715,6 +717,139 @@ void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int
_setInbodyDocumentation(d,inbodyFile,inbodyLine);
}
+//---------------------------------------
+
+struct FilterCacheItem
+{
+ portable_off_t filePos;
+ uint fileSize;
+};
+
+/*! Cache for storing the result of filtering a file */
+class FilterCache
+{
+ public:
+ FilterCache() : m_endPos(0) { m_cache.setAutoDelete(TRUE); }
+ bool getFileContents(const QCString &fileName,BufStr &str)
+ {
+ static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
+ QCString filter = getFileFilter(fileName,TRUE);
+ bool usePipe = !filter.isEmpty() && filterSourceFiles;
+ FILE *f=0;
+ const int blockSize = 4096;
+ char buf[blockSize];
+ FilterCacheItem *item=0;
+ if (usePipe && (item = m_cache.find(fileName))) // cache hit: reuse stored result
+ {
+ //printf("getFileContents(%s): cache hit\n",qPrint(fileName));
+ // file already processed, get the results after filtering from the tmp file
+ Debug::print(Debug::FilterOutput,0,"Reusing filter result for %s from %s at offset=%d size=%d\n",
+ qPrint(fileName),qPrint(Doxygen::filterDBFileName),(int)item->filePos,(int)item->fileSize);
+ f = portable_fopen(Doxygen::filterDBFileName,"rb");
+ if (f)
+ {
+ bool success=TRUE;
+ str.resize(item->fileSize+1);
+ if (portable_fseek(f,item->filePos,SEEK_SET)==-1)
+ {
+ err("Failed to seek to position %d in filter database file %s\n",(int)item->filePos,qPrint(Doxygen::filterDBFileName));
+ success=FALSE;
+ }
+ if (success)
+ {
+ int numBytes = fread(str.data(),1,item->fileSize,f);
+ if (numBytes!=item->fileSize)
+ {
+ err("Failed to read %d bytes from position %d in filter database file %s: got %d bytes\n",
+ (int)item->fileSize,(int)item->filePos,qPrint(Doxygen::filterDBFileName),numBytes);
+ success=FALSE;
+ }
+ }
+ str.addChar('\0');
+ fclose(f);
+ return success;
+ }
+ else
+ {
+ err("Failed to open filter database file %s\n",qPrint(Doxygen::filterDBFileName));
+ return FALSE;
+ }
+ }
+ else if (usePipe) // cache miss: filter active but file not previously processed
+ {
+ //printf("getFileContents(%s): cache miss\n",qPrint(fileName));
+ // filter file
+ QCString cmd=filter+" \""+fileName+"\"";
+ Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",qPrint(cmd));
+ f = portable_popen(cmd,"r");
+ FILE *bf = portable_fopen(Doxygen::filterDBFileName,"a+b");
+ FilterCacheItem *item = new FilterCacheItem;
+ item->filePos = m_endPos;
+ if (bf==0)
+ {
+ // handle error
+ err("Error opening filter database file %s\n",qPrint(Doxygen::filterDBFileName));
+ str.addChar('\0');
+ delete item;
+ portable_pclose(f);
+ return FALSE;
+ }
+ // append the filtered output to the database file
+ int size=0;
+ while (!feof(f))
+ {
+ int bytesRead = fread(buf,1,blockSize,f);
+ int bytesWritten = fwrite(buf,1,bytesRead,bf);
+ if (bytesRead!=bytesWritten)
+ {
+ // handle error
+ err("Failed to write to filter database %s. Wrote %d out of %d bytes\n",
+ qPrint(Doxygen::filterDBFileName),bytesWritten,bytesRead);
+ str.addChar('\0');
+ delete item;
+ portable_pclose(f);
+ fclose(bf);
+ return FALSE;
+ }
+ size+=bytesWritten;
+ str.addArray(buf,bytesWritten);
+ }
+ str.addChar('\0');
+ item->fileSize = size;
+ // add location entry to the dictionary
+ m_cache.append(fileName,item);
+ Debug::print(Debug::FilterOutput,0,"Storing new filter result for %s in %s at offset=%d size=%d\n",
+ qPrint(fileName),qPrint(Doxygen::filterDBFileName),(int)item->filePos,(int)item->fileSize);
+ // update end of file position
+ m_endPos += size;
+ portable_pclose(f);
+ fclose(bf);
+ }
+ else // no filtering
+ {
+ // normal file
+ //printf("getFileContents(%s): no filter\n",qPrint(fileName));
+ f = portable_fopen(fileName,"r");
+ while (!feof(f))
+ {
+ int bytesRead = fread(buf,1,blockSize,f);
+ str.addArray(buf,bytesRead);
+ }
+ str.addChar('\0');
+ fclose(f);
+ }
+ return TRUE;
+ }
+ private:
+ SDict<FilterCacheItem> m_cache;
+ portable_off_t m_endPos;
+};
+
+static FilterCache g_filterCache;
+
+//-----------------------------------------
+
+
/*! Reads a fragment of code from file \a fileName starting at
* line \a startLine and ending at line \a endLine (inclusive). The fragment is
* stored in \a result. If FALSE is returned the code fragment could not be
@@ -729,67 +864,60 @@ void Definition::setInbodyDocumentation(const char *d,const char *inbodyFile,int
bool readCodeFragment(const char *fileName,
int &startLine,int &endLine,QCString &result)
{
+ //printf("readCodeFragment(%s,startLine=%d,endLine=%d)\n",fileName,startLine,endLine);
static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
- static int tabSize = Config_getInt(TAB_SIZE);
- //printf("readCodeFragment(%s,%d,%d)\n",fileName,startLine,endLine);
- if (fileName==0 || fileName[0]==0) return FALSE; // not a valid file name
QCString filter = getFileFilter(fileName,TRUE);
- FILE *f=0;
bool usePipe = !filter.isEmpty() && filterSourceFiles;
+ int tabSize = Config_getInt(TAB_SIZE);
SrcLangExt lang = getLanguageFromFileName(fileName);
- if (!usePipe) // no filter given or wanted
- {
- f = portable_fopen(fileName,"r");
- }
- else // use filter
- {
- QCString cmd=filter+" \""+fileName+"\"";
- Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",qPrint(cmd));
- f = portable_popen(cmd,"r");
- }
- bool found = lang==SrcLangExt_VHDL ||
- lang==SrcLangExt_Tcl ||
- lang==SrcLangExt_Python ||
- lang==SrcLangExt_Fortran;
+ const int blockSize = 4096;
+ BufStr str(blockSize);
+ g_filterCache.getFileContents(fileName,str);
+
+ bool found = lang==SrcLangExt_VHDL ||
+ lang==SrcLangExt_Tcl ||
+ lang==SrcLangExt_Python ||
+ lang==SrcLangExt_Fortran;
// for VHDL, TCL, Python, and Fortran no bracket search is possible
- if (f)
+ char *p=str.data();
+ if (p)
{
int c=0;
int col=0;
int lineNr=1;
// skip until the startLine has reached
- while (lineNr<startLine && !feof(f))
+ while (lineNr<startLine && *p)
{
- while ((c=fgetc(f))!='\n' && c!=EOF) /* skip */;
- lineNr++;
+ while ((c=*p++)!='\n' && c!=0) /* skip */;
+ lineNr++;
if (found && c == '\n') c = '\0';
}
- if (!feof(f))
+ if (*p)
{
// skip until the opening bracket or lonely : is found
char cn=0;
- while (lineNr<=endLine && !feof(f) && !found)
+ while (lineNr<=endLine && *p && !found)
{
int pc=0;
- while ((c=fgetc(f))!='{' && c!=':' && c!=EOF) // } so vi matching brackets has no problem
+ while ((c=*p++)!='{' && c!=':' && c!=0)
{
//printf("parsing char `%c'\n",c);
- if (c=='\n')
+ if (c=='\n')
{
- lineNr++,col=0;
+ lineNr++,col=0;
}
- else if (c=='\t')
+ else if (c=='\t')
{
col+=tabSize - (col%tabSize);
}
else if (pc=='/' && c=='/') // skip single line comment
{
- while ((c=fgetc(f))!='\n' && c!=EOF) pc=c;
+ while ((c=*p++)!='\n' && c!=0) pc=c;
if (c=='\n') lineNr++,col=0;
}
else if (pc=='/' && c=='*') // skip C style comment
{
- while (((c=fgetc(f))!='/' || pc!='*') && c!=EOF)
+ while (((c=*p++)!='/' || pc!='*') && c!=0)
{
if (c=='\n') lineNr++,col=0;
pc=c;
@@ -803,16 +931,16 @@ bool readCodeFragment(const char *fileName,
}
if (c==':')
{
- cn=fgetc(f);
+ cn=*p++;
if (cn!=':') found=TRUE;
}
- else if (c=='{') // } so vi matching brackets has no problem
+ else if (c=='{')
{
found=TRUE;
}
}
//printf(" -> readCodeFragment(%s,%d,%d) lineNr=%d\n",fileName,startLine,endLine,lineNr);
- if (found)
+ if (found)
{
// For code with more than one line,
// fill the line with spaces until we are at the right column
@@ -826,57 +954,47 @@ bool readCodeFragment(const char *fileName,
// copy until end of line
if (c) result+=c;
startLine=lineNr;
- if (c==':')
+ if (c==':')
{
result+=cn;
if (cn=='\n') lineNr++;
}
- const int maxLineLength=4096;
- char lineStr[maxLineLength];
- do
+ char lineStr[blockSize];
+ do
{
//printf("reading line %d in range %d-%d\n",lineNr,startLine,endLine);
int size_read;
- do
+ do
{
// read up to maxLineLength-1 bytes, the last byte being zero
- char *p = fgets(lineStr, maxLineLength,f);
- //printf(" read %s",p);
- if (p)
- {
- size_read=qstrlen(p);
- }
- else // nothing read
+ int i=0;
+ while ((c=*p++) && i<blockSize-1)
{
- size_read=-1;
- lineStr[0]='\0';
+ lineStr[i++]=c;
+ if (c=='\n') break; // stop at end of the line
}
- result+=lineStr;
- } while (size_read == (maxLineLength-1));
-
- lineNr++;
- } while (lineNr<=endLine && !feof(f));
+ lineStr[i]=0;
+ size_read=i;
+ result+=lineStr; // append line to the output
+ } while (size_read == (blockSize-1)); // append more if line does not fit in buffer
+ lineNr++;
+ } while (lineNr<=endLine && *p);
// strip stuff after closing bracket
int newLineIndex = result.findRev('\n');
int braceIndex = result.findRev('}');
- if (braceIndex > newLineIndex)
+ if (braceIndex > newLineIndex)
{
result.truncate(braceIndex+1);
}
endLine=lineNr-1;
}
}
- if (usePipe)
+ if (usePipe)
{
- portable_pclose(f);
Debug::print(Debug::FilterOutput, 0, "Filter output\n");
Debug::print(Debug::FilterOutput,0,"-------------\n%s\n-------------\n",qPrint(result));
}
- else
- {
- fclose(f);
- }
}
result = transcodeCharacterStringToUTF8(result);
if (!result.isEmpty() && result.at(result.length()-1)!='\n') result += "\n";
@@ -921,6 +1039,7 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
static bool latexSourceCode = Config_getBool(LATEX_SOURCE_CODE);
static bool rtfSourceCode = Config_getBool(RTF_SOURCE_CODE);
+ static bool docbookSourceCode = Config_getBool(DOCBOOK_PROGRAMLISTING);
ol.pushGeneratorState();
//printf("Definition::writeSourceRef %d %p\n",bodyLine,bodyDef);
QCString fn = getSourceFileBase();
@@ -945,11 +1064,15 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (!docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (!rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
}
- // write line link (HTML, LaTeX optionally, RTF optionally)
+ // write line link (HTML and optionally LaTeX, Docbook, RTF)
ol.writeObjectLink(0,fn,anchorStr,lineStr);
ol.enableAll();
ol.disable(OutputGenerator::Html);
@@ -957,6 +1080,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -975,6 +1102,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (!docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (!rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -987,6 +1118,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1009,6 +1144,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (!docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (!rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1021,6 +1160,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1040,6 +1183,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.enable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.enable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.enable(OutputGenerator::RTF);
@@ -1052,6 +1199,10 @@ void Definition::writeSourceDef(OutputList &ol,const char *)
{
ol.disable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1145,6 +1296,7 @@ void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
const QCString &text,MemberSDict *members,bool /*funcOnly*/)
{
static bool latexSourceCode = Config_getBool(LATEX_SOURCE_CODE);
+ static bool docbookSourceCode = Config_getBool(DOCBOOK_PROGRAMLISTING);
static bool rtfSourceCode = Config_getBool(RTF_SOURCE_CODE);
static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
static bool refLinkSource = Config_getBool(REFERENCES_LINK_SOURCE);
@@ -1203,6 +1355,10 @@ void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
{
ol.disable(OutputGenerator::Latex);
}
+ if (!docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (!rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1221,6 +1377,10 @@ void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
{
ol.disable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1238,6 +1398,10 @@ void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
{
ol.disable(OutputGenerator::Latex);
}
+ if (!docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (!rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1255,6 +1419,10 @@ void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
{
ol.disable(OutputGenerator::Latex);
}
+ if (docbookSourceCode)
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (rtfSourceCode)
{
ol.disable(OutputGenerator::RTF);
@@ -1278,18 +1446,12 @@ void Definition::_writeSourceRefList(OutputList &ol,const char *scopeName,
void Definition::writeSourceReffedBy(OutputList &ol,const char *scopeName)
{
- if (Config_getBool(REFERENCED_BY_RELATION))
- {
- _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
- }
+ _writeSourceRefList(ol,scopeName,theTranslator->trReferencedBy(),m_impl->sourceRefByDict,FALSE);
}
void Definition::writeSourceRefs(OutputList &ol,const char *scopeName)
{
- if (Config_getBool(REFERENCES_RELATION))
- {
- _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
- }
+ _writeSourceRefList(ol,scopeName,theTranslator->trReferences(),m_impl->sourceRefsDict,TRUE);
}
bool Definition::hasDocumentation() const
@@ -1476,13 +1638,21 @@ void Definition::mergeRefItems(Definition *d)
m_impl->xrefListItems->setAutoDelete(TRUE);
}
QListIterator<ListItemInfo> slii(*xrefList);
+ QListIterator<ListItemInfo> mlii(*m_impl->xrefListItems);
ListItemInfo *lii;
+ ListItemInfo *mii;
for (slii.toFirst();(lii=slii.current());++slii)
{
- if (_getXRefListId(lii->type)==-1)
+ bool found = false;
+ for (mlii.toFirst();(mii=mlii.current());++mlii)
{
- m_impl->xrefListItems->append(new ListItemInfo(*lii));
+ if ((qstrcmp(lii->type,mii->type)==0) && (lii->itemId == mii->itemId))
+ {
+ found = true;
+ break;
+ }
}
+ if (!found) m_impl->xrefListItems->append(new ListItemInfo(*lii));
}
}
}
@@ -1633,7 +1803,7 @@ void Definition::writeToc(OutputList &ol, const LocalToc &localToc)
int level=1,l;
char cs[2];
cs[1]='\0';
- bool inLi[5]={ FALSE, FALSE, FALSE, FALSE };
+ bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
for (li.toFirst();(si=li.current());++li)
{
if (si->type==SectionInfo::Section ||
@@ -1681,6 +1851,55 @@ void Definition::writeToc(OutputList &ol, const LocalToc &localToc)
ol.popGeneratorState();
}
+ if (localToc.isDocbookEnabled())
+ {
+ ol.pushGeneratorState();
+ ol.disableAllBut(OutputGenerator::Docbook);
+ ol.writeString(" <toc>\n");
+ ol.writeString(" <title>" + theTranslator->trRTFTableOfContents() + "</title>\n");
+ SectionDict *sectionDict = getSectionDict();
+ SDict<SectionInfo>::Iterator li(*sectionDict);
+ SectionInfo *si;
+ int level=1,l;
+ bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
+ int maxLevel = localToc.docbookLevel();
+ for (li.toFirst();(si=li.current());++li)
+ {
+ if (si->type==SectionInfo::Section ||
+ si->type==SectionInfo::Subsection ||
+ si->type==SectionInfo::Subsubsection ||
+ si->type==SectionInfo::Paragraph)
+ {
+ //printf(" level=%d title=%s\n",level,si->title.data());
+ int nextLevel = (int)si->type;
+ if (nextLevel>level)
+ {
+ for (l=level;l<nextLevel;l++)
+ {
+ if (l < maxLevel) ol.writeString(" <tocdiv>\n");
+ }
+ }
+ else if (nextLevel<level)
+ {
+ for (l=level;l>nextLevel;l--)
+ {
+ inLi[l]=FALSE;
+ if (l <= maxLevel) ol.writeString(" </tocdiv>\n");
+ }
+ }
+ if (nextLevel <= maxLevel)
+ {
+ QCString titleDoc = convertToDocBook(si->title);
+ ol.writeString(" <tocentry>" + (si->title.isEmpty()?si->label:titleDoc) + "</tocentry>\n");
+ }
+ inLi[nextLevel]=TRUE;
+ level = nextLevel;
+ }
+ }
+ ol.writeString(" </toc>\n");
+ ol.popGeneratorState();
+ }
+
if (localToc.isLatexEnabled())
{
ol.pushGeneratorState();
diff --git a/src/docbookgen.cpp b/src/docbookgen.cpp
index 345629e..8c8ed90 100644
--- a/src/docbookgen.cpp
+++ b/src/docbookgen.cpp
@@ -1,6 +1,6 @@
/******************************************************************************
*
-*
+*
*
* Copyright (C) 1997-2015 by Dimitri van Heesch.
*
@@ -21,11 +21,14 @@
#include <qfile.h>
#include <qtextstream.h>
#include <qintdict.h>
+#include <qregexp.h>
#include "docbookgen.h"
#include "doxygen.h"
#include "message.h"
#include "config.h"
#include "classlist.h"
+#include "classdef.h"
+#include "diagram.h"
#include "util.h"
#include "defargs.h"
#include "outputgen.h"
@@ -54,57 +57,22 @@
// debug inside output
//#define Docbook_DB(x) QCString __t;__t.sprintf x;m_t << __t
+#if 0
+#define DB_GEN_C DB_GEN_C1(t)
+#define DB_GEN_C1(x) x << "<!-- DB_GEN_C " << __LINE__ << " -->\n";
+#define DB_GEN_C2(y) DB_GEN_C2a(t,y)
+#define DB_GEN_C2a(x,y) x << "<!-- DB_GEN_C " << __LINE__ << " " << y << " -->\n";
+#else
+#define DB_GEN_C
+#define DB_GEN_C1(x)
+#define DB_GEN_C2(y)
+#define DB_GEN_C2a(x,y)
+#endif
//------------------
-class DocbookSectionMapper : public QIntDict<char>
-{
- public:
- DocbookSectionMapper() : QIntDict<char>(47)
- {
- insert(MemberListType_pubTypes,"public-type");
- insert(MemberListType_pubMethods,"public-func");
- insert(MemberListType_pubAttribs,"public-attrib");
- insert(MemberListType_pubSlots,"public-slot");
- insert(MemberListType_signals,"signal");
- insert(MemberListType_dcopMethods,"dcop-func");
- insert(MemberListType_properties,"property");
- insert(MemberListType_events,"event");
- insert(MemberListType_pubStaticMethods,"public-static-func");
- insert(MemberListType_pubStaticAttribs,"public-static-attrib");
- insert(MemberListType_proTypes,"protected-type");
- insert(MemberListType_proMethods,"protected-func");
- insert(MemberListType_proAttribs,"protected-attrib");
- insert(MemberListType_proSlots,"protected-slot");
- insert(MemberListType_proStaticMethods,"protected-static-func");
- insert(MemberListType_proStaticAttribs,"protected-static-attrib");
- insert(MemberListType_pacTypes,"package-type");
- insert(MemberListType_pacMethods,"package-func");
- insert(MemberListType_pacAttribs,"package-attrib");
- insert(MemberListType_pacStaticMethods,"package-static-func");
- insert(MemberListType_pacStaticAttribs,"package-static-attrib");
- insert(MemberListType_priTypes,"private-type");
- insert(MemberListType_priMethods,"private-func");
- insert(MemberListType_priAttribs,"private-attrib");
- insert(MemberListType_priSlots,"private-slot");
- insert(MemberListType_priStaticMethods,"private-static-func");
- insert(MemberListType_priStaticAttribs,"private-static-attrib");
- insert(MemberListType_friends,"friend");
- insert(MemberListType_related,"related");
- insert(MemberListType_decDefineMembers,"define");
- insert(MemberListType_decProtoMembers,"prototype");
- insert(MemberListType_decTypedefMembers,"typedef");
- insert(MemberListType_decEnumMembers,"enum");
- insert(MemberListType_decFuncMembers,"func");
- insert(MemberListType_decVarMembers,"var");
- }
-};
-
-static DocbookSectionMapper g_docbookSectionMapper;
-
-
inline void writeDocbookString(FTextStream &t,const char *s)
{
- t << convertToXML(s);
+ t << convertToDocBook(s);
}
inline void writeDocbookCodeString(FTextStream &t,const char *s, int &col)
@@ -128,27 +96,30 @@ inline void writeDocbookCodeString(FTextStream &t,const char *s, int &col)
case '&': t << "&amp;"; col++; break;
case '\'': t << "&apos;"; col++; break;
case '"': t << "&quot;"; col++; break;
+ case '\007': t << "^G"; col++; break; // bell
+ case '\014': t << "^L"; col++; break; // form feed
default: t << c; col++; break;
}
}
}
-static void writeDocbookHeaderMainpage(FTextStream &t)
+static void addIndexTerm(FTextStream &t, QCString prim, QCString sec = "")
{
- t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
- t << "<chapter xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" << endl;
-}
-
-static void writeDocbookHeader_ID(FTextStream &t, QCString id)
-{
- t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
- t << "<section xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:id=\"" << id << "\">" << endl;
+ t << "<indexterm><primary>";
+ t << convertToDocBook(prim);
+ t << "</primary>";
+ if (!sec.isEmpty())
+ {
+ t << "<secondary>";
+ t << convertToDocBook(sec);
+ t << "</secondary>";
+ }
+ t << "</indexterm>" << endl;
}
-
void writeDocbookLink(FTextStream &t,const char * /*extRef*/,const char *compoundId,
const char *anchorId,const char * text,const char * /*tooltip*/)
{
- t << "<link linkend=\"" << compoundId;
+ t << "<link linkend=\"_" << stripPath(compoundId);
if (anchorId) t << "_1" << anchorId;
t << "\"";
t << ">";
@@ -156,1856 +127,1054 @@ void writeDocbookLink(FTextStream &t,const char * /*extRef*/,const char *compoun
t << "</link>";
}
-class TextGeneratorDocbookImpl : public TextGeneratorIntf
+DocbookCodeGenerator::DocbookCodeGenerator(FTextStream &t) : m_lineNumber(-1), m_col(0),
+ m_insideCodeLine(FALSE), m_insideSpecialHL(FALSE)
{
- public:
- TextGeneratorDocbookImpl(FTextStream &t): m_t(t) {}
- void writeString(const char *s,bool /*keepSpaces*/) const
- {
- writeDocbookString(m_t,s);
- }
- void writeBreak(int) const {}
- void writeLink(const char *extRef,const char *file,
- const char *anchor,const char *text
- ) const
- {
- writeDocbookLink(m_t,extRef,file,anchor,text,0);
- }
- private:
- FTextStream &m_t;
-};
+ m_prettyCode=Config_getBool(DOCBOOK_PROGRAMLISTING);
+ setTextStream(t);
+}
-class DocbookCodeGenerator : public CodeOutputInterface
+DocbookCodeGenerator::DocbookCodeGenerator() : m_lineNumber(-1), m_col(0),
+ m_insideCodeLine(FALSE), m_insideSpecialHL(FALSE), m_streamSet(FALSE)
{
- public:
- DocbookCodeGenerator(FTextStream &t) : m_t(t), m_lineNumber(-1), m_col(0),
- m_insideCodeLine(FALSE), m_insideSpecialHL(FALSE) {}
- virtual ~DocbookCodeGenerator() {}
+ m_prettyCode=Config_getBool(DOCBOOK_PROGRAMLISTING);
+}
- void codify(const char *text)
- {
- Docbook_DB(("(codify \"%s\")\n",text));
- writeDocbookCodeString(m_t,text,m_col);
- }
- void writeCodeLink(const char *ref,const char *file,
- const char *anchor,const char *name,
- const char *tooltip)
- {
- Docbook_DB(("(writeCodeLink)\n"));
- writeDocbookLink(m_t,ref,file,anchor,name,tooltip);
- m_col+=strlen(name);
- }
- void writeTooltip(const char *, const DocLinkInfo &, const char *,
- const char *, const SourceLinkInfo &, const SourceLinkInfo &
- )
- {
- Docbook_DB(("(writeToolTip)\n"));
- }
- void startCodeLine(bool)
- {
- Docbook_DB(("(startCodeLine)\n"));
- if (m_lineNumber!=-1)
- {
- if (!m_refId.isEmpty())
- {
- m_t << "<link linkend=\"" << m_refId << "\">";
- }
- m_t << m_lineNumber << " ";
- if (!m_refId.isEmpty())
- {
- m_t << "</link>";
- }
- }
- m_insideCodeLine=TRUE;
- m_col=0;
- }
- void endCodeLine()
- {
- m_t << endl;
- Docbook_DB(("(endCodeLine)\n"));
- m_lineNumber = -1;
- m_refId.resize(0);
- m_external.resize(0);
- m_insideCodeLine=FALSE;
- }
- void startFontClass(const char *colorClass)
- {
- Docbook_DB(("(startFontClass)\n"));
- m_t << "<emphasis class=\"" << colorClass << "\">";
- m_insideSpecialHL=TRUE;
- }
- void endFontClass()
- {
- Docbook_DB(("(endFontClass)\n"));
- m_t << "</emphasis>"; // non DocBook
- m_insideSpecialHL=FALSE;
- }
- void writeCodeAnchor(const char *)
- {
- Docbook_DB(("(writeCodeAnchor)\n"));
- }
- void writeLineNumber(const char *extRef,const char *compId,
- const char *anchorId,int l)
- {
- Docbook_DB(("(writeLineNumber)\n"));
- // we remember the information provided here to use it
- // at the <codeline> start tag.
- m_lineNumber = l;
- if (compId)
- {
- m_refId=compId;
- if (anchorId) m_refId+=(QCString)"_1"+anchorId;
- if (extRef) m_external=extRef;
- }
- }
- void setCurrentDoc(Definition *,const char *,bool)
- {
- }
- void addWord(const char *,bool)
+DocbookCodeGenerator::~DocbookCodeGenerator() {}
+
+void DocbookCodeGenerator::codify(const char *text)
+{
+ Docbook_DB(("(codify \"%s\")\n",text));
+ writeDocbookCodeString(m_t,text,m_col);
+}
+void DocbookCodeGenerator::writeCodeLink(const char *ref,const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip)
+{
+ Docbook_DB(("(writeCodeLink)\n"));
+ writeDocbookLink(m_t,ref,file,anchor,name,tooltip);
+ m_col+=strlen(name);
+}
+void DocbookCodeGenerator::writeCodeLinkLine(const char *ref,const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip)
+{
+ Docbook_DB(("(writeCodeLinkLine)\n"));
+ m_t << "<anchor xml:id=\"_" << stripExtensionGeneral(stripPath(file),".xml");
+ m_t << "_1l";
+ writeDocbookString(m_t,name);
+ m_t << "\"/>";
+ m_col+=strlen(name);
+}
+void DocbookCodeGenerator::writeTooltip(const char *, const DocLinkInfo &, const char *,
+ const char *, const SourceLinkInfo &, const SourceLinkInfo &
+ )
+{
+ Docbook_DB(("(writeToolTip)\n"));
+}
+void DocbookCodeGenerator::startCodeLine(bool)
+{
+ Docbook_DB(("(startCodeLine)\n"));
+ m_insideCodeLine=TRUE;
+ m_col=0;
+}
+void DocbookCodeGenerator::endCodeLine()
+{
+ m_t << endl;
+ Docbook_DB(("(endCodeLine)\n"));
+ m_lineNumber = -1;
+ m_refId.resize(0);
+ m_external.resize(0);
+ m_insideCodeLine=FALSE;
+}
+void DocbookCodeGenerator::startFontClass(const char *colorClass)
+{
+ Docbook_DB(("(startFontClass)\n"));
+ m_t << "<emphasis role=\"" << colorClass << "\">";
+ m_insideSpecialHL=TRUE;
+}
+void DocbookCodeGenerator::endFontClass()
+{
+ Docbook_DB(("(endFontClass)\n"));
+ m_t << "</emphasis>"; // non DocBook
+ m_insideSpecialHL=FALSE;
+}
+void DocbookCodeGenerator::writeCodeAnchor(const char *)
+{
+ Docbook_DB(("(writeCodeAnchor)\n"));
+}
+void DocbookCodeGenerator::writeLineNumber(const char *ref,const char *fileName,
+ const char *anchor,int l)
+{
+ Docbook_DB(("(writeLineNumber)\n"));
+ m_insideCodeLine = TRUE;
+ if (m_prettyCode)
+ {
+ QCString lineNumber;
+ lineNumber.sprintf("%05d",l);
+
+ if (fileName && !m_sourceFileName.isEmpty())
{
+ writeCodeLinkLine(ref,m_sourceFileName,anchor,lineNumber,0);
+ writeCodeLink(ref,fileName,anchor,lineNumber,0);
}
- void finish()
+ else
{
- if (m_insideCodeLine) endCodeLine();
+ codify(lineNumber);
}
-
- private:
- FTextStream &m_t;
- QCString m_refId;
- QCString m_external;
- int m_lineNumber;
- int m_col;
- bool m_insideCodeLine;
- bool m_insideSpecialHL;
-};
-
-
-static void writeTemplateArgumentList(ArgumentList *al,
- FTextStream &t,
- Definition *scope,
- FileDef *fileScope,
- int indent)
-{
- QCString indentStr;
- indentStr.fill(' ',indent);
- if (al)
+ m_t << " ";
+ }
+ else
{
- t << indentStr << "<templateparamlist>" << endl;
- ArgumentListIterator ali(*al);
- Argument *a;
- for (ali.toFirst();(a=ali.current());++ali)
- {
- t << indentStr << " <param>" << endl;
- if (!a->type.isEmpty())
- {
- t << indentStr << " <type>";
- linkifyText(TextGeneratorDocbookImpl(t),scope,fileScope,0,a->type);
- t << "</type>" << endl;
- }
- if (!a->name.isEmpty())
- {
- t << indentStr << " <declname>" << a->name << "</declname>" << endl;
- t << indentStr << " <defname>" << a->name << "</defname>" << endl;
- }
- if (!a->defval.isEmpty())
- {
- t << indentStr << " <defval>";
- linkifyText(TextGeneratorDocbookImpl(t),scope,fileScope,0,a->defval);
- t << "</defval>" << endl;
- }
- t << indentStr << " </param>" << endl;
- }
- t << indentStr << "</templateparamlist>" << endl;
+ m_t << l << " ";
}
-}
-static void writeTemplateList(ClassDef *cd,FTextStream &t)
+}
+void DocbookCodeGenerator::setCurrentDoc(Definition *,const char *,bool)
{
- writeTemplateArgumentList(cd->templateArguments(),t,cd,0,4);
}
-
-static void writeDocbookDocBlock(FTextStream &t,
- const QCString &fileName,
- int lineNr,
- Definition *scope,
- MemberDef * md,
- const QCString &text)
-{
- QCString stext = text.stripWhiteSpace();
- if (stext.isEmpty()) return;
- // convert the documentation string into an abstract syntax tree
- DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,text,FALSE,FALSE);
- // create a code generator
- DocbookCodeGenerator *docbookCodeGen = new DocbookCodeGenerator(t);
- // create a parse tree visitor for Docbook
- DocbookDocVisitor *visitor = new DocbookDocVisitor(t,*docbookCodeGen);
- // visit all nodes
- root->accept(visitor);
- // clean up
- delete visitor;
- delete docbookCodeGen;
- delete root;
+void DocbookCodeGenerator::addWord(const char *,bool)
+{
}
-
-void writeDocbookCodeBlock(FTextStream &t,FileDef *fd)
-{
- ParserInterface *pIntf=Doxygen::parserManager->getParser(fd->getDefFileExtension());
- SrcLangExt langExt = getLanguageFromFileName(fd->getDefFileExtension());
- pIntf->resetCodeParserState();
- DocbookCodeGenerator *docbookGen = new DocbookCodeGenerator(t);
- pIntf->parseCode(*docbookGen, // codeOutIntf
- 0, // scopeName
- fileToString(fd->absFilePath(),Config_getBool(FILTER_SOURCE_FILES)),
- langExt, // lang
- FALSE, // isExampleBlock
- 0, // exampleName
- fd, // fileDef
- -1, // startLine
- -1, // endLine
- FALSE, // inlineFragement
- 0, // memberDef
- TRUE // showLineNumbers
- );
- docbookGen->finish();
- delete docbookGen;
+void DocbookCodeGenerator::finish()
+{
+ if (m_insideCodeLine) endCodeLine();
}
-
-static QCString classOutputFileBase(ClassDef *cd)
+void DocbookCodeGenerator::startCodeFragment()
+{
+ m_t << "<literallayout><computeroutput>" << endl;
+}
+void DocbookCodeGenerator::endCodeFragment()
{
- //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
- //if (inlineGroupedClasses && cd->partOfGroups()!=0)
- return cd->getOutputFileBase();
- //else
- // return cd->getOutputFileBase();
+ m_t << "</computeroutput></literallayout>" << endl;
}
-static QCString memberOutputFileBase(MemberDef *md)
+DocbookGenerator::DocbookGenerator() : OutputGenerator()
{
- //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
- //if (inlineGroupedClasses && md->getClassDef() && md->getClassDef()->partOfGroups()!=0)
- // return md->getClassDef()->getDocbookOutputFileBase();
- //else
- // return md->getOutputFileBase();
- return md->getOutputFileBase();
+DB_GEN_C
+ dir=Config_getString(DOCBOOK_OUTPUT);
+ //insideTabbing=FALSE;
+ //firstDescItem=TRUE;
+ //disableLinks=FALSE;
+ //m_indent=0;
+ //templateMemberItem = FALSE;
+ m_prettyCode=Config_getBool(DOCBOOK_PROGRAMLISTING);
+ m_denseText = FALSE;
+ m_inGroup = FALSE;
+ m_inDetail = FALSE;
+ m_levelListItem = 0;
+ m_descTable = FALSE;
+ m_inLevel = -1;
+ m_firstMember = FALSE;
+ for (int i = 0 ; i < sizeof(m_inListItem) / sizeof(*m_inListItem) ; i++) m_inListItem[i] = FALSE;
+ for (int i = 0 ; i < sizeof(m_inSimpleSect) / sizeof(*m_inSimpleSect) ; i++) m_inSimpleSect[i] = FALSE;
}
+DocbookGenerator::~DocbookGenerator()
+{
+DB_GEN_C
+}
-static void generateDocbookForMember(MemberDef *md,FTextStream &t,Definition *def, bool detailed=0)
+void DocbookGenerator::init()
{
+ QCString dir=Config_getString(DOCBOOK_OUTPUT);
+ QDir d(dir);
+ if (!d.exists() && !d.mkdir(dir))
+ {
+ err("Could not create output directory %s\n",dir.data());
+ exit(1);
+ }
- // + declaration/definition arg lists
- // + reimplements
- // + reimplementedBy
- // + exceptions
- // + const/volatile specifiers
- // - examples
- // + source definition
- // + source references
- // + source referenced by
- // - body code
- // + template arguments
- // (templateArguments(), definitionTemplateParameterLists())
- // - call graph
+ createSubDirs(d);
+}
- // enum values are written as part of the enum
- if (md->memberType()==MemberType_EnumValue) return;
- if (md->isHidden()) return;
- //if (md->name().at(0)=='@') return; // anonymous member
+void DocbookGenerator::startFile(const char *name,const char *,const char *)
+{
+DB_GEN_C
+ QCString fileName=name;
+ QCString pageName;
+ QCString fileType="section";
+ if (fileName == "refman")
+ {
+ fileName="index";
+ fileType="book";
+ }
+ else if (fileName == "index")
+ {
+ fileName="mainpage";
+ fileType="chapter";
+ }
+ pageName = fileName;
+ relPath = relativePathToRoot(fileName);
+ if (fileName.right(4)!=".xml") fileName+=".xml";
+ startPlainFile(fileName);
+ m_codeGen.setTextStream(t);
+ m_codeGen.setRelativePath(relPath);
+ m_codeGen.setSourceFileName(stripPath(fileName));
+
+ t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
+ t << "<" << fileType << " xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"";
+ if (!pageName.isEmpty()) t << " xml:id=\"_" << stripPath(pageName) << "\"";
+ t << ">" << endl;
+}
- // group members are only visible in their group
- //if (def->definitionType()!=Definition::TypeGroup && md->getGroupDef()) return;
- QCString memType;
- switch (md->memberType())
+void DocbookGenerator::endFile()
+{
+DB_GEN_C
+ if (m_inDetail) t << "</section>" << endl;
+ m_inDetail = FALSE;
+ while (m_inLevel != -1)
{
- case MemberType_Define: memType="define"; break;
- case MemberType_Function: memType="function"; break;
- case MemberType_Variable: memType="variable"; break;
- case MemberType_Typedef: memType="typedef"; break;
- case MemberType_Enumeration: memType="enum"; break;
- case MemberType_EnumValue: ASSERT(0); break;
- case MemberType_Signal: memType="signal"; break;
- case MemberType_Slot: memType="slot"; break;
- case MemberType_Friend: memType="friend"; break;
- case MemberType_DCOP: memType="dcop"; break;
- case MemberType_Property: memType="property"; break;
- case MemberType_Event: memType="event"; break;
- case MemberType_Interface: memType="interface"; break;
- case MemberType_Service: memType="service"; break;
+ t << "</section>" << endl;
+ m_inLevel--;
}
- QCString scopeName;
- if (md->getClassDef())
+ if (m_inGroup) t << "</section>" << endl;
+ m_inGroup = FALSE;
+
+ QCString fileType="section";
+ QCString fileName= m_codeGen.sourceFileName();
+ if (fileName == "index.xml")
{
- scopeName=md->getClassDef()->name();
+ fileType="book";
}
- else if (md->getNamespaceDef())
+ else if (fileName == "mainpage.xml")
{
- scopeName=md->getNamespaceDef()->name();
+ fileType="chapter";
}
- if (detailed==0)
+ t << "</" << fileType << ">" << endl;
+ endPlainFile();
+ m_codeGen.setSourceFileName("");
+}
+
+void DocbookGenerator::startIndexSection(IndexSections is)
+{
+DB_GEN_C2("IndexSections " << is)
+ switch (is)
{
- t << " <para>" << endl;
- t << " <itemizedlist>" << endl;
- t << " <listitem>" << endl;
- //enum
- bool closePara=TRUE;
- if (md->memberType()==MemberType_Enumeration)
- {
- MemberList *enumFields = md->enumFieldList();
- t << " <para><literallayout>" << memType << " <link linkend=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
+ case isTitlePageStart:
{
- t << md->getGroupDef()->getOutputFileBase();
+ QCString dbk_projectName = Config_getString(PROJECT_NAME);
+ t << " <info>" << endl;
+ t << " <title>" << convertToDocBook(dbk_projectName) << "</title>" << endl;
+ t << " </info>" << endl;
}
- else
- {
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
- if (enumFields!=0)
+ break;
+ case isTitlePageAuthor:
+ break;
+ case isMainPage:
+ t << "<chapter>" << endl;
+ t << " <title>";
+ break;
+ case isModuleIndex:
+ //Module Index}\n"
+ break;
+ case isDirIndex:
+ //Directory Index}\n"
+ break;
+ case isNamespaceIndex:
+ //Namespace Index}\n"
+ break;
+ case isClassHierarchyIndex:
+ //Hierarchical Index}\n"
+ break;
+ case isCompoundIndex:
+ //t << "{"; //Class Index}\n"
+ break;
+ case isFileIndex:
+ //Annotated File Index}\n"
+ break;
+ case isPageIndex:
+ //Annotated Page Index}\n"
+ break;
+ case isModuleDocumentation:
+ t << "<chapter>\n";
+ t << " <title>";
+ break;
+ case isDirDocumentation:
+ t << "<chapter>\n";
+ t << " <title>";
+ break;
+ case isNamespaceDocumentation:
+ t << "<chapter>\n";
+ t << " <title>";
+ break;
+ case isClassDocumentation:
+ t << "<chapter>\n";
+ t << " <title>";
+ break;
+ case isFileDocumentation:
+ t << "<chapter>\n";
+ t << " <title>";
+ break;
+ case isExampleDocumentation:
+ t << "<chapter>\n";
+ t << " <title>";
+ break;
+ case isPageDocumentation:
+ break;
+ case isPageDocumentation2:
+ break;
+ case isEndIndex:
+ break;
+ }
+}
+
+void DocbookGenerator::endIndexSection(IndexSections is)
+{
+DB_GEN_C2("IndexSections " << is)
+ static bool sourceBrowser = Config_getBool(SOURCE_BROWSER);
+ switch (is)
+ {
+ case isTitlePageStart:
+ break;
+ case isTitlePageAuthor:
+ break;
+ case isMainPage:
+ t << "</title>" << endl;
+ t << " <xi:include href=\"mainpage.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ t << "</chapter>" << endl;
+ break;
+ case isModuleIndex:
+ //t << "</chapter>" << endl;
+ break;
+ case isDirIndex:
+ //t << "<xi:include href=\"dirs.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>";
+ //t << "</chapter>" << endl;
+ break;
+ case isNamespaceIndex:
+ //t << "<xi:include href=\"namespaces.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>";
+ //t << "</chapter>" << endl;
+ break;
+ case isClassHierarchyIndex:
+ //t << "<xi:include href=\"hierarchy.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>";
+ //t << "</chapter>" << endl;
+ break;
+ case isCompoundIndex:
+ //t << "</chapter>" << endl;
+ break;
+ case isFileIndex:
+ //t << "<xi:include href=\"files.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>";
+ //t << "</chapter>" << endl;
+ break;
+ case isPageIndex:
+ //t << "<xi:include href=\"pages.xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>";
+ //t << "</chapter>" << endl;
+ break;
+ case isModuleDocumentation:
{
- MemberListIterator emli(*enumFields);
- MemberDef *emd;
- t << " {" << endl;
- int cnt=0;
- for (emli.toFirst();(emd=emli.current());++emli)
+ t << "</title>" << endl;
+ GroupSDict::Iterator gli(*Doxygen::groupSDict);
+ GroupDef *gd;
+ bool found=FALSE;
+ for (gli.toFirst();(gd=gli.current()) && !found;++gli)
{
- if (cnt!=0)
- {
- t << "," << endl;
- }
- t << "<link linkend=\"" << memberOutputFileBase(emd) << "_1" << emd->anchor() << "\">";
- writeDocbookString(t,emd->name());
- t << "</link>";
- if (!emd->initializer().isEmpty())
+ if (!gd->isReference())
{
- writeDocbookString(t,emd->initializer());
+ t << " <xi:include href=\"" << gd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ found=TRUE;
}
- cnt++;
- }
- t << endl << "}";
- }
- t << "</literallayout>" << endl;
- if (md->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis></para>" << endl;
- }
- }
- else if (md->memberType()==MemberType_Define)
- {
- t << " <para>" << "#" << memType << " <link linkend=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
- }
- else
- {
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
- if (!md->initializer().isEmpty() && md->initializer().length()<2000)
- {
- t << " ";
- linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->initializer());
- }
- if (md->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis></para>" << endl;
- }
- }
- else if (md->memberType()==MemberType_Variable)
- {
- if (md->getClassDef())
- {
- t << " <para>" << convertToXML(md->declaration());
- if (md->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis></para>";
- }
- }
- else
- {
- t << " <para>";
- linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->typeString());
- t << " <link linkend=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
}
- else
+ for (;(gd=gli.current());++gli)
{
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
- if (md->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis></para>" << endl;
+ if (!gd->isReference())
+ {
+ t << " <xi:include href=\"" << gd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ }
}
}
- }
- else if (md->memberType()==MemberType_Typedef)
- {
- t << " <para>" << memType;
- t << " ";
- linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->typeString());
- t << " ";
- t << " <link linkend=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
- }
- else
+ t << "</chapter>\n";
+ break;
+ case isDirDocumentation:
{
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
- if (md->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis></para>" << endl;
- }
- }
- else if (md->memberType()==MemberType_Function)
- {
- t << " <para>";
- linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,md->typeString());
- t << " <link linkend=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
- }
- else
- {
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << convertToXML(md->name()) << "</link>";
- t << " (" << endl;
- ArgumentList *declAl = md->declArgumentList();
- if (declAl && declAl->count()>0)
- {
- ArgumentListIterator declAli(*declAl);
- Argument *a;
- int cnt=0;
- for (declAli.toFirst();(a=declAli.current());++declAli)
+ t << "</title>" << endl;
+ SDict<DirDef>::Iterator dli(*Doxygen::directories);
+ DirDef *dd;
+ bool found=FALSE;
+ for (dli.toFirst();(dd=dli.current()) && !found;++dli)
{
- if (cnt!=0)
- {
- t << ", ";
- }
- if (!a->type.isEmpty())
+ if (dd->isLinkableInProject())
{
- linkifyText(TextGeneratorDocbookImpl(t),def,md->getBodyDef(),md,a->type);
+ t << "< xi:include href=\"" << dd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ found=TRUE;
}
- t << " ";
- if (!a->name.isEmpty())
+ }
+ for (;(dd=dli.current());++dli)
+ {
+ if (dd->isLinkableInProject())
{
- writeDocbookString(t,a->name);
+ t << " <xi:include href=\"" << dd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
}
- cnt++;
}
}
- t << ")";
- if (md->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis></para>" << endl;
- }
- }
- else
- {
- closePara = FALSE;
- }
- if (closePara) t << "</para>" << endl;
- t << " </listitem>" << endl;
- t << " </itemizedlist>" << endl;
- t << " </para>" << endl;
- }
- else
- {
- if (md->memberType()==MemberType_Enumeration)
- {
- MemberList *enumFields = md->enumFieldList();
- t << " <section xml:id=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
- }
- else
+ t << "</chapter>\n";
+ break;
+ case isNamespaceDocumentation:
{
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << endl;
- t << " <title>" << memType << " " << convertToXML(md->name()) << " " << "</title>" << endl;
- t << " ";
- writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
- t << endl;
- if (enumFields!=0)
- {
- MemberListIterator emli(*enumFields);
- MemberDef *emd;
- t << " <formalpara>" << endl;
- t << " <title>" << theTranslator->trEnumerationValues() << ":</title>" << endl;
- t << " <variablelist>" << endl;
- for (emli.toFirst();(emd=emli.current());++emli)
+ t << "</title>" << endl;
+ NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
+ NamespaceDef *nd;
+ bool found=FALSE;
+ for (nli.toFirst();(nd=nli.current()) && !found;++nli)
{
- t << " <varlistentry xml:id=\"";
- t << memberOutputFileBase(emd) << "_1" << emd->anchor() << "\">" << endl;
- t << " <term>";
- writeDocbookString(t,emd->name());
- t << "</term>" << endl;
- t << " <listitem>" << endl;
- if(Config_getBool(REPEAT_BRIEF))
+ if (nd->isLinkableInProject())
{
- t << " <para>";
- writeDocbookString(t,emd->briefDescription());
- t << "</para>" << endl;
+ t << "<xi:include href=\"" << nd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ found=TRUE;
}
- t << " </listitem>" << endl;
- t << " </varlistentry>" << endl;
}
- t << " </variablelist>" << endl;
- t << " </formalpara>" << endl;
- t << " <para>";
- t << "Definition at line " << md->getDefLine() << " of file " << stripPath(md->getDefFileName()) << endl;
- t << " <computeroutput><literallayout>" << endl;
- t << "{" << endl;
- for (emli.toFirst();(emd=emli.current());++emli)
+ while ((nd=nli.current()))
{
- writeDocbookString(t,emd->name());
- if (!emd->initializer().isEmpty())
+ if (nd->isLinkableInProject())
{
- writeDocbookString(t,emd->initializer());
+ t << "<xi:include href=\"" << nd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
}
- t << ", " << endl;
+ ++nli;
}
- t << "}" << convertToXML(md->name()) << ";" << endl;
- t << " </literallayout></computeroutput>" << endl;
- t << " </para>" << endl;
- t << " </section>" << endl;
- }
- }
- else if (md->memberType()==MemberType_Typedef)
- {
- t << " <section xml:id=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
}
- else
+ t << "</chapter>\n";
+ break;
+ case isClassDocumentation:
{
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << endl;
- t << " <title>" << convertToXML(md->definition()) << "</title>";
- if(Config_getBool(REPEAT_BRIEF))
- {
- t << " <emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis>" << endl;
- }
- t << " ";
- writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
- t << endl;
- t << " </section>" << endl;
- }
- else if (md->memberType()==MemberType_Function)
- {
- t << " <section xml:id=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
- {
- t << md->getGroupDef()->getOutputFileBase();
- }
- else
- {
- t << memberOutputFileBase(md);
- }
- t << "_1" << md->anchor() << "\">" << endl;
- t << " <title>" << convertToXML(md->definition()) << " " << convertToXML(md->argsString()) << "</title>";
- if(Config_getBool(REPEAT_BRIEF))
- {
- t << " <emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis>" << endl;
- }
- t << " ";
- writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
- t << endl;
- t << " </section>" << endl;
- }
- else if (md->memberType()==MemberType_Define)
- {
- if (md->documentation())
- {
- t << " <section xml:id=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
+ t << "</title>" << endl;
+ ClassSDict::Iterator cli(*Doxygen::classSDict);
+ ClassDef *cd=0;
+ bool found=FALSE;
+ for (cli.toFirst();(cd=cli.current()) && !found;++cli)
{
- t << md->getGroupDef()->getOutputFileBase();
+ if (cd->isLinkableInProject() &&
+ cd->templateMaster()==0 &&
+ !cd->isEmbeddedInOuterScope()
+ )
+ {
+ t << " <xi:include href=\"" << cd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ found=TRUE;
+ }
}
- else
+ for (;(cd=cli.current());++cli)
{
- t << memberOutputFileBase(md);
+ if (cd->isLinkableInProject() &&
+ cd->templateMaster()==0 &&
+ !cd->isEmbeddedInOuterScope()
+ )
+ {
+ t << " <xi:include href=\"" << cd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ }
}
- t << "_1" << md->anchor() << "\">" << endl;
- t << " <title>" << convertToXML(md->definition()) << "</title>";
- t << " ";
- writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
- t << endl;
- t << " <para>Definition at line " << md->getDefLine() << " of file " << stripPath(md->getDefFileName()) << "</para>" << endl;
- t << " <para>The Documentation for this define was generated from the following file: </para>" << endl;
- t << " <para><itemizedlist><listitem><para>" << stripPath(md->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
- t << " </section>" << endl;
}
- }
- else if (md->memberType()==MemberType_Variable)
- {
- if (md->getClassDef())
+ t << "</chapter>\n";
+ break;
+ case isFileDocumentation:
{
- if (md->documentation())
+ t << "</title>" << endl;
+ bool isFirst=TRUE;
+ FileNameListIterator fnli(*Doxygen::inputNameList);
+ FileName *fn;
+ for (fnli.toFirst();(fn=fnli.current());++fnli)
{
- t << " <simplesect>" << endl;
- t << " <title>" << convertToXML(md->definition()) << "</title>";
- t << " ";
- writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
- t << endl;
- t << " <para>Definition at line " << md->getDefLine() << " of file " << stripPath(md->getDefFileName()) << "</para>" << endl;
- t << " <para>The Documentation for this struct was generated from the following file: </para>" << endl;
- t << " <para><itemizedlist><listitem><para>" << stripPath(md->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
- t << " </simplesect>" << endl;
+ FileNameIterator fni(*fn);
+ FileDef *fd;
+ for (;(fd=fni.current());++fni)
+ {
+ if (fd->isLinkableInProject())
+ {
+ if (isFirst)
+ {
+ t << " <xi:include href=\"" << fd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ if (sourceBrowser && m_prettyCode && fd->generateSourceFile())
+ {
+ t << " <xi:include href=\"" << fd->getSourceFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ }
+ isFirst=FALSE;
+ }
+ else
+ {
+ t << " <xi:include href=\"" << fd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ if (sourceBrowser && m_prettyCode && fd->generateSourceFile())
+ {
+ t << " <xi:include href=\"" << fd->getSourceFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ }
+ }
+ }
+ }
}
}
- else
+ t << "</chapter>\n";
+ break;
+ case isExampleDocumentation:
{
- t << " <section xml:id=\"";
- if (md->getGroupDef() && def->definitionType()==Definition::TypeGroup)
+ t << "</title>" << endl;
+ PageSDict::Iterator pdi(*Doxygen::exampleSDict);
+ PageDef *pd=pdi.toFirst();
+ if (pd)
{
- t << md->getGroupDef()->getOutputFileBase();
+ t << " <xi:include href=\"" << pd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
}
- else
+ for (++pdi;(pd=pdi.current());++pdi)
{
- t << memberOutputFileBase(md);
+ t << " <xi:include href=\"" << pd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
}
- t << "_1" << md->anchor() << "\">" << endl;
- t << " <title>" << convertToXML(md->definition()) << "</title>";
- if(Config_getBool(REPEAT_BRIEF))
- {
- t << " <emphasis>";
- writeDocbookString(t,md->briefDescription());
- t << "</emphasis>" << endl;
- }
- t << " ";
- writeDocbookDocBlock(t,md->docFile(),md->docLine(),md->getOuterScope(),md,md->documentation());
- t << endl;
- t << " </section>" << endl;
}
- }
- }
-}
-
-static void generateDocbookSection(Definition *d,FTextStream &t,MemberList *ml,const char *,
- bool detailed=0, const char *header=0,const char *documentation=0)
-{
- if (ml==0) return;
- MemberListIterator mli(*ml);
- MemberDef *md;
- int count=0;
- int doc_count=0;
- QCString title, desctitle;
-
- for (mli.toFirst();(md=mli.current());++mli)
- {
- // namespace members are also inserted in the file scope, but
- // to prevent this duplication in the Docbook output, we filter those here.
- if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0)
- {
- count++;
- }
- }
-
- if (count==0) return; // empty list
-
- switch (ml->listType())
- {
- case MemberListType_decDefineMembers: title=theTranslator->trDefines(); desctitle=theTranslator->trDefineDocumentation(); break;
- case MemberListType_decTypedefMembers: title=theTranslator->trTypedefs(); desctitle=theTranslator->trTypedefDocumentation(); break;
- case MemberListType_decEnumMembers: title=theTranslator->trEnumerations(); desctitle=theTranslator->trEnumerationTypeDocumentation(); break;
- case MemberListType_decFuncMembers: title=theTranslator->trFunctions(); desctitle=theTranslator->trFunctionDocumentation(); break;
- case MemberListType_decVarMembers: title=theTranslator->trVariables(); desctitle=theTranslator->trVariableDocumentation(); break;
- case MemberListType_pubAttribs: title=theTranslator->trPublicAttribs(); desctitle=theTranslator->trMemberDataDocumentation(); break;
- case MemberListType_priAttribs: title=theTranslator->trPrivateAttribs(); desctitle=theTranslator->trMemberDataDocumentation(); break;
- case MemberListType_proAttribs: title=theTranslator->trProtectedAttribs(); desctitle=theTranslator->trMemberDataDocumentation(); break;
- default: title=""; desctitle=""; break;
- }
-
- if (detailed)
- {
- for (mli.toFirst();(md=mli.current());++mli)
- {
- if (md->documentation().isEmpty() && !Config_getBool(REPEAT_BRIEF))
- {
- continue;
- }
- doc_count = 1;
- break;
- }
-
- if(doc_count == 0)
- {
- return;
- }
-
- if (desctitle)
- {
- t << " <section>" << endl;
- t << " <title>" << desctitle << "</title>" << endl;
- }
- } else
- {
- t << " <section>" << endl;
- if (header)
- {
- t << " <title>" << convertToXML(header) << "</title>" << endl;
- }
- else
- {
- t << " <title>" << title << "</title>" << endl;
- }
- }
-
- if (documentation)
- {
- t << " <description>";
- writeDocbookDocBlock(t,d->docFile(),d->docLine(),d,0,documentation);
- t << "</description>" << endl;
- }
- for (mli.toFirst();(md=mli.current());++mli)
- {
- // namespace members are also inserted in the file scope, but
- // to prevent this duplication in the Docbook output, we filter those here.
- if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0)
- {
- if (detailed && md->documentation().isEmpty() && !Config_getBool(REPEAT_BRIEF))
- {
- continue;
- }
-
- generateDocbookForMember(md,t,d,detailed);
- }
- }
- if (detailed)
- {
- if (desctitle)
- {
- t << " </section>" << endl;
- }
- }
- else
- {
- t << " </section>" << endl;
+ t << "</chapter>\n";
+ break;
+ case isPageDocumentation:
+ break;
+ case isPageDocumentation2:
+ break;
+ case isEndIndex:
+ t << "<index/>" << endl;
+ break;
}
}
-
-static void writeInnerClasses(const ClassSDict *cl,FTextStream &t)
+void DocbookGenerator::writePageLink(const char *name, bool /*first*/)
{
- if (cl)
+DB_GEN_C
+ PageSDict::Iterator pdi(*Doxygen::pageSDict);
+ PageDef *pd = pdi.toFirst();
+ for (pd = pdi.toFirst();(pd=pdi.current());++pdi)
{
- ClassSDict::Iterator cli(*cl);
- ClassDef *cd;
- QCString title = theTranslator->trClasses();
-
- if (cli.toFirst())
+ if (!pd->getGroupDef() && !pd->isReference() && pd->name() == stripPath(name))
{
- t << " <section>" << endl;
- t << " <title> " << title << " </title>" << endl;
- }
- for (cli.toFirst();(cd=cli.current());++cli)
- {
- if (!cd->isHidden() && cd->name().find('@')==-1)
+ t << "<chapter>\n";
+ if (!pd->title().isEmpty())
{
- t << " <para>" << endl;
- t << " <itemizedlist>" << endl;
- t << " <listitem>" << endl;
- t << " <para>" << "struct <link linkend=\"" << classOutputFileBase(cd) << "\">" << convertToXML(cd->name()) << "</link>";
- t << "</para>" << endl;
- if (cd->briefDescription())
- {
- t << "<para><emphasis>";
- writeDocbookString(t,cd->briefDescription());
- t << "</emphasis></para>" << endl;
- }
- t << " </listitem>" << endl;
- t << " </itemizedlist>" << endl;
- t << " </para>" << endl;
+ t << " <title>" << convertToDocBook(pd->title()) << "</title>" << endl;
}
- }
- if (cli.toFirst())
- {
- t << " </section>" << endl;
- }
- }
-}
-
-static void writeInnerNamespaces(const NamespaceSDict *nl,FTextStream &t)
-{
- if (nl)
- {
- NamespaceSDict::Iterator nli(*nl);
- NamespaceDef *nd;
- QCString title = theTranslator->trNamespaces();
-
- if (nli.toFirst())
- {
- t << " <simplesect>" << endl;
- t << " <title> " << title << " </title>" << endl;
- }
- for (nli.toFirst();(nd=nli.current());++nli)
- {
- if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymouse scopes
+ else
{
- t << " <para>" << endl;
- t << " <itemizedlist>" << endl;
- t << " <listitem>" << endl;
- t << " <para>" << "struct <link linkend=\"" << nd->getOutputFileBase() << "\">" << convertToXML(nd->name()) << "</link>";
- t << "</para>" << endl;
- t << " </listitem>" << endl;
- t << " </itemizedlist>" << endl;
- t << " </para>" << endl;
+ t << " <title>" << convertToDocBook(pd->name()) << "</title>" << endl;
}
- }
- if (nli.toFirst())
- {
- t << " </simplesect>" << endl;
+ t << " <xi:include href=\"" << pd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+ t << "</chapter>\n";
}
}
}
-
-static void writeInnerFiles(const FileList *fl,FTextStream &t)
+void DocbookGenerator::writeDoc(DocNode *n,Definition *ctx,MemberDef *)
{
- if (fl)
- {
- QListIterator<FileDef> fli(*fl);
- FileDef *fd;
- QCString title = theTranslator->trFile(TRUE,TRUE);
-
- if (fli.toFirst())
- {
- t << " <simplesect>" << endl;
- t << " <title> " << title << " </title>" << endl;
- }
- for (fli.toFirst();(fd=fli.current());++fli)
- {
- t << " <para>" << endl;
- t << " <itemizedlist>" << endl;
- t << " <listitem>" << endl;
- t << " <para>" << "file <link linkend=\"" << fd->getOutputFileBase() << "\">" << convertToXML(fd->name()) << "</link>";
- t << "</para>" << endl;
- t << " </listitem>" << endl;
- t << " </itemizedlist>" << endl;
- t << " </para>" << endl;
- }
- if (fli.toFirst())
- {
- t << " </simplesect>" << endl;
- }
- }
+DB_GEN_C
+ DocbookDocVisitor *visitor =
+ new DocbookDocVisitor(t,*this);
+ n->accept(visitor);
+ delete visitor;
}
-static void writeInnerPages(const PageSDict *pl,FTextStream &t)
+void DocbookGenerator::startParagraph(const char *)
{
- if (pl)
- {
- PageSDict::Iterator pli(*pl);
- PageDef *pd;
-
- for (pli.toFirst();(pd=pli.current());++pli)
- {
- t << "<xi:include href=\"" << pd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
- }
- }
+DB_GEN_C
+ t << "<para>" << endl;
}
-static void writeInnerGroups(const GroupList *gl,FTextStream &t)
+void DocbookGenerator::endParagraph()
{
- if (gl)
- {
- GroupListIterator gli(*gl);
- GroupDef *sgd;
-
- //Docbook header tags for inner groups
- if (gli.toFirst())
- {
- t << " <simplesect>" << endl;
- t << " <title>" << theTranslator->trModules() << "</title>" << endl;
- t << " </simplesect>" << endl;
- t << " <para>" << endl;
- t << " <itemizedlist>" << endl;
- }
-
- for (gli.toFirst();(sgd=gli.current());++gli)
- {
- t << " <listitem><para><link linkend=\"" << sgd->getOutputFileBase() << "\">" << convertToXML(sgd->groupTitle()) << "</link></para></listitem>" << endl;
- }
-
- //Docbook footer tags for inner groups
- if (gli.toFirst())
- {
- t << " </itemizedlist>" << endl;
- t << " </para>" << endl;
- }
-
- }
+DB_GEN_C
+ t << "</para>" << endl;
}
-
-static void writeInnerDirs(const DirList *dl,FTextStream &t)
+void DocbookGenerator::writeString(const char *text)
{
- if (dl)
- {
- QListIterator<DirDef> subdirs(*dl);
- DirDef *subdir;
- QCString title = theTranslator->trDirectories();
- if (subdirs.toFirst())
- {
- t << " <simplesect>" << endl;
- t << " <title> " << title << " </title>" << endl;
- }
- for (subdirs.toFirst();(subdir=subdirs.current());++subdirs)
- {
- t << " <para>" << endl;
- t << " <itemizedlist>" << endl;
- t << " <listitem>" << endl;
- t << " <para>" << "dir <link linkend=\"" << subdir->getOutputFileBase() << "\">" << convertToXML(subdir->displayName()) << "</link>";
- t << "</para>" << endl;
- t << " </listitem>" << endl;
- t << " </itemizedlist>" << endl;
- t << " </para>" << endl;
- }
- if (subdirs.toFirst())
- {
- t << " </simplesect>" << endl;
- }
- }
+DB_GEN_C
+ t << text;
}
-
-static void writeInnerGroupFiles(const GroupList *gl,FTextStream &t)
+void DocbookGenerator::startMemberHeader(const char *name,int)
{
- if (gl)
- {
- GroupListIterator gli(*gl);
- GroupDef *sgd;
-
- for (gli.toFirst();(sgd=gli.current());++gli)
- {
- t << "<xi:include href=\"" << sgd->getOutputFileBase() << ".xml\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
- }
- }
+DB_GEN_C
+ t << "<simplesect>" << endl;
+ m_inSimpleSect[m_levelListItem] = TRUE;
+ t << " <title>";
}
-static void generateDocbookForClass(ClassDef *cd,FTextStream &ti)
-{
- // + brief description
- // + detailed description
- // + template argument list(s)
- // - include file
- // + member groups
- // + inheritance diagram
- // + list of direct super classes
- // + list of direct sub classes
- // + list of inner classes
- // + collaboration diagram
- // + list of all members
- // + user defined member sections
- // + standard member sections
- // + detailed member documentation
- // - examples using the class
-
- if (cd->isReference()) return; // skip external references.
- if (cd->isHidden()) return; // skip hidden classes.
- if (cd->name().find('@')!=-1) return; // skip anonymous compounds.
- if (cd->templateMaster()!=0) return; // skip generated template instances.
-
- msg("Generating Docbook output for class %s\n",cd->name().data());
-
- QCString fileDocbook=cd->getOutputFileBase()+".xml";
- //Add the file Documentation info to index file
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
-
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- QCString fileName=outputDirectory+"/"+ classOutputFileBase(cd)+".xml";
- QCString relPath = relativePathToRoot(fileName);
- QFile f(fileName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
-
- writeDocbookHeader_ID(t, classOutputFileBase(cd));
+void DocbookGenerator::endMemberHeader()
+{
+DB_GEN_C
+ t << " </title>" << endl;
+}
+void DocbookGenerator::docify(const char *str)
+{
+DB_GEN_C
+ t << convertToDocBook(str);
+}
+void DocbookGenerator::writeObjectLink(const char *ref, const char *f,
+ const char *anchor, const char *text)
+{
+DB_GEN_C
+ if (anchor)
+ if (f) t << "<link linkend=\"_" << stripPath(f) << "_1" << anchor << "\">";
+ else t << "<link linkend=\"_" << anchor << "\">";
+ else
+ t << "<link linkend=\"_" << stripPath(f) << "\">";
+ docify(text);
+ t << "</link>";
+}
+void DocbookGenerator::startMemberList()
+{
+DB_GEN_C
+ t << " <itemizedlist>" << endl;
+ m_levelListItem++;
+}
+void DocbookGenerator::endMemberList()
+{
+DB_GEN_C
+ if (m_inListItem[m_levelListItem]) t << "</listitem>" << endl;
+ m_inListItem[m_levelListItem] = FALSE;
+ t << " </itemizedlist>" << endl;
+ m_levelListItem = (m_levelListItem> 0 ? m_levelListItem - 1 : 0);
+ if (m_inSimpleSect[m_levelListItem]) t << "</simplesect>" << endl;
+ m_inSimpleSect[m_levelListItem] = FALSE;
+}
+void DocbookGenerator::startMemberItem(const char *,int,const char *)
+{
+DB_GEN_C
+ if (m_inListItem[m_levelListItem]) t << "</listitem>" << endl;
+ t << " <listitem><para>";
+ m_inListItem[m_levelListItem] = TRUE;
+}
+void DocbookGenerator::endMemberItem()
+{
+DB_GEN_C
+ t << "</para>" << endl;
+}
+void DocbookGenerator::startBold(void)
+{
+DB_GEN_C
+ t << "<emphasis role=\"strong\">";
+}
+void DocbookGenerator::endBold(void)
+{
+DB_GEN_C
+ t << "</emphasis>";
+}
+void DocbookGenerator::startGroupHeader(int extraIndentLevel)
+{
+DB_GEN_C2("m_inLevel " << m_inLevel)
+DB_GEN_C2("extraIndentLevel " << extraIndentLevel)
+ m_firstMember = TRUE;
+ if (m_inSimpleSect[m_levelListItem]) t << "</simplesect>" << endl;
+ m_inSimpleSect[m_levelListItem] = FALSE;
+ if (m_inLevel != -1) m_inGroup = TRUE;
+ if (m_inLevel == extraIndentLevel) t << "</section>" << endl;
+ m_inLevel = extraIndentLevel;
+ t << "<section>" << endl;
t << "<title>";
- writeDocbookString(t,cd->name());
- t << " " << cd->compoundTypeString() << " Reference";
- t << "</title>" << endl;
-
- IncludeInfo *ii=cd->includeInfo();
- if (ii)
- {
- QCString nm = ii->includeName;
- if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName();
- if (!nm.isEmpty())
- {
- t << "<para>" << endl;
- t << " <programlisting>#include ";
- if (ii->fileDef && !ii->fileDef->isReference()) // TODO: support external references
- {
- t << "<link linkend=\"" << ii->fileDef->getOutputFileBase() << "\">";
- }
- if (ii->local)
- {
- t << "&quot;";
- }
- else
- {
- t << "&lt;";
- }
- t << convertToXML(nm);
- if (ii->local)
- {
- t << "&quot;";
- }
- else
- {
- t << "&gt;";
- }
- if (ii->fileDef && !ii->fileDef->isReference())
- {
- t << "</link>";
- }
- t << "</programlisting>" << endl;
- t << "</para>" << endl;
- }
- }
-
- if (Config_getBool(HAVE_DOT) && (Config_getBool(CLASS_DIAGRAMS) || Config_getBool(CLASS_GRAPH)))
- {
- t << "<para>Inheritance diagram for " << convertToXML(cd->name()) << "</para>" << endl;
- DotClassGraph inheritanceGraph(cd,DotNode::Inheritance);
- inheritanceGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,TRUE,FALSE);
- }
-
- if (Config_getBool(HAVE_DOT) && Config_getBool(COLLABORATION_GRAPH))
- {
- t << "<para>Collaboration diagram for " << convertToXML(cd->name()) << "</para>" << endl;
- DotClassGraph collaborationGraph(cd,DotNode::Collaboration);
- collaborationGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,TRUE,FALSE);
- }
-
- writeInnerClasses(cd->getClassSDict(),t);
-
- writeTemplateList(cd,t);
- if (cd->getMemberGroupSDict())
- {
- MemberGroupSDict::Iterator mgli(*cd->getMemberGroupSDict());
- MemberGroup *mg;
- for (;(mg=mgli.current());++mgli)
- {
- generateDocbookSection(cd,t,mg->members(),"user-defined",0,mg->header(),
- mg->documentation());
- }
- }
+}
+void DocbookGenerator::writeRuler(void)
+{
+DB_GEN_C2("m_inLevel " << m_inLevel)
+DB_GEN_C2("m_inGroup " << m_inGroup)
+ if (m_inGroup) t << "</section>" << endl;
+ m_inGroup = FALSE;
+}
+void DocbookGenerator::endGroupHeader(int)
+{
+DB_GEN_C
+ t << "</title>" << endl;
+}
- QListIterator<MemberList> mli(cd->getMemberLists());
- MemberList *ml;
- for (mli.toFirst();(ml=mli.current());++mli)
+void DocbookGenerator::startParameterList(bool openBracket)
+{
+DB_GEN_C
+ if (openBracket) t << "(";
+}
+void DocbookGenerator::endParameterList()
+{
+DB_GEN_C
+}
+void DocbookGenerator::writeNonBreakableSpace(int n)
+{
+DB_GEN_C
+ for (int i=0;i<n;i++) t << " ";
+}
+void DocbookGenerator::lineBreak(const char *)
+{
+DB_GEN_C
+ t << endl;
+}
+void DocbookGenerator::startTypewriter()
+{
+DB_GEN_C
+ if (!m_denseText) t << "<computeroutput>";
+}
+void DocbookGenerator::endTypewriter()
+{
+DB_GEN_C
+ if (!m_denseText) t << "</computeroutput>" << endl;
+}
+void DocbookGenerator::startTextBlock(bool dense)
+{
+DB_GEN_C
+ if (dense)
{
- if ((ml->listType()&MemberListType_detailedLists)==0)
- {
- generateDocbookSection(cd,t,ml,g_docbookSectionMapper.find(ml->listType()));
- }
+ m_denseText = TRUE;
+ t << "<programlisting>";
}
-
- if(Config_getBool(REPEAT_BRIEF))
+}
+void DocbookGenerator::endTextBlock(bool dense)
+{
+DB_GEN_C
+ if (m_denseText)
{
- if (cd->briefDescription())
- {
- t << " <simplesect>" << endl;
- // A title as 'Brief Description' may not be necessary.
- //t << " <title>" << theTranslator->trBriefDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,cd->briefFile(),cd->briefLine(),cd,0,cd->briefDescription());
- t << " </simplesect>" << endl;
- }
+ m_denseText = FALSE;
+ t << "</programlisting>";
}
-
- if (cd->documentation())
+}
+void DocbookGenerator::startMemberDoc(const char *clname, const char *memname, const char *anchor, const char *title,
+ int memCount, int memTotal, bool showInline)
+{
+DB_GEN_C2("m_inLevel " << m_inLevel)
+ t << " <section>" << endl;
+ t << " <title>" << convertToDocBook(title);
+ if (memTotal>1)
{
- t << " <simplesect>" << endl;
- t << " <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,cd->docFile(),cd->docLine(),cd,0,cd->documentation());
- t << " <para>Definition at line " << cd->getDefLine() << " of file " << stripPath(cd->getDefFileName()) << "</para>" << endl;
- t << " <para>The Documentation for this struct was generated from the following file: </para>" << endl;
- t << " <para><itemizedlist><listitem><para>" << stripPath(cd->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
- t << " </simplesect>" << endl;
+ t << "<computeroutput>[" << memCount << "/" << memTotal << "]</computeroutput>";
}
- for (mli.toFirst();(ml=mli.current());++mli)
+ t << "</title>" << endl;
+ if (memname && memname[0]!='@')
{
- if ((ml->listType()&MemberListType_detailedLists)==0)
- {
- generateDocbookSection(cd,t,ml,g_docbookSectionMapper.find(ml->listType()),1);
- }
+ addIndexTerm(t,memname,clname);
+ addIndexTerm(t,clname,memname);
}
-
- /*// TODO: Handling of Inheritance and Colloboration graph for Docbook to be implemented
- DotClassGraph inheritanceGraph(cd,DotNode::Inheritance);
- if (!inheritanceGraph.isTrivial())
- {
- t << " <inheritancegraph>" << endl;
- inheritanceGraph.writeDocbook(t);
- t << " </inheritancegraph>" << endl;
- }
- DotClassGraph collaborationGraph(cd,DotNode::Collaboration);
- if (!collaborationGraph.isTrivial())
- {
- t << " <collaborationgraph>" << endl;
- collaborationGraph.writeDocbook(t);
- t << " </collaborationgraph>" << endl;
- }
- t << " <location file=\""
- << cd->getDefFileName() << "\" line=\""
- << cd->getDefLine() << "\"";
- if (cd->getStartBodyLine()!=-1)
- {
- FileDef *bodyDef = cd->getBodyDef();
- if (bodyDef)
- {
- t << " bodyfile=\"" << bodyDef->absFilePath() << "\"";
- }
- t << " bodystart=\"" << cd->getStartBodyLine() << "\" bodyend=\""
- << cd->getEndBodyLine() << "\"";
- }
- t << "/>" << endl;
- writeListOfAllMembers(cd,t);
- */
-
- t << "</section>" << endl;
-
}
-
-static void generateDocbookForNamespace(NamespaceDef *nd,FTextStream &ti)
-{
- // + contained class definitions
- // + contained namespace definitions
- // + member groups
- // + normal members
- // + brief desc
- // + detailed desc
- // + location
- // - files containing (parts of) the namespace definition
-
- if (nd->isReference() || nd->isHidden()) return; // skip external references
-
- QCString fileDocbook=nd->getOutputFileBase()+".xml";
- //Add the file Documentation info to index file
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
-
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- QCString fileName=outputDirectory+"/"+nd->getOutputFileBase()+".xml";
- QFile f(fileName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
-
- writeDocbookHeader_ID(t, nd->getOutputFileBase());
+void DocbookGenerator::endMemberDoc(bool)
+{
+DB_GEN_C
+ t << "</computeroutput></para>";
+}
+void DocbookGenerator::startTitleHead(const char *)
+{
+DB_GEN_C
t << "<title>";
- writeDocbookString(t,nd->name());
+}
+void DocbookGenerator::endTitleHead(const char *fileName,const char *name)
+{
+DB_GEN_C
t << "</title>" << endl;
-
- writeInnerClasses(nd->getClassSDict(),t);
- writeInnerNamespaces(nd->getNamespaceSDict(),t);
-
- if (nd->getMemberGroupSDict())
- {
- MemberGroupSDict::Iterator mgli(*nd->getMemberGroupSDict());
- MemberGroup *mg;
- for (;(mg=mgli.current());++mgli)
- {
- generateDocbookSection(nd,t,mg->members(),"user-defined",0,mg->header(),
- mg->documentation());
- }
- }
-
- QListIterator<MemberList> mli(nd->getMemberLists());
- MemberList *ml;
- for (mli.toFirst();(ml=mli.current());++mli)
+ if (name) addIndexTerm(t, name);
+}
+void DocbookGenerator::startDoxyAnchor(const char *fName,const char *manName,
+ const char *anchor,const char *name,
+ const char *args)
+{
+DB_GEN_C
+ if (!m_inListItem[m_levelListItem] && !m_descTable)
{
- if ((ml->listType()&MemberListType_declarationLists)!=0)
- {
- generateDocbookSection(nd,t,ml,g_docbookSectionMapper.find(ml->listType()));
- }
+ if (!m_firstMember) t << " </section>";
+ m_firstMember = FALSE;
}
-
- if(Config_getBool(REPEAT_BRIEF))
+ if (anchor)
{
- if (nd->briefDescription())
- {
- t << " <simplesect>" << endl;
- //t << " <title>" << theTranslator->trBriefDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,nd->briefFile(),nd->briefLine(),nd,0,nd->briefDescription());
- t << " </simplesect>" << endl;
- }
+ t << "<anchor xml:id=\"_" << stripPath(fName) << "_1" << anchor << "\"/>";
}
-
- if (nd->documentation())
- {
- t << " <simplesect>" << endl;
- t << " <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,nd->docFile(),nd->docLine(),nd,0,nd->documentation());
- t << " <para>Definition at line " << nd->getDefLine() << " of file " << stripPath(nd->getDefFileName()) << "</para>" << endl;
- t << " <para>The Documentation for this struct was generated from the following file: </para>" << endl;
- t << " <para><itemizedlist><listitem><para>" << stripPath(nd->getDefFileName()) << "</para></listitem></itemizedlist></para>" << endl;
- t << " </simplesect>" << endl;
- }
- t << "</section>" << endl;
}
-
-static void generateDocbookForFile(FileDef *fd,FTextStream &ti)
-{
- // + includes files
- // + includedby files
- // + include graph
- // + included by graph
- // + contained class definitions
- // + contained namespace definitions
- // + member groups
- // + normal members
- // + brief desc
- // + detailed desc
- // + source code
- // + location
- // - number of lines
-
- if (fd->isReference()) return; // skip external references
-
- QCString fileDocbook=fd->getOutputFileBase()+".xml";
- //Add the file Documentation info to index file
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
-
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- QCString fileName=outputDirectory+"/"+fd->getOutputFileBase()+".xml";
- QCString relPath = relativePathToRoot(fileName);
-
- QFile f(fileName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
- writeDocbookHeader_ID(t, fd->getOutputFileBase());
-
- t << " <title>";
- writeDocbookString(t,fd->name());
- t << " File Reference";
+void DocbookGenerator::endDoxyAnchor(const char *fileName,const char *anchor)
+{
+DB_GEN_C
+}
+void DocbookGenerator::startMemberDocName(bool)
+{
+DB_GEN_C
+ t << "<para><computeroutput>";
+}
+void DocbookGenerator::endMemberDocName()
+{
+DB_GEN_C
+}
+void DocbookGenerator::startMemberGroupHeader(bool hasHeader)
+{
+DB_GEN_C
+ t << "<simplesect><title>";
+}
+void DocbookGenerator::endMemberGroupHeader()
+{
+DB_GEN_C
t << "</title>" << endl;
-
- IncludeInfo *inc;
-
- if (fd->includeFileList())
- {
- QListIterator<IncludeInfo> ili1(*fd->includeFileList());
- for (ili1.toFirst();(inc=ili1.current());++ili1)
- {
- t << " <programlisting>#include ";
- if (inc->local)
- {
- t << "&quot;";
- }
- else
- {
- t << "&lt;";
- }
- t << convertToXML(inc->includeName);
- if (inc->local)
- {
- t << "&quot;";
- }
- else
- {
- t << "&gt;";
- }
- t << "</programlisting>" << endl;
- }
- }
- if (Config_getBool(HAVE_DOT))
- {
- if (Config_getBool(INCLUDE_GRAPH))
- {
- t << "<para>Include dependency diagram for " << convertToXML(fd->name()) << "</para>" << endl;
- DotInclDepGraph idepGraph(fd, FALSE);
- idepGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
- }
- if (Config_getBool(INCLUDED_BY_GRAPH))
- {
- t << "<para>Included by dependency diagram for " << convertToXML(fd->name()) << "</para>" << endl;
- DotInclDepGraph ibdepGraph(fd, TRUE);
- ibdepGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
- }
- }
-
- if (fd->getClassSDict())
- {
- writeInnerClasses(fd->getClassSDict(),t);
- }
- if (fd->getNamespaceSDict())
- {
- writeInnerNamespaces(fd->getNamespaceSDict(),t);
- }
-
- if (fd->getMemberGroupSDict())
- {
- MemberGroupSDict::Iterator mgli(*fd->getMemberGroupSDict());
- MemberGroup *mg;
- for (;(mg=mgli.current());++mgli)
- {
- generateDocbookSection(fd,t,mg->members(),"user-defined",0,mg->header(),
- mg->documentation());
- }
- }
-
- QListIterator<MemberList> mli(fd->getMemberLists());
- MemberList *ml;
- for (mli.toFirst();(ml=mli.current());++mli)
- {
- if ((ml->listType()&MemberListType_declarationLists)!=0)
- {
- generateDocbookSection(fd,t,ml,g_docbookSectionMapper.find(ml->listType()));
- }
- }
-
- t << " <simplesect>" << endl;
- t << " <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,fd->briefFile(),fd->briefLine(),fd,0,fd->briefDescription());
- writeDocbookDocBlock(t,fd->docFile(),fd->docLine(),fd,0,fd->documentation());
- if (Config_getBool(FULL_PATH_NAMES))
- {
- t << " <para>Definition in file " << fd->getDefFileName() << "</para>" << endl;
- }
- else
- {
- t << " <para>Definition in file " << stripPath(fd->getDefFileName()) << "</para>" << endl;
- }
- t << " </simplesect>" << endl;
-
- if (Config_getBool(DOCBOOK_PROGRAMLISTING))
- {
- t << " <literallayout><computeroutput>" << endl;
- writeDocbookCodeBlock(t,fd);
- t << " </computeroutput></literallayout>" << endl;
- }
-
- t << "</section>" << endl;
+}
+void DocbookGenerator::startMemberGroup()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endMemberGroup(bool)
+{
+DB_GEN_C
+ t << "</simplesect>" << endl;
+}
+void DocbookGenerator::startClassDiagram()
+{
+DB_GEN_C
+ t << "<para>";
}
-static void generateDocbookForGroup(GroupDef *gd,FTextStream &ti)
-{
- // + members
- // + member groups
- // + files
- // + classes
- // + namespaces
- // - packages
- // + pages
- // + child groups
- // - examples
- // + brief description
- // + detailed description
-
- if (gd->isReference()) return; // skip external references
-
- if (!gd->isASubGroup())
- {
- QCString fileDocbook=gd->getOutputFileBase()+".xml";
- //Add the file Documentation info to index file
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
- }
-
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- QCString fileName=outputDirectory+"/"+gd->getOutputFileBase()+".xml";
- QCString relPath = relativePathToRoot(fileName);
-
- QFile f(fileName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
-
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
- writeDocbookHeader_ID(t, gd->getOutputFileBase());
-
- t << " <title>" << convertToXML(gd->groupTitle()) << "</title>" << endl;
+void DocbookGenerator::endClassDiagram(const ClassDiagram &d, const char *fileName,const char *)
+{
+DB_GEN_C
+ visitPreStart(t, FALSE, relPath + fileName + ".png", NULL, NULL);
+ d.writeImage(t,dir,relPath,fileName,FALSE);
+ visitPostEnd(t, FALSE);
+ t << "</para>" << endl;
+}
+void DocbookGenerator::startLabels()
+{
+DB_GEN_C
+}
- if (Config_getBool(GROUP_GRAPHS) && Config_getBool(HAVE_DOT))
- {
- t << "<para>Collaboration diagram for " << convertToXML(gd->groupTitle()) << "</para>" << endl;
- DotGroupCollaboration collaborationGraph(gd);
- collaborationGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
- }
+void DocbookGenerator::writeLabel(const char *l,bool isLast)
+{
+DB_GEN_C
+ t << "<computeroutput>[" << l << "]</computeroutput>";
+ if (!isLast) t << ", ";
+}
- if (gd->briefDescription())
- {
- //t << " <section>" << endl;
- //t << " <title>" << theTranslator->trBriefDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,gd->briefFile(),gd->briefLine(),gd,0,gd->briefDescription());
- //t << " </section>" << endl;
- }
+void DocbookGenerator::endLabels()
+{
+DB_GEN_C
+}
+void DocbookGenerator::startExamples()
+{
+DB_GEN_C
+ t << "<simplesect><title>";
+ docify(theTranslator->trExamples());
+ t << "</title>";
+}
- if (gd->documentation())
+void DocbookGenerator::endExamples()
+{
+DB_GEN_C
+ t << "</simplesect>" << endl;
+}
+void DocbookGenerator::startSubsubsection(void)
+{
+DB_GEN_C
+ t << "<simplesect><title>";
+}
+void DocbookGenerator::endSubsubsection(void)
+{
+DB_GEN_C
+ t << "</title></simplesect>" << endl;
+}
+void DocbookGenerator::writeChar(char c)
+{
+DB_GEN_C
+ char cs[2];
+ cs[0]=c;
+ cs[1]=0;
+ docify(cs);
+}
+void DocbookGenerator::startMemberDocPrefixItem()
+{
+DB_GEN_C
+ t << "<computeroutput>";
+}
+void DocbookGenerator::endMemberDocPrefixItem()
+{
+DB_GEN_C
+ t << "</computeroutput>";
+}
+void DocbookGenerator::exceptionEntry(const char* prefix,bool closeBracket)
+{
+DB_GEN_C
+ if (prefix)
+ t << " " << prefix << "(";
+ else if (closeBracket)
+ t << ")";
+ t << " ";
+}
+void DocbookGenerator::startParameterName(bool)
+{
+DB_GEN_C
+ t << " ";
+}
+void DocbookGenerator::endParameterName(bool last,bool /*emptyList*/,bool closeBracket)
+{
+DB_GEN_C
+ if (last)
{
- t << " <section>" << endl;
- t << " <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,gd->docFile(),gd->docLine(),gd,0,gd->documentation());
- t << " </section>" << endl;
+ if (closeBracket) t << ")";
}
+}
+void DocbookGenerator::startCodeFragment()
+{
+DB_GEN_C
+ t << "<programlisting>";
+}
+void DocbookGenerator::endCodeFragment()
+{
+DB_GEN_C
+ t << "</programlisting>";
+}
+void DocbookGenerator::startMemberTemplateParams()
+{
+DB_GEN_C
+}
- writeInnerFiles(gd->getFiles(),t);
- writeInnerClasses(gd->getClasses(),t);
- writeInnerNamespaces(gd->getNamespaces(),t);
- writeInnerPages(gd->getPages(),t);
- writeInnerGroups(gd->getSubGroups(),t);
-
- if (gd->getMemberGroupSDict())
- {
- MemberGroupSDict::Iterator mgli(*gd->getMemberGroupSDict());
- MemberGroup *mg;
- for (;(mg=mgli.current());++mgli)
- {
- generateDocbookSection(gd,t,mg->members(),"user-defined",0,mg->header(),
- mg->documentation());
- }
- }
+void DocbookGenerator::endMemberTemplateParams(const char *,const char *)
+{
+DB_GEN_C
+ t << "</para>";
+ t << "<para>";
+}
+void DocbookGenerator::startSection(const char *lab,const char *,SectionInfo::SectionType type)
+{
+DB_GEN_C
+ t << " <section xml:id=\"_" << stripPath(lab) << "\">";
+ t << "<title>";
+}
+void DocbookGenerator::endSection(const char *lab,SectionInfo::SectionType)
+{
+DB_GEN_C
+ t << "</title>";
+ t << " </section>";
+}
+void DocbookGenerator::addIndexItem(const char *prim,const char *sec)
+{
+DB_GEN_C
+ addIndexTerm(t, prim, sec);
+}
- QListIterator<MemberList> mli(gd->getMemberLists());
- MemberList *ml;
- for (mli.toFirst();(ml=mli.current());++mli)
- {
- if ((ml->listType()&MemberListType_declarationLists)!=0)
- {
- generateDocbookSection(gd,t,ml,g_docbookSectionMapper.find(ml->listType()));
- }
- }
- for (mli.toFirst();(ml=mli.current());++mli)
+void DocbookGenerator::startDescTable(const char *title)
+{
+DB_GEN_C
+ int ncols = 2;
+ t << "<informaltable frame=\"all\">" << endl;
+ if (title)t << "<title>" << convertToDocBook(title) << "</title>" << endl;
+ t << " <tgroup cols=\"" << ncols << "\" align=\"left\" colsep=\"1\" rowsep=\"1\">" << endl;
+ for (int i = 0; i < ncols; i++)
{
- if ((ml->listType()&MemberListType_declarationLists)!=0)
- {
- generateDocbookSection(gd,t,ml,g_docbookSectionMapper.find(ml->listType()),1);
- }
+ t << " <colspec colname='c" << i+1 << "'/>\n";
}
+ t << "<tbody>\n";
+ m_descTable = TRUE;
+}
- writeInnerGroupFiles(gd->getSubGroups(),t);
-
- t << "</section>" << endl;
-
+void DocbookGenerator::endDescTable()
+{
+DB_GEN_C
+ t << " </tbody>" << endl;
+ t << " </tgroup>" << endl;
+ t << "</informaltable>" << endl;
+ m_descTable = FALSE;
}
-static void generateDocbookForDir(DirDef *dd,FTextStream &ti)
+void DocbookGenerator::startDescTableRow()
{
- if (dd->isReference()) return; // skip external references
+DB_GEN_C
+ t << "<row>";
+ t << "<entry>";
+}
- QCString fileDocbook=dd->getOutputFileBase()+".xml";
- //Add the file Documentation info to index file
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
+void DocbookGenerator::endDescTableRow()
+{
+DB_GEN_C
+ t << "</row>";
+}
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- QCString fileName=outputDirectory+"/"+dd->getOutputFileBase()+".xml";
- QFile f(fileName);
- QCString relPath = relativePathToRoot(fileName);
+void DocbookGenerator::startDescTableTitle()
+{
+DB_GEN_C
+}
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
+void DocbookGenerator::endDescTableTitle()
+{
+DB_GEN_C
+}
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
- writeDocbookHeader_ID(t, dd->getOutputFileBase());
+void DocbookGenerator::startDescTableData()
+{
+DB_GEN_C
+ t << "</entry><entry>";
+}
- t << " <title>";
- t << theTranslator->trDirReference(dd->displayName());
+void DocbookGenerator::endDescTableData()
+{
+DB_GEN_C
+ t << "</entry>";
+}
+void DocbookGenerator::startGroupCollaboration()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endGroupCollaboration(const DotGroupCollaboration &g)
+{
+DB_GEN_C
+ g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
+}
+void DocbookGenerator::startDotGraph()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endDotGraph(const DotClassGraph &g)
+{
+DB_GEN_C
+ g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,TRUE,FALSE);
+}
+void DocbookGenerator::startInclDepGraph()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endInclDepGraph(const DotInclDepGraph &g)
+{
+DB_GEN_C
+ QCString fn = g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT), fileName,relPath,FALSE);
+}
+void DocbookGenerator::startCallGraph()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endCallGraph(const DotCallGraph &g)
+{
+DB_GEN_C
+ QCString fn = g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT), fileName,relPath,FALSE);
+}
+void DocbookGenerator::startDirDepGraph()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endDirDepGraph(const DotDirDeps &g)
+{
+DB_GEN_C
+ QCString fn = g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT), fileName,relPath,FALSE);
+}
+void DocbookGenerator::startMemberDocList()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endMemberDocList()
+{
+DB_GEN_C
+ m_inGroup = TRUE;
+}
+void DocbookGenerator::startConstraintList(const char *header)
+{
+DB_GEN_C
+ t << "<simplesect><title>";
+ docify(header);
t << "</title>" << endl;
- if (Config_getBool(DIRECTORY_GRAPH) && Config_getBool(HAVE_DOT))
- {
- t << "<para>Directory dependency diagram for " << convertToXML(dd->displayName()) << "</para>" << endl;
- DotDirDeps dirdepGraph(dd);
- dirdepGraph.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
- }
-
- writeInnerDirs(&dd->subDirs(),t);
- writeInnerFiles(dd->getFiles(),t);
-
- t << " <simplesect>" << endl;
- t << " <title>" << theTranslator->trDetailedDescription() << "</title>" << endl;
- writeDocbookDocBlock(t,dd->briefFile(),dd->briefLine(),dd,0,dd->briefDescription());
- writeDocbookDocBlock(t,dd->docFile(),dd->docLine(),dd,0,dd->documentation());
- t << " <para>Directory location is " << dd->name() << "</para>" << endl;
- t << " </simplesect>" << endl;
-
- t << "</section>" << endl;
}
-
-static void generateDocbookForPage(PageDef *pd,FTextStream &ti,bool isExample)
+void DocbookGenerator::startConstraintParam()
{
- // + name
- // + title
- // + documentation
-
- if (pd->isReference()) return;
-
- QCString pageName = pd->getOutputFileBase();
- if (pd->getGroupDef())
- {
- pageName+=(QCString)"_"+pd->name();
- }
- if (pageName=="index")
- {
- pageName="mainpage"; // to prevent overwriting the generated index page.
- }
-
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- QCString fileName=outputDirectory+"/"+pageName+".xml";
- QFile f(fileName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
-
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
-
- if(isExample)
- {
- QCString fileDocbook=pageName+".xml";
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
- }
-
- if (!pd->hasParentPage() && !isExample)
- {
- QCString fileDocbook=pageName+".xml";
- //Add the file Documentation info to index file
- ti << " <xi:include href=\"" << fileDocbook << "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\"/>" << endl;
- writeDocbookHeaderMainpage(t);
- }
- else
- {
- QCString pid;
- if(isExample)
- {
- pid = pageName;
- }
- else
- {
- pid = pageName+"_1"+pageName;
- }
- writeDocbookHeader_ID(t, pid);
- }
-
- SectionInfo *si = Doxygen::sectionDict->find(pd->name());
- if (si)
- {
- t << " <title>" << convertToXML(si->title) << "</title>" << endl;
- }
- else
- {
- t << " <title>" << convertToXML(pd->name()) << "</title>" << endl;
- }
-
- if (isExample)
- {
- writeDocbookDocBlock(t,pd->docFile(),pd->docLine(),pd,0,
- pd->documentation()+"\n\\include "+pd->name());
- }
- else
- {
- writeDocbookDocBlock(t,pd->docFile(),pd->docLine(),pd,0,
- pd->documentation());
- }
- writeInnerPages(pd->getSubPages(),t);
-
- if (!pd->hasParentPage() && !isExample)
- {
- t << endl << "</chapter>" << endl;
- }
- else
- {
- t << endl << "</section>" << endl;
- }
+DB_GEN_C
+ t << "<para><emphasis role=\"strong\">";
}
-
-void generateDocbook()
+void DocbookGenerator::endConstraintParam()
{
-
- // + classes
- // + namespaces
- // + files
- // + groups
- // + related pages
- // - examples
-
- QCString outputDirectory = Config_getString(DOCBOOK_OUTPUT);
- if (outputDirectory.isEmpty())
- {
- outputDirectory=QDir::currentDirPath().utf8();
- }
- else
- {
- QDir dir(outputDirectory);
- if (!dir.exists())
- {
- dir.setPath(QDir::currentDirPath());
- if (!dir.mkdir(outputDirectory))
- {
- err("tag DOCBOOK_OUTPUT: Output directory `%s' does not "
- "exist and cannot be created\n",outputDirectory.data());
- exit(1);
- }
- else
- {
- msg("Notice: Output directory `%s' does not exist. "
- "I have created it for you.\n", outputDirectory.data());
- }
- dir.cd(outputDirectory);
- }
- outputDirectory=dir.absPath().utf8();
- }
-
- QDir dir(outputDirectory);
- if (!dir.exists())
- {
- dir.setPath(QDir::currentDirPath());
- if (!dir.mkdir(outputDirectory))
- {
- err("Cannot create directory %s\n",outputDirectory.data());
- return;
- }
- }
- QDir docbookDir(outputDirectory);
- createSubDirs(docbookDir);
-
- QCString fileName=outputDirectory+"/index.xml";
- QCString dbk_projectName = Config_getString(PROJECT_NAME);
- QFile f(fileName);
-
- f.setName(fileName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot open file %s for writing!\n",fileName.data());
- return;
- }
- FTextStream t(&f);
- //t.setEncoding(FTextStream::UnicodeUTF8);
-
- // write index header for Docbook which calls the structure file
- t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
- t << "<book xmlns=\"http://docbook.org/ns/docbook\" version=\"5.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" << endl;
- t << " <info>" << endl;
- t << " <title>" << dbk_projectName << "</title>" << endl;
- t << " </info>" << endl;
-
- // NAMESPACE DOCUMENTATION
- NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
- NamespaceDef *nd;
-
- //Namespace Documentation index header
- if (nli.toFirst())
- {
- t << " <chapter>" << endl;
- t << " <title>Namespace Documentation</title>" << endl;
- }
-
- for (nli.toFirst();(nd=nli.current());++nli)
- {
- msg("Generating Docbook output for namespace %s\n",nd->name().data());
- generateDocbookForNamespace(nd,t);
- }
-
- //Namespace Documentation index footer
- if (nli.toFirst())
- {
- t << " </chapter>" << endl;
- }
-
- /** MAINPAGE DOCUMENTATION **/
-
- if (Doxygen::mainPage)
- {
- msg("Generating Docbook output for the main page\n");
- generateDocbookForPage(Doxygen::mainPage,t,FALSE);
- }
-
- // PAGE DOCUMENTATION
- {
- PageSDict::Iterator pdi(*Doxygen::pageSDict);
- PageDef *pd=0;
-
- for (pdi.toFirst();(pd=pdi.current());++pdi)
- {
- msg("Generating Docbook output for page %s\n",pd->name().data());
- generateDocbookForPage(pd,t,FALSE);
- }
- }
-
- /** MODULE GROUP DOCUMENTATION **/
-
- GroupSDict::Iterator gli(*Doxygen::groupSDict);
- GroupDef *gd;
-
- //Module group Documentation index header
- if (gli.toFirst())
- {
- t << " <chapter>" << endl;
- t << " <title>" << theTranslator->trModuleDocumentation() << "</title>" << endl;
- }
-
- for (;(gd=gli.current());++gli)
- {
- msg("Generating Docbook output for group %s\n",gd->name().data());
- generateDocbookForGroup(gd,t);
- }
-
- //Module group Documentation index footer
- if (gli.toFirst())
- {
- t << " </chapter>" << endl;
- }
-
- //CLASS DOCUMENTATION
-
- {
- ClassSDict::Iterator cli(*Doxygen::classSDict);
- ClassDef *cd;
-
- //Class Documentation index header
- if (cli.toFirst())
- {
- t << " <chapter>" << endl;
- t << " <title>" << theTranslator->trClassDocumentation() << "</title>" << endl;
- }
-
- for (cli.toFirst();(cd=cli.current());++cli)
- {
- generateDocbookForClass(cd,t);
- }
-
- //Class Documentation index footer
- if (cli.toFirst())
- {
- t << " </chapter>" << endl;
- }
- }
-
- // FILE DOCUMENTATION
-
- static bool showFiles = Config_getBool(SHOW_FILES);
- if (showFiles)
- {
- FileNameListIterator fnli(*Doxygen::inputNameList);
- FileName *fn;
-
- //File Documentation index header
- if (fnli.toFirst())
- {
- t << " <chapter>" << endl;
- t << " <title>" << theTranslator->trFileDocumentation() << "</title>" << endl;
- }
-
- for (;(fn=fnli.current());++fnli)
- {
- FileNameIterator fni(*fn);
- FileDef *fd;
- for (;(fd=fni.current());++fni)
- {
- msg("Generating Docbook output for file %s\n",fd->name().data());
- generateDocbookForFile(fd,t);
- }
- }
-
- //File Documentation index footer
- if (fnli.toFirst())
- {
- t << " </chapter>" << endl;
- }
- }
-
- // DIRECTORY DOCUMENTATION
- if (Config_getBool(DIRECTORY_GRAPH) && Config_getBool(HAVE_DOT))
- {
- DirDef *dir;
- DirSDict::Iterator sdi(*Doxygen::directories);
-
- //Directory Documentation index header
- if (sdi.toFirst())
- {
- t << " <chapter>" << endl;
- t << " <title>" << theTranslator->trDirDocumentation() << "</title>" << endl;
- }
-
- for (sdi.toFirst();(dir=sdi.current());++sdi)
- {
- msg("Generate Docbook output for dir %s\n",dir->name().data());
- generateDocbookForDir(dir,t);
- }
-
- //Module group Documentation index footer
- if (sdi.toFirst())
- {
- t << " </chapter>" << endl;
- }
- }
-
- // EXAMPLE PAGE DOCUMENTATION
-
- {
- PageSDict::Iterator pdi(*Doxygen::exampleSDict);
- PageDef *pd=0;
-
- //Example Page Documentation index header
- if (pdi.toFirst())
- {
- t << " <chapter>" << endl;
- t << " <title>" << theTranslator->trExampleDocumentation() << "</title>" << endl;
- }
-
- for (pdi.toFirst();(pd=pdi.current());++pdi)
- {
- msg("Generating Docbook output for example %s\n",pd->name().data());
- generateDocbookForPage(pd,t,TRUE);
- }
-
- //Example Page Documentation index footer
- if (pdi.toFirst())
- {
- t << " </chapter>" << endl;
- }
- }
-
- t << "</book>" << endl;
-
+DB_GEN_C
+}
+void DocbookGenerator::startConstraintType()
+{
+DB_GEN_C
+ t << ":";
+}
+void DocbookGenerator::endConstraintType()
+{
+DB_GEN_C
+ t << "</emphasis></para>" << endl;
+}
+void DocbookGenerator::startConstraintDocs()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endConstraintDocs()
+{
+DB_GEN_C
+}
+void DocbookGenerator::endConstraintList()
+{
+DB_GEN_C
+ t << "</simplesect>" << endl;
}
-
-
diff --git a/src/docbookgen.h b/src/docbookgen.h
index 866d056..08255a1 100644
--- a/src/docbookgen.h
+++ b/src/docbookgen.h
@@ -15,6 +15,349 @@
#ifndef DOCBOOKGEN_H
#define DOCBOOKGEN_H
-void generateDocbook();
+#include "outputgen.h"
+
+class DocbookCodeGenerator : public CodeOutputInterface
+{
+ public:
+ DocbookCodeGenerator(FTextStream &t);
+ DocbookCodeGenerator();
+ virtual ~DocbookCodeGenerator();
+ void setTextStream(FTextStream &t)
+ {
+ m_streamSet = t.device()!=0;
+ m_t.setDevice(t.device());
+ }
+ void setRelativePath(const QCString &path) { m_relPath = path; }
+ void setSourceFileName(const QCString &sourceFileName) { m_sourceFileName = sourceFileName; }
+ QCString sourceFileName() { return m_sourceFileName; }
+
+ void codify(const char *text);
+ void writeCodeLink(const char *ref,const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip);
+ void writeCodeLinkLine(const char *ref,const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip);
+ void writeTooltip(const char *, const DocLinkInfo &, const char *,
+ const char *, const SourceLinkInfo &, const SourceLinkInfo &
+ );
+ void startCodeLine(bool);
+ void endCodeLine();
+ void startFontClass(const char *colorClass);
+ void endFontClass();
+ void writeCodeAnchor(const char *);
+ void writeLineNumber(const char *extRef,const char *compId,
+ const char *anchorId,int l);
+ void setCurrentDoc(Definition *,const char *,bool);
+ void addWord(const char *,bool);
+ void finish();
+ void startCodeFragment();
+ void endCodeFragment();
+
+ private:
+ FTextStream m_t;
+ bool m_streamSet;
+ QCString m_refId;
+ QCString m_external;
+ int m_lineNumber;
+ int m_col;
+ bool m_insideCodeLine;
+ bool m_insideSpecialHL;
+ QCString m_relPath;
+ QCString m_sourceFileName;
+ bool m_prettyCode;
+};
+
+
+#if 0
+// define for cases that have been implemented with an empty body
+#define DB_GEN_EMPTY t << "<!-- DBG_GEN_head_check " << __LINE__ << " -->\n";
+#else
+#define DB_GEN_EMPTY
+#endif
+
+#if 0
+// Generic debug statements
+#define DB_GEN_H DB_GEN_H1(t)
+#define DB_GEN_H1(x) x << "<!-- DBG_GEN_head " << __LINE__ << " -->\n";
+#define DB_GEN_H2(y) DB_GEN_H2a(t,y)
+#define DB_GEN_H2a(x,y) x << "<!-- DBG_GEN_head " << __LINE__ << " " << y << " -->\n";
+// define for cases that have NOT yet been implemented / considered
+#define DB_GEN_NEW fprintf(stderr,"DBG_GEN_head %d\n",__LINE__); DB_GEN_H
+#else
+#define DB_GEN_H
+#define DB_GEN_H1(x)
+#define DB_GEN_H2(y)
+#define DB_GEN_H2a(x,y)
+#define DB_GEN_NEW
+#endif
+
+class DocbookGenerator : public OutputGenerator
+{
+ public:
+ DocbookGenerator();
+ ~DocbookGenerator();
+ static void init();
+
+ ///////////////////////////////////////////////////////////////
+ // generic generator methods
+ ///////////////////////////////////////////////////////////////
+ void enable()
+ { if (genStack->top()) active=*genStack->top(); else active=TRUE; }
+ void disable() { active=FALSE; }
+ void enableIf(OutputType o) { if (o==Docbook) enable(); }
+ void disableIf(OutputType o) { if (o==Docbook) disable(); }
+ void disableIfNot(OutputType o) { if (o!=Docbook) disable(); }
+ bool isEnabled(OutputType o) { return (o==Docbook && active); }
+ OutputGenerator *get(OutputType o) { return (o==Docbook) ? this : 0; }
+
+ // --- CodeOutputInterface
+ void codify(const char *text)
+ { m_codeGen.codify(text); }
+ void writeCodeLink(const char *ref, const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip)
+ { m_codeGen.writeCodeLink(ref,file,anchor,name,tooltip); }
+ void writeLineNumber(const char *ref,const char *file,const char *anchor,int lineNumber)
+ { m_codeGen.writeLineNumber(ref,file,anchor,lineNumber); }
+ void writeTooltip(const char *id, const DocLinkInfo &docInfo, const char *decl,
+ const char *desc, const SourceLinkInfo &defInfo, const SourceLinkInfo &declInfo
+ )
+ { m_codeGen.writeTooltip(id,docInfo,decl,desc,defInfo,declInfo); }
+ void startCodeLine(bool hasLineNumbers)
+ { m_codeGen.startCodeLine(hasLineNumbers); }
+ void endCodeLine()
+ { m_codeGen.endCodeLine(); }
+ void startFontClass(const char *s)
+ { m_codeGen.startFontClass(s); }
+ void endFontClass()
+ { m_codeGen.endFontClass(); }
+ void writeCodeAnchor(const char *anchor)
+ { m_codeGen.writeCodeAnchor(anchor); }
+ // ---------------------------
+
+ void writeDoc(DocNode *,Definition *ctx,MemberDef *md);
+
+ ///////////////////////////////////////////////////////////////
+ // structural output interface
+ ///////////////////////////////////////////////////////////////
+ void startFile(const char *name,const char *manName,
+ const char *title);
+ void writeSearchInfo(){DB_GEN_EMPTY};
+ void writeFooter(const char *navPath){DB_GEN_NEW};
+ void endFile();
+ void startIndexSection(IndexSections);
+ void endIndexSection(IndexSections);
+ void writePageLink(const char *,bool);
+ void startProjectNumber(){DB_GEN_NEW};
+ void endProjectNumber(){DB_GEN_NEW};
+ void writeStyleInfo(int part){DB_GEN_EMPTY};
+ void startTitleHead(const char *);
+ void endTitleHead(const char *fileName,const char *name);
+ void startIndexListItem(){DB_GEN_NEW};
+ void endIndexListItem(){DB_GEN_NEW};
+ void startIndexList(){DB_GEN_NEW};
+ void endIndexList(){DB_GEN_NEW};
+ void startIndexKey(){DB_GEN_NEW};
+ void endIndexKey(){DB_GEN_NEW};
+ void startIndexValue(bool){DB_GEN_NEW};
+ void endIndexValue(const char *,bool){DB_GEN_NEW};
+ void startItemList() {DB_GEN_EMPTY};
+ void endItemList() {DB_GEN_EMPTY};
+
+ void startIndexItem(const char *ref,const char *file){DB_GEN_NEW};
+ void endIndexItem(const char *ref,const char *file){DB_GEN_NEW};
+ void startItemListItem() {DB_GEN_EMPTY};
+ void endItemListItem() {DB_GEN_EMPTY};
+ void docify(const char *text);
+ void writeChar(char);
+ void writeString(const char *);
+ void startParagraph(const char *);
+ void endParagraph(void);
+ void writeObjectLink(const char *,const char *,const char *,const char *);
+ void startHtmlLink(const char *){DB_GEN_NEW};
+ void endHtmlLink(void){DB_GEN_NEW};
+ void startBold(void);
+ void endBold(void);
+ void startTypewriter(void);
+ void endTypewriter(void);
+ void startEmphasis(void){DB_GEN_NEW};
+ void endEmphasis(void){DB_GEN_NEW};
+ void startCodeFragment(void);
+ void endCodeFragment(void);
+ void writeRuler(void);
+ void startDescription(void){DB_GEN_NEW};
+ void endDescription(void){DB_GEN_NEW};
+ void startDescItem(void){DB_GEN_NEW};
+ void startDescForItem(void){DB_GEN_EMPTY};
+ void endDescForItem(void){DB_GEN_EMPTY};
+ void endDescItem(void){DB_GEN_NEW};
+ void startCenter(void){DB_GEN_NEW};
+ void endCenter(void){DB_GEN_NEW};
+ void startSmall(void){DB_GEN_NEW};
+ void endSmall(void){DB_GEN_NEW};
+ void startExamples(void);
+ void endExamples(void);
+ void startParamList(BaseOutputDocInterface::ParamListTypes,const char *){DB_GEN_NEW};
+ void endParamList(void){DB_GEN_NEW};
+ void startTitle(void){DB_GEN_NEW};
+ void endTitle(void){DB_GEN_NEW};
+ void writeAnchor(const char *,const char *){DB_GEN_EMPTY};
+ void startSection(const char *,const char *,SectionInfo::SectionType);
+ void endSection(const char *,SectionInfo::SectionType);
+ void lineBreak(const char *);
+ void addIndexItem(const char *,const char *);
+ void writeNonBreakableSpace(int);
+ void startDescTable(const char *);
+ void endDescTable(void);
+ void startDescTableRow(void);
+ void endDescTableRow(void);
+ void startDescTableTitle(void);
+ void endDescTableTitle(void);
+ void startDescTableData(void);
+ void endDescTableData(void);
+ void startTextLink(const char *,const char *){DB_GEN_NEW};
+ void endTextLink(void){DB_GEN_NEW};
+ void startPageRef(void){DB_GEN_NEW};
+ void endPageRef(const char *,const char *){DB_GEN_NEW};
+ void startSubsection(void){DB_GEN_NEW};
+ void endSubsection(void){DB_GEN_NEW};
+ void startSubsubsection(void);
+ void endSubsubsection(void);
+
+
+ void startGroupHeader(int);
+ void endGroupHeader(int);
+ void startMemberSections(){DB_GEN_EMPTY};
+ void endMemberSections(){DB_GEN_EMPTY};
+ void startHeaderSection(){DB_GEN_EMPTY};
+ void endHeaderSection(){DB_GEN_EMPTY};
+ void startMemberHeader(const char *anchor, int typ);
+ void endMemberHeader();
+ void startMemberSubtitle(){DB_GEN_EMPTY};
+ void endMemberSubtitle(){DB_GEN_EMPTY};
+ void startMemberDocList();
+ void endMemberDocList();
+ void startMemberList();
+ void endMemberList();
+ void startInlineHeader(){DB_GEN_NEW};
+ void endInlineHeader(){DB_GEN_NEW};
+ void startAnonTypeScope(int){DB_GEN_EMPTY};
+ void endAnonTypeScope(int){DB_GEN_EMPTY};
+ void startMemberItem(const char *,int,const char *);
+ void endMemberItem();
+ void startMemberTemplateParams();
+ void endMemberTemplateParams(const char *,const char *);
+ void startMemberGroupHeader(bool);
+ void endMemberGroupHeader();
+ void startMemberGroupDocs(){DB_GEN_EMPTY};
+ void endMemberGroupDocs(){DB_GEN_EMPTY};
+ void startMemberGroup();
+ void endMemberGroup(bool);
+ void insertMemberAlign(bool){DB_GEN_EMPTY};
+ void insertMemberAlignLeft(int,bool){DB_GEN_EMPTY};
+ void startMemberDoc(const char *,const char *,
+ const char *,const char *,int,int,bool);
+ void endMemberDoc(bool);
+ void startDoxyAnchor(const char *fName,const char *manName,
+ const char *anchor,const char *name,
+ const char *args);
+ void endDoxyAnchor(const char *fileName,const char *anchor);
+ void writeLatexSpacing(){DB_GEN_EMPTY}
+ void writeStartAnnoItem(const char *type,const char *file,
+ const char *path,const char *name){DB_GEN_NEW};
+ void writeEndAnnoItem(const char *name){DB_GEN_NEW};
+ void startMemberDescription(const char *anchor,const char *inheritId, bool typ){DB_GEN_EMPTY};
+ void endMemberDescription(){DB_GEN_EMPTY};
+ void startMemberDeclaration(){DB_GEN_EMPTY};
+ void endMemberDeclaration(const char *anchor,const char *inheritId){DB_GEN_EMPTY};
+ void writeInheritedSectionTitle(const char *id,const char *ref,
+ const char *file,const char *anchor,
+ const char *title,const char *name){DB_GEN_NEW};
+ void startIndent(){DB_GEN_EMPTY};
+ void endIndent(){DB_GEN_EMPTY};
+ void writeSynopsis(){DB_GEN_EMPTY};
+ void startClassDiagram();
+ void endClassDiagram(const ClassDiagram &,const char *,const char *);
+ void startDotGraph();
+ void endDotGraph(const DotClassGraph &g);
+ void startInclDepGraph();
+ void endInclDepGraph(const DotInclDepGraph &g);
+ void startGroupCollaboration();
+ void endGroupCollaboration(const DotGroupCollaboration &g);
+ void startCallGraph();
+ void endCallGraph(const DotCallGraph &g);
+ void startDirDepGraph();
+ void endDirDepGraph(const DotDirDeps &g);
+ void writeGraphicalHierarchy(const DotGfxHierarchyTable &g){DB_GEN_NEW};
+ void startQuickIndices(){DB_GEN_EMPTY};
+ void endQuickIndices(){DB_GEN_EMPTY};
+ void writeSplitBar(const char *){DB_GEN_EMPTY};
+ void writeNavigationPath(const char *){DB_GEN_NEW};
+ void writeLogo(){DB_GEN_NEW};
+ void writeQuickLinks(bool compact,HighlightedItem hli,const char *file){DB_GEN_EMPTY};
+ void writeSummaryLink(const char *file,const char *anchor,const char *title,bool first){DB_GEN_EMPTY};
+ void startContents(){DB_GEN_EMPTY};
+ void endContents(){DB_GEN_EMPTY};
+ void startPageDoc(const char *pageTitle){DB_GEN_EMPTY}
+ void endPageDoc() {DB_GEN_EMPTY}
+ void startTextBlock(bool);
+ void endTextBlock(bool);
+ void lastIndexPage(){DB_GEN_EMPTY};
+ void startMemberDocPrefixItem();
+ void endMemberDocPrefixItem();
+ void startMemberDocName(bool);
+ void endMemberDocName();
+ void startParameterType(bool,const char *key){DB_GEN_EMPTY};
+ void endParameterType(){DB_GEN_EMPTY};
+ void startParameterName(bool);
+ void endParameterName(bool,bool,bool);
+ void startParameterList(bool);
+ void endParameterList();
+ void exceptionEntry(const char*,bool);
+
+ void startConstraintList(const char *);
+ void startConstraintParam();
+ void endConstraintParam();
+ void startConstraintType();
+ void endConstraintType();
+ void startConstraintDocs();
+ void endConstraintDocs();
+ void endConstraintList();
+
+ void startMemberDocSimple(bool){DB_GEN_NEW};
+ void endMemberDocSimple(bool){DB_GEN_NEW};
+ void startInlineMemberType(){DB_GEN_NEW};
+ void endInlineMemberType(){DB_GEN_NEW};
+ void startInlineMemberName(){DB_GEN_NEW};
+ void endInlineMemberName(){DB_GEN_NEW};
+ void startInlineMemberDoc(){DB_GEN_NEW};
+ void endInlineMemberDoc(){DB_GEN_NEW};
+
+ void startLabels();
+ void writeLabel(const char *,bool);
+ void endLabels();
+
+ void setCurrentDoc(Definition *,const char *,bool) {DB_GEN_EMPTY}
+ void addWord(const char *,bool) {DB_GEN_EMPTY}
+
+private:
+ DocbookGenerator(const DocbookGenerator &o);
+ DocbookGenerator &operator=(const DocbookGenerator &o);
+
+ QCString relPath;
+ DocbookCodeGenerator m_codeGen;
+ bool m_prettyCode;
+ bool m_denseText;
+ bool m_inGroup;
+ bool m_inDetail;
+ int m_levelListItem;
+ bool m_inListItem[20];
+ bool m_inSimpleSect[20];
+ bool m_descTable;
+ int m_inLevel;
+ bool m_firstMember;
+};
#endif
diff --git a/src/docbookvisitor.cpp b/src/docbookvisitor.cpp
index 78d19a4..7a948ec 100644
--- a/src/docbookvisitor.cpp
+++ b/src/docbookvisitor.cpp
@@ -34,19 +34,38 @@
#include "msc.h"
#include "dia.h"
#include "htmlentity.h"
+#include "emoji.h"
#include "plantuml.h"
-static void visitPreStart(FTextStream &t, const bool hasCaption, QCString name, QCString width, QCString height, const bool inlineImage = FALSE)
+#if 0
+#define DB_VIS_C DB_VIS_C1(m_t)
+#define DB_VIS_C1(x) x << "<!-- DB_VIS_C " << __LINE__ << " -->\n";
+#define DB_VIS_C2(y) DB_VIS_C2a(m_t,y)
+#define DB_VIS_C2a(x,y) x << "<!-- DB_VIS_C " << __LINE__ << " " << y << " -->\n";
+#else
+#define DB_VIS_C
+#define DB_VIS_C1(x)
+#define DB_VIS_C2(y)
+#define DB_VIS_C2a(x,y)
+#endif
+
+void visitPreStart(FTextStream &t, bool hasCaption, QCString name, QCString width, QCString height, bool inlineImage)
{
QCString tmpStr;
- t << " <figure>" << endl;
- t << " <title></title>" << endl;
+ if (hasCaption)
+ {
+ t << " <figure>" << endl;
+ }
+ else
+ {
+ t << " <informalfigure>" << endl;
+ }
t << " <mediaobject>" << endl;
t << " <imageobject>" << endl;
t << " <imagedata";
if (!width.isEmpty())
{
- t << " width=\"" << convertToXML(width) << "\"";
+ t << " width=\"" << convertToDocBook(width) << "\"";
}
else
{
@@ -54,26 +73,33 @@ static void visitPreStart(FTextStream &t, const bool hasCaption, QCString name,
}
if (!height.isEmpty())
{
- t << " depth=\"" << convertToXML(tmpStr) << "\"";
+ t << " depth=\"" << convertToDocBook(tmpStr) << "\"";
}
- t << " align=\"center\" valign=\"middle\" scalefit=\"1\" fileref=\"" << name << "\">";
+ t << " align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << name << "\">";
t << "</imagedata>" << endl;
t << " </imageobject>" << endl;
if (hasCaption)
{
- t << " <caption>" << endl;
+ t << " <title>" << endl;
}
}
-static void visitPostEnd(FTextStream &t, const bool hasCaption, const bool inlineImage = FALSE)
+void visitPostEnd(FTextStream &t, bool hasCaption, bool inlineImage)
{
t << endl;
if (hasCaption)
{
- t << " </caption>" << endl;
+ t << " </title>" << endl;
}
t << " </mediaobject>" << endl;
- t << " </figure>" << endl;
+ if (hasCaption)
+ {
+ t << " </figure>" << endl;
+ }
+ else
+ {
+ t << " </informalfigure>" << endl;
+ }
}
static void visitCaption(DocbookDocVisitor *parent, QList<DocNode> children)
@@ -86,6 +112,13 @@ static void visitCaption(DocbookDocVisitor *parent, QList<DocNode> children)
DocbookDocVisitor::DocbookDocVisitor(FTextStream &t,CodeOutputInterface &ci)
: DocVisitor(DocVisitor_Docbook), m_t(t), m_ci(ci), m_insidePre(FALSE), m_hide(FALSE)
{
+DB_VIS_C
+ // m_t << "<section>" << endl;
+}
+DocbookDocVisitor::~DocbookDocVisitor()
+{
+DB_VIS_C
+ // m_t << "</section>" << endl;
}
//--------------------------------------
@@ -94,12 +127,14 @@ DocbookDocVisitor::DocbookDocVisitor(FTextStream &t,CodeOutputInterface &ci)
void DocbookDocVisitor::visit(DocWord *w)
{
+DB_VIS_C
if (m_hide) return;
filter(w->word());
}
void DocbookDocVisitor::visit(DocLinkedWord *w)
{
+DB_VIS_C
if (m_hide) return;
startLink(w->file(),w->anchor());
filter(w->word());
@@ -108,6 +143,7 @@ void DocbookDocVisitor::visit(DocLinkedWord *w)
void DocbookDocVisitor::visit(DocWhiteSpace *w)
{
+DB_VIS_C
if (m_hide) return;
if (m_insidePre)
{
@@ -121,6 +157,7 @@ void DocbookDocVisitor::visit(DocWhiteSpace *w)
void DocbookDocVisitor::visit(DocSymbol *s)
{
+DB_VIS_C
if (m_hide) return;
const char *res = HtmlEntityMapper::instance()->docbook(s->symbol());
if (res)
@@ -133,8 +170,24 @@ void DocbookDocVisitor::visit(DocSymbol *s)
}
}
+void DocbookDocVisitor::visit(DocEmoji *s)
+{
+DB_VIS_C
+ if (m_hide) return;
+ const char *res = EmojiEntityMapper::instance()->docbook(s->emoji());
+ if (res)
+ {
+ m_t << res;
+ }
+ else
+ {
+ err("DocBook: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+}
+
void DocbookDocVisitor::visit(DocURL *u)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<link xlink:href=\"";
if (u->isEmail()) m_t << "mailto:";
@@ -146,12 +199,16 @@ void DocbookDocVisitor::visit(DocURL *u)
void DocbookDocVisitor::visit(DocLineBreak *)
{
+DB_VIS_C
if (m_hide) return;
- m_t << endl << "<literallayout>\n</literallayout>" << endl;
+ m_t << endl << "<literallayout>&#160;&#xa;</literallayout>" << endl;
+ // gives nicer results but gives problems as it is not allowed in <pare> and also problems with dblatex
+ // m_t << endl << "<sbr/>" << endl;
}
void DocbookDocVisitor::visit(DocHorRuler *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<informaltable frame='bottom'><tgroup cols='1'><colspec align='center'/><tbody><row><entry align='center'>\n";
m_t << "</entry></row></tbody></tgroup></informaltable>\n";
@@ -159,6 +216,7 @@ void DocbookDocVisitor::visit(DocHorRuler *)
void DocbookDocVisitor::visit(DocStyleChange *s)
{
+DB_VIS_C
if (m_hide) return;
switch (s->style())
{
@@ -196,6 +254,8 @@ void DocbookDocVisitor::visit(DocStyleChange *s)
/* There is no equivalent Docbook tag for rendering Small text */
case DocStyleChange::Small: /* XSLT Stylesheets can be used */ break;
/* HTML only */
+ case DocStyleChange::Strike: break;
+ case DocStyleChange::Underline: break;
case DocStyleChange::Div: /* HTML only */ break;
case DocStyleChange::Span: /* HTML only */ break;
}
@@ -203,6 +263,7 @@ void DocbookDocVisitor::visit(DocStyleChange *s)
void DocbookDocVisitor::visit(DocVerbatim *s)
{
+DB_VIS_C
if (m_hide) return;
SrcLangExt langExt = getLanguageFromFileName(m_langExt);
switch(s->type())
@@ -215,9 +276,9 @@ void DocbookDocVisitor::visit(DocVerbatim *s)
m_t << "</computeroutput></literallayout>";
break;
case DocVerbatim::Verbatim:
- m_t << "<literallayout>";
+ m_t << "<literallayout><computeroutput>";
filter(s->text());
- m_t << "</literallayout>";
+ m_t << "</computeroutput></literallayout>";
break;
case DocVerbatim::HtmlOnly:
break;
@@ -230,7 +291,6 @@ void DocbookDocVisitor::visit(DocVerbatim *s)
case DocVerbatim::XmlOnly:
break;
case DocVerbatim::DocbookOnly:
- break;
m_t << s->text();
break;
case DocVerbatim::Dot:
@@ -302,12 +362,14 @@ void DocbookDocVisitor::visit(DocVerbatim *s)
void DocbookDocVisitor::visit(DocAnchor *anc)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<anchor id=\"" << anc->file() << "_1" << anc->anchor() << "\"/>";
+ m_t << "<anchor xml:id=\"_" << stripPath(anc->file()) << "_1" << anc->anchor() << "\"/>";
}
void DocbookDocVisitor::visit(DocInclude *inc)
{
+DB_VIS_C
if (m_hide) return;
SrcLangExt langExt = getLanguageFromFileName(inc->extension());
switch(inc->type())
@@ -343,9 +405,9 @@ void DocbookDocVisitor::visit(DocInclude *inc)
case DocInclude::LatexInclude:
break;
case DocInclude::VerbInclude:
- m_t << "<verbatim>";
+ m_t << "<literallayout>";
filter(inc->text());
- m_t << "</verbatim>";
+ m_t << "</literallayout>";
break;
case DocInclude::Snippet:
m_t << "<literallayout><computeroutput>";
@@ -391,6 +453,7 @@ void DocbookDocVisitor::visit(DocInclude *inc)
void DocbookDocVisitor::visit(DocIncOperator *op)
{
+DB_VIS_C
if (op->isFirst())
{
if (!m_hide)
@@ -427,27 +490,37 @@ void DocbookDocVisitor::visit(DocIncOperator *op)
void DocbookDocVisitor::visit(DocFormula *f)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<equation><title>" << f->name() << "</title>";
- filter(f->text());
- m_t << "</equation>";
+
+ if (f->isInline()) m_t << "<inlinemediaobject>" << endl;
+ else m_t << " <mediaobject>" << endl;
+ m_t << " <imageobject>" << endl;
+ m_t << " <imagedata ";
+ m_t << "align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << f->relPath() << f->name() << ".png\"/>" << endl;
+ m_t << " </imageobject>" << endl;
+ if (f->isInline()) m_t << "</inlinemediaobject>" << endl;
+ else m_t << " </mediaobject>" << endl;
}
void DocbookDocVisitor::visit(DocIndexEntry *ie)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<indexentry><primaryie>" << endl;
+ m_t << "<indexterm><primary>";
filter(ie->entry());
- m_t << "</primaryie><secondaryie></secondaryie></indexentry>" << endl;
+ m_t << "</primary></indexterm>" << endl;
}
void DocbookDocVisitor::visit(DocSimpleSectSep *)
{
- m_t << "<simplesect/>";
+DB_VIS_C
+ // m_t << "<simplesect/>";
}
void DocbookDocVisitor::visit(DocCite *cite)
{
+DB_VIS_C
if (m_hide) return;
if (!cite->file().isEmpty()) startLink(cite->file(),cite->anchor());
filter(cite->text());
@@ -460,6 +533,7 @@ void DocbookDocVisitor::visit(DocCite *cite)
void DocbookDocVisitor::visitPre(DocAutoList *l)
{
+DB_VIS_C
if (m_hide) return;
if (l->isEnumList())
{
@@ -473,6 +547,7 @@ void DocbookDocVisitor::visitPre(DocAutoList *l)
void DocbookDocVisitor::visitPost(DocAutoList *l)
{
+DB_VIS_C
if (m_hide) return;
if (l->isEnumList())
{
@@ -486,18 +561,21 @@ void DocbookDocVisitor::visitPost(DocAutoList *l)
void DocbookDocVisitor::visitPre(DocAutoListItem *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<listitem>";
}
void DocbookDocVisitor::visitPost(DocAutoListItem *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</listitem>";
}
void DocbookDocVisitor::visitPre(DocPara *)
{
+DB_VIS_C
if (m_hide) return;
m_t << endl;
m_t << "<para>";
@@ -505,6 +583,7 @@ void DocbookDocVisitor::visitPre(DocPara *)
void DocbookDocVisitor::visitPost(DocPara *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</para>";
m_t << endl;
@@ -512,16 +591,19 @@ void DocbookDocVisitor::visitPost(DocPara *)
void DocbookDocVisitor::visitPre(DocRoot *)
{
+DB_VIS_C
//m_t << "<hr><h4><font color=\"red\">New parser:</font></h4>\n";
}
void DocbookDocVisitor::visitPost(DocRoot *)
{
+DB_VIS_C
//m_t << "<hr><h4><font color=\"red\">Old parser:</font></h4>\n";
}
void DocbookDocVisitor::visitPre(DocSimpleSect *s)
{
+DB_VIS_C
if (m_hide) return;
switch(s->type())
{
@@ -532,7 +614,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trSeeAlso()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trSeeAlso()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Return:
@@ -542,7 +624,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trReturns()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trReturns()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Author:
@@ -552,7 +634,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trAuthor(TRUE, TRUE)) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trAuthor(TRUE, TRUE)) << ": </title>" << endl;
}
break;
case DocSimpleSect::Authors:
@@ -562,7 +644,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trAuthor(TRUE, FALSE)) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trAuthor(TRUE, FALSE)) << ": </title>" << endl;
}
break;
case DocSimpleSect::Version:
@@ -572,7 +654,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trVersion()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trVersion()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Since:
@@ -582,7 +664,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trSince()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trSince()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Date:
@@ -592,27 +674,27 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trDate()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trDate()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Note:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trNote() << ": </title>" << endl;
+ m_t << "<note><title>" << theTranslator->trNote() << ": </title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trNote()) << ": </title>" << endl;
+ m_t << "<note><title>" << convertToDocBook(theTranslator->trNote()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Warning:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trWarning() << ": </title>" << endl;
+ m_t << "<warning><title>" << theTranslator->trWarning() << ": </title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trWarning()) << ": </title>" << endl;
+ m_t << "<warning><title>" << convertToDocBook(theTranslator->trWarning()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Pre:
@@ -622,7 +704,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trPrecondition()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trPrecondition()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Post:
@@ -632,7 +714,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trPostcondition()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trPostcondition()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Copyright:
@@ -642,7 +724,7 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trCopyright()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trCopyright()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Invar:
@@ -652,85 +734,121 @@ void DocbookDocVisitor::visitPre(DocSimpleSect *s)
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trInvariant()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trInvariant()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Remark:
+ // <remark> is miising the <title> possibility
if (m_insidePre)
{
m_t << "<formalpara><title>" << theTranslator->trRemarks() << ": </title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trRemarks()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trRemarks()) << ": </title>" << endl;
}
break;
case DocSimpleSect::Attention:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trAttention() << ": </title>" << endl;
+ m_t << "<caution><title>" << theTranslator->trAttention() << ": </title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToXML(theTranslator->trAttention()) << ": </title>" << endl;
+ m_t << "<caution><title>" << convertToDocBook(theTranslator->trAttention()) << ": </title>" << endl;
}
break;
case DocSimpleSect::User:
- m_t << "<formalpara><title></title>" << endl;
+ if (s->hasTitle())
+ m_t << "<formalpara>" << endl;
+ else
+ m_t << "<para>" << endl;
break;
case DocSimpleSect::Rcs:
- m_t << "<formalpara><title></title>" << endl;
+ case DocSimpleSect::Unknown:
+ m_t << "<para>" << endl;
break;
- case DocSimpleSect::Unknown: m_t << "<formalpara><title></title>" << endl; break;
}
}
-void DocbookDocVisitor::visitPost(DocSimpleSect *)
+void DocbookDocVisitor::visitPost(DocSimpleSect *s)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "</formalpara>" << endl;
+ switch(s->type())
+ {
+ case DocSimpleSect::Rcs:
+ case DocSimpleSect::Unknown:
+ m_t << "</para>" << endl;
+ break;
+ case DocSimpleSect::User:
+ if (s->hasTitle())
+ m_t << "</formalpara>" << endl;
+ else
+ m_t << "</para>" << endl;
+ break;
+ case DocSimpleSect::Note:
+ m_t << "</note>" << endl;
+ break;
+ case DocSimpleSect::Attention:
+ m_t << "</caution>" << endl;
+ break;
+ case DocSimpleSect::Warning:
+ m_t << "</warning>" << endl;
+ break;
+ default:
+ m_t << "</formalpara>" << endl;
+ break;
+ }
}
-void DocbookDocVisitor::visitPre(DocTitle *)
+void DocbookDocVisitor::visitPre(DocTitle *t)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<title>";
+ if (t->hasTitle()) m_t << "<title>";
}
-void DocbookDocVisitor::visitPost(DocTitle *)
+void DocbookDocVisitor::visitPost(DocTitle *t)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "</title>";
+ if (t->hasTitle()) m_t << "</title>";
}
void DocbookDocVisitor::visitPre(DocSimpleList *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<itemizedlist>\n";
}
void DocbookDocVisitor::visitPost(DocSimpleList *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</itemizedlist>\n";
}
void DocbookDocVisitor::visitPre(DocSimpleListItem *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<listitem>";
}
void DocbookDocVisitor::visitPost(DocSimpleListItem *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</listitem>\n";
}
void DocbookDocVisitor::visitPre(DocSection *s)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<section xml:id=\"" << s->file();
+ m_t << "<section xml:id=\"_" << stripPath(s->file());
if (!s->anchor().isEmpty()) m_t << "_1" << s->anchor();
m_t << "\">" << endl;
m_t << "<title>";
@@ -740,11 +858,13 @@ void DocbookDocVisitor::visitPre(DocSection *s)
void DocbookDocVisitor::visitPost(DocSection *)
{
+DB_VIS_C
m_t << "</section>\n";
}
void DocbookDocVisitor::visitPre(DocHtmlList *s)
{
+DB_VIS_C
if (m_hide) return;
if (s->type()==DocHtmlList::Ordered)
m_t << "<orderedlist>\n";
@@ -754,6 +874,7 @@ void DocbookDocVisitor::visitPre(DocHtmlList *s)
void DocbookDocVisitor::visitPost(DocHtmlList *s)
{
+DB_VIS_C
if (m_hide) return;
if (s->type()==DocHtmlList::Ordered)
m_t << "</orderedlist>\n";
@@ -763,143 +884,277 @@ void DocbookDocVisitor::visitPost(DocHtmlList *s)
void DocbookDocVisitor::visitPre(DocHtmlListItem *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<listitem>\n";
}
void DocbookDocVisitor::visitPost(DocHtmlListItem *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</listitem>\n";
}
void DocbookDocVisitor::visitPre(DocHtmlDescList *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<variablelist>\n";
}
void DocbookDocVisitor::visitPost(DocHtmlDescList *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</variablelist>\n";
}
void DocbookDocVisitor::visitPre(DocHtmlDescTitle *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<varlistentry><term>";
}
void DocbookDocVisitor::visitPost(DocHtmlDescTitle *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</term>\n";
}
void DocbookDocVisitor::visitPre(DocHtmlDescData *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<listitem>";
}
void DocbookDocVisitor::visitPost(DocHtmlDescData *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</listitem></varlistentry>\n";
}
+static int colCnt = 0;
+static bool bodySet = FALSE; // it is possible to have tables without a header
void DocbookDocVisitor::visitPre(DocHtmlTable *t)
{
+DB_VIS_C
+ bodySet = FALSE;
if (m_hide) return;
- m_t << "<table frame=\"all\">" << endl;
- m_t << " <title></title>" << endl;
+ m_t << "<informaltable frame=\"all\">" << endl;
m_t << " <tgroup cols=\"" << t->numColumns() << "\" align=\"left\" colsep=\"1\" rowsep=\"1\">" << endl;
- m_t << " <tbody>" << endl;
+ for (int i = 0; i <t->numColumns(); i++)
+ {
+ // do something with colwidth based of cell width specification (be aware of possible colspan in the header)?
+ m_t << " <colspec colname='c" << i+1 << "'/>\n";
+ }
}
void DocbookDocVisitor::visitPost(DocHtmlTable *)
{
+DB_VIS_C
if (m_hide) return;
- m_t << " </tbody>" << endl;
+ if (bodySet) m_t << " </tbody>" << endl;
+ bodySet = FALSE;
m_t << " </tgroup>" << endl;
- m_t << "</table>" << endl;
+ m_t << "</informaltable>" << endl;
}
-void DocbookDocVisitor::visitPre(DocHtmlRow *)
+void DocbookDocVisitor::visitPre(DocHtmlRow *tr)
{
+DB_VIS_C
+ colCnt = 0;
if (m_hide) return;
- m_t << "<row>\n";
+
+ if (tr->isHeading()) m_t << "<thead>\n";
+ else if (!bodySet)
+ {
+ bodySet = TRUE;
+ m_t << "<tbody>\n";
+ }
+
+ m_t << " <row ";
+
+ HtmlAttribListIterator li(tr->attribs());
+ HtmlAttrib *opt;
+ for (li.toFirst();(opt=li.current());++li)
+ {
+ if (opt->name=="class")
+ {
+ // just skip it
+ }
+ else if (opt->name=="style")
+ {
+ // just skip it
+ }
+ else if (opt->name=="height")
+ {
+ // just skip it
+ }
+ else if (opt->name=="filter")
+ {
+ // just skip it
+ }
+ else
+ {
+ m_t << " " << opt->name << "='" << opt->value << "'";
+ }
+ }
+ m_t << ">\n";
}
-void DocbookDocVisitor::visitPost(DocHtmlRow *)
+void DocbookDocVisitor::visitPost(DocHtmlRow *tr)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</row>\n";
+ if (tr->isHeading())
+ {
+ bodySet = TRUE;
+ m_t << "</thead><tbody>\n";
+ }
}
-void DocbookDocVisitor::visitPre(DocHtmlCell *)
+void DocbookDocVisitor::visitPre(DocHtmlCell *c)
{
+DB_VIS_C
+ colCnt++;
if (m_hide) return;
- m_t << "<entry>";
+ m_t << "<entry";
+
+ HtmlAttribListIterator li(c->attribs());
+ HtmlAttrib *opt;
+ for (li.toFirst();(opt=li.current());++li)
+ {
+ if (opt->name=="colspan")
+ {
+ m_t << " namest='c" << colCnt << "'";
+ int cols = opt->value.toInt();
+ colCnt += (cols - 1);
+ m_t << " nameend='c" << colCnt << "'";
+ }
+ else if (opt->name=="rowspan")
+ {
+ int extraRows = opt->value.toInt() - 1;
+ m_t << " morerows='" << extraRows << "'";
+ }
+ else if (opt->name=="class")
+ {
+ if (opt->value == "markdownTableBodyRight")
+ {
+ m_t << " align='right'";
+ }
+ else if (opt->value == "markdownTableBodyLeftt")
+ {
+ m_t << " align='left'";
+ }
+ else if (opt->value == "markdownTableBodyCenter")
+ {
+ m_t << " align='center'";
+ }
+ else if (opt->value == "markdownTableHeadRight")
+ {
+ m_t << " align='right'";
+ }
+ else if (opt->value == "markdownTableHeadLeftt")
+ {
+ m_t << " align='left'";
+ }
+ else if (opt->value == "markdownTableHeadCenter")
+ {
+ m_t << " align='center'";
+ }
+ }
+ else if (opt->name=="style")
+ {
+ // just skip it
+ }
+ else if (opt->name=="width")
+ {
+ // just skip it
+ }
+ else if (opt->name=="height")
+ {
+ // just skip it
+ }
+ else
+ {
+ m_t << " " << opt->name << "='" << opt->value << "'";
+ }
+ }
+ m_t << ">";
}
-void DocbookDocVisitor::visitPost(DocHtmlCell *)
+void DocbookDocVisitor::visitPost(DocHtmlCell *c)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</entry>";
}
-void DocbookDocVisitor::visitPre(DocHtmlCaption *)
+void DocbookDocVisitor::visitPre(DocHtmlCaption *c)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<caption>";
+ m_t << "<caption>";
}
void DocbookDocVisitor::visitPost(DocHtmlCaption *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</caption>\n";
}
void DocbookDocVisitor::visitPre(DocInternal *)
{
+DB_VIS_C
if (m_hide) return;
// TODO: to be implemented
}
void DocbookDocVisitor::visitPost(DocInternal *)
{
+DB_VIS_C
if (m_hide) return;
// TODO: to be implemented
}
void DocbookDocVisitor::visitPre(DocHRef *href)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<link xlink:href=\"" << href->url() << "\">";
+ m_t << "<link xlink:href=\"" << convertToDocBook(href->url()) << "\">";
}
void DocbookDocVisitor::visitPost(DocHRef *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</link>";
}
void DocbookDocVisitor::visitPre(DocHtmlHeader *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<formalpara><title>";
}
void DocbookDocVisitor::visitPost(DocHtmlHeader *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</title></formalpara>\n";
}
void DocbookDocVisitor::visitPre(DocImage *img)
{
+DB_VIS_C
if (img->type()==DocImage::DocBook)
{
if (m_hide) return;
@@ -910,7 +1165,7 @@ void DocbookDocVisitor::visitPre(DocImage *img)
{
baseName=baseName.right(baseName.length()-i-1);
}
- visitPreStart(m_t, img -> hasCaption(), baseName, img -> width(), img -> height(),img -> isInlineImage());
+ visitPreStart(m_t, img -> hasCaption(), img->relPath() + baseName, img -> width(), img -> height(),img -> isInlineImage());
}
else
{
@@ -921,6 +1176,7 @@ void DocbookDocVisitor::visitPre(DocImage *img)
void DocbookDocVisitor::visitPost(DocImage *img)
{
+DB_VIS_C
if (img->type()==DocImage::DocBook)
{
if (m_hide) return;
@@ -961,96 +1217,118 @@ void DocbookDocVisitor::visitPost(DocImage *img)
void DocbookDocVisitor::visitPre(DocDotFile *df)
{
+DB_VIS_C
if (m_hide) return;
startDotFile(df->file(),df->width(),df->height(),df->hasCaption());
}
void DocbookDocVisitor::visitPost(DocDotFile *df)
{
+DB_VIS_C
if (m_hide) return;
endDotFile(df->hasCaption());
}
void DocbookDocVisitor::visitPre(DocMscFile *df)
{
+DB_VIS_C
if (m_hide) return;
startMscFile(df->file(),df->width(),df->height(),df->hasCaption());
}
void DocbookDocVisitor::visitPost(DocMscFile *df)
{
+DB_VIS_C
if (m_hide) return;
endMscFile(df->hasCaption());
}
void DocbookDocVisitor::visitPre(DocDiaFile *df)
{
+DB_VIS_C
if (m_hide) return;
startDiaFile(df->file(),df->width(),df->height(),df->hasCaption());
}
void DocbookDocVisitor::visitPost(DocDiaFile *df)
{
+DB_VIS_C
if (m_hide) return;
endDiaFile(df->hasCaption());
}
void DocbookDocVisitor::visitPre(DocLink *lnk)
{
+DB_VIS_C
if (m_hide) return;
startLink(lnk->file(),lnk->anchor());
}
void DocbookDocVisitor::visitPost(DocLink *)
{
+DB_VIS_C
if (m_hide) return;
endLink();
}
void DocbookDocVisitor::visitPre(DocRef *ref)
{
+DB_VIS_C
if (m_hide) return;
- if (!ref->file().isEmpty()) startLink(ref->file(),ref->anchor());
+ if (ref->isSubPage())
+ {
+ startLink(0,ref->anchor());
+ }
+ else
+ {
+ if (!ref->file().isEmpty()) startLink(ref->file(),ref->anchor());
+ }
+
if (!ref->hasLinkText()) filter(ref->targetTitle());
}
void DocbookDocVisitor::visitPost(DocRef *ref)
{
+DB_VIS_C
if (m_hide) return;
if (!ref->file().isEmpty()) endLink();
}
void DocbookDocVisitor::visitPre(DocSecRefItem *ref)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<tocitem id=\"" << ref->file() << "_1" << ref->anchor() << "\">";
+ //m_t << "<tocentry xml:idref=\"_" << stripPath(ref->file()) << "_1" << ref->anchor() << "\">";
+ m_t << "<tocentry>";
}
void DocbookDocVisitor::visitPost(DocSecRefItem *)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "</tocitem>" << endl;
+ m_t << "</tocentry>" << endl;
}
void DocbookDocVisitor::visitPre(DocSecRefList *)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "<toclist>" << endl;
+ m_t << "<toc>" << endl;
}
void DocbookDocVisitor::visitPost(DocSecRefList *)
{
+DB_VIS_C
if (m_hide) return;
- m_t << "</toclist>" << endl;
+ m_t << "</toc>" << endl;
}
void DocbookDocVisitor::visitPre(DocParamSect *s)
{
+DB_VIS_C
if (m_hide) return;
m_t << endl;
m_t << " <formalpara>" << endl;
- m_t << " <title/>" << endl;
- m_t << " <table frame=\"all\">" << endl;
- m_t << " <title>";
+ m_t << " <title>" << endl;
switch(s->type())
{
case DocParamSect::Param: m_t << theTranslator->trParameters(); break;
@@ -1060,29 +1338,96 @@ void DocbookDocVisitor::visitPre(DocParamSect *s)
default:
ASSERT(0);
}
- m_t << " </title>" << endl;
- m_t << " <tgroup cols=\"2\" align=\"left\" colsep=\"1\" rowsep=\"1\">" << endl;
- m_t << " <colspec colwidth=\"1*\"/>" << endl;
- m_t << " <colspec colwidth=\"4*\"/>" << endl;
+ m_t << " </title>" << endl;
+ m_t << " <para>" << endl;
+ m_t << " <table frame=\"all\">" << endl;
+ int ncols = 2;
+ if (s->type() == DocParamSect::Param)
+ {
+ bool hasInOutSpecs = s->hasInOutSpecifier();
+ bool hasTypeSpecs = s->hasTypeSpecifier();
+ if (hasInOutSpecs && hasTypeSpecs) ncols += 2;
+ else if (hasInOutSpecs || hasTypeSpecs) ncols += 1;
+ }
+ m_t << " <tgroup cols=\"" << ncols << "\" align=\"left\" colsep=\"1\" rowsep=\"1\">" << endl;
+ for (int i = 1; i <= ncols; i++)
+ {
+ if (i == ncols) m_t << " <colspec colwidth=\"4*\"/>" << endl;
+ else m_t << " <colspec colwidth=\"1*\"/>" << endl;
+ }
m_t << " <tbody>" << endl;
}
void DocbookDocVisitor::visitPost(DocParamSect *)
{
+DB_VIS_C
if (m_hide) return;
m_t << " </tbody>" << endl;
m_t << " </tgroup>" << endl;
m_t << " </table>" << endl;
+ m_t << " </para>" << endl;
m_t << " </formalpara>" << endl;
m_t << " ";
}
void DocbookDocVisitor::visitPre(DocParamList *pl)
{
+DB_VIS_C
if (m_hide) return;
+ m_t << " <row>" << endl;
+
+ DocParamSect::Type parentType = DocParamSect::Unknown;
+ DocParamSect *sect = 0;
+ if (pl->parent() && pl->parent()->kind()==DocNode::Kind_ParamSect)
+ {
+ parentType = ((DocParamSect*)pl->parent())->type();
+ sect=(DocParamSect*)pl->parent();
+ }
+
+ if (sect && sect->hasInOutSpecifier())
+ {
+ m_t << " <entry>";
+ if (pl->direction()!=DocParamSect::Unspecified)
+ {
+ if (pl->direction()==DocParamSect::In)
+ {
+ m_t << "in";
+ }
+ else if (pl->direction()==DocParamSect::Out)
+ {
+ m_t << "out";
+ }
+ else if (pl->direction()==DocParamSect::InOut)
+ {
+ m_t << "in,out";
+ }
+ }
+ m_t << " </entry>";
+ }
+
+ if (sect && sect->hasTypeSpecifier())
+ {
+ QListIterator<DocNode> li(pl->paramTypes());
+ DocNode *type;
+ bool first=TRUE;
+ m_t << " <entry>";
+ for (li.toFirst();(type=li.current());++li)
+ {
+ if (!first) m_t << " | "; else first=FALSE;
+ if (type->kind()==DocNode::Kind_Word)
+ {
+ visit((DocWord*)type);
+ }
+ else if (type->kind()==DocNode::Kind_LinkedWord)
+ {
+ visit((DocLinkedWord*)type);
+ }
+ }
+ m_t << " </entry>";
+ }
+
QListIterator<DocNode> li(pl->parameters());
DocNode *param;
- m_t << " <row>" << endl;
if (!li.toFirst())
{
m_t << " <entry></entry>" << endl;
@@ -1114,6 +1459,7 @@ void DocbookDocVisitor::visitPre(DocParamList *pl)
void DocbookDocVisitor::visitPost(DocParamList *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</entry>" << endl;
m_t << " </row>" << endl;
@@ -1121,10 +1467,11 @@ void DocbookDocVisitor::visitPost(DocParamList *)
void DocbookDocVisitor::visitPre(DocXRefItem *x)
{
+DB_VIS_C
if (m_hide) return;
if (x->title().isEmpty()) return;
- m_t << "<para><link linkend=\"";
- m_t << x->file() << "_1" << x->anchor();
+ m_t << "<para><link linkend=\"_";
+ m_t << stripPath(x->file()) << "_1" << x->anchor();
m_t << "\">";
filter(x->title());
m_t << "</link>";
@@ -1133,6 +1480,7 @@ void DocbookDocVisitor::visitPre(DocXRefItem *x)
void DocbookDocVisitor::visitPost(DocXRefItem *x)
{
+DB_VIS_C
if (m_hide) return;
if (x->title().isEmpty()) return;
m_t << "</para>";
@@ -1140,12 +1488,14 @@ void DocbookDocVisitor::visitPost(DocXRefItem *x)
void DocbookDocVisitor::visitPre(DocInternalRef *ref)
{
+DB_VIS_C
if (m_hide) return;
startLink(ref->file(),ref->anchor());
}
void DocbookDocVisitor::visitPost(DocInternalRef *)
{
+DB_VIS_C
if (m_hide) return;
endLink();
m_t << " ";
@@ -1153,6 +1503,7 @@ void DocbookDocVisitor::visitPost(DocInternalRef *)
void DocbookDocVisitor::visitPre(DocCopy *)
{
+DB_VIS_C
if (m_hide) return;
// TODO: to be implemented
}
@@ -1160,6 +1511,7 @@ void DocbookDocVisitor::visitPre(DocCopy *)
void DocbookDocVisitor::visitPost(DocCopy *)
{
+DB_VIS_C
if (m_hide) return;
// TODO: to be implemented
}
@@ -1167,72 +1519,89 @@ void DocbookDocVisitor::visitPost(DocCopy *)
void DocbookDocVisitor::visitPre(DocText *)
{
+DB_VIS_C
// TODO: to be implemented
}
void DocbookDocVisitor::visitPost(DocText *)
{
+DB_VIS_C
// TODO: to be implemented
}
void DocbookDocVisitor::visitPre(DocHtmlBlockQuote *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "<blockquote>";
}
void DocbookDocVisitor::visitPost(DocHtmlBlockQuote *)
{
+DB_VIS_C
if (m_hide) return;
m_t << "</blockquote>";
}
void DocbookDocVisitor::visitPre(DocVhdlFlow *)
{
+DB_VIS_C
// TODO: to be implemented
}
void DocbookDocVisitor::visitPost(DocVhdlFlow *)
{
+DB_VIS_C
// TODO: to be implemented
}
void DocbookDocVisitor::visitPre(DocParBlock *)
{
+DB_VIS_C
}
void DocbookDocVisitor::visitPost(DocParBlock *)
{
+DB_VIS_C
}
void DocbookDocVisitor::filter(const char *str)
{
- m_t << convertToXML(str);
+DB_VIS_C
+ m_t << convertToDocBook(str);
}
void DocbookDocVisitor::startLink(const QCString &file,const QCString &anchor)
{
- m_t << "<link linkend=\"" << file;
- if (!anchor.isEmpty()) m_t << "_1" << anchor;
+DB_VIS_C
+ m_t << "<link linkend=\"_" << stripPath(file);
+ if (!anchor.isEmpty())
+ {
+ if (file) m_t << "_1";
+ m_t << anchor;
+ }
m_t << "\">";
}
void DocbookDocVisitor::endLink()
{
+DB_VIS_C
m_t << "</link>";
}
void DocbookDocVisitor::pushEnabled()
{
+DB_VIS_C
m_enabled.push(new bool(m_hide));
}
void DocbookDocVisitor::popEnabled()
{
+DB_VIS_C
bool *v=m_enabled.pop();
ASSERT(v!=0);
m_hide = *v;
@@ -1241,6 +1610,7 @@ void DocbookDocVisitor::popEnabled()
void DocbookDocVisitor::writeMscFile(const QCString &baseName, DocVerbatim *s)
{
+DB_VIS_C
QCString shortName = baseName;
int i;
if ((i=shortName.findRev('/'))!=-1)
@@ -1249,13 +1619,14 @@ void DocbookDocVisitor::writeMscFile(const QCString &baseName, DocVerbatim *s)
}
QCString outDir = Config_getString(DOCBOOK_OUTPUT);
writeMscGraphFromFile(baseName+".msc",outDir,shortName,MSC_BITMAP);
- visitPreStart(m_t, s->hasCaption(), shortName, s->width(),s->height());
+ visitPreStart(m_t, s->hasCaption(), s->relPath() + shortName + ".png", s->width(),s->height());
visitCaption(this, s->children());
visitPostEnd(m_t, s->hasCaption());
}
void DocbookDocVisitor::writePlantUMLFile(const QCString &baseName, DocVerbatim *s)
{
+DB_VIS_C
QCString shortName = baseName;
int i;
if ((i=shortName.findRev('/'))!=-1)
@@ -1264,7 +1635,7 @@ void DocbookDocVisitor::writePlantUMLFile(const QCString &baseName, DocVerbatim
}
QCString outDir = Config_getString(DOCBOOK_OUTPUT);
generatePlantUMLOutput(baseName,outDir,PUML_BITMAP);
- visitPreStart(m_t, s->hasCaption(), shortName, s->width(),s->height());
+ visitPreStart(m_t, s->hasCaption(), s->relPath() + shortName + ".png", s->width(),s->height());
visitCaption(this, s->children());
visitPostEnd(m_t, s->hasCaption());
}
@@ -1275,6 +1646,7 @@ void DocbookDocVisitor::startMscFile(const QCString &fileName,
bool hasCaption
)
{
+DB_VIS_C
QCString baseName=fileName;
int i;
if ((i=baseName.findRev('/'))!=-1)
@@ -1294,6 +1666,7 @@ void DocbookDocVisitor::startMscFile(const QCString &fileName,
void DocbookDocVisitor::endMscFile(bool hasCaption)
{
+DB_VIS_C
if (m_hide) return;
visitPostEnd(m_t, hasCaption);
m_t << "</para>" << endl;
@@ -1301,6 +1674,7 @@ void DocbookDocVisitor::endMscFile(bool hasCaption)
void DocbookDocVisitor::writeDiaFile(const QCString &baseName, DocVerbatim *s)
{
+DB_VIS_C
QCString shortName = baseName;
int i;
if ((i=shortName.findRev('/'))!=-1)
@@ -1320,6 +1694,7 @@ void DocbookDocVisitor::startDiaFile(const QCString &fileName,
bool hasCaption
)
{
+DB_VIS_C
QCString baseName=fileName;
int i;
if ((i=baseName.findRev('/'))!=-1)
@@ -1339,6 +1714,7 @@ void DocbookDocVisitor::startDiaFile(const QCString &fileName,
void DocbookDocVisitor::endDiaFile(bool hasCaption)
{
+DB_VIS_C
if (m_hide) return;
visitPostEnd(m_t, hasCaption);
m_t << "</para>" << endl;
@@ -1346,6 +1722,7 @@ void DocbookDocVisitor::endDiaFile(bool hasCaption)
void DocbookDocVisitor::writeDotFile(const QCString &baseName, DocVerbatim *s)
{
+DB_VIS_C
QCString shortName = baseName;
int i;
if ((i=shortName.findRev('/'))!=-1)
@@ -1354,7 +1731,7 @@ void DocbookDocVisitor::writeDotFile(const QCString &baseName, DocVerbatim *s)
}
QCString outDir = Config_getString(DOCBOOK_OUTPUT);
writeDotGraphFromFile(baseName+".dot",outDir,shortName,GOF_BITMAP);
- visitPreStart(m_t, s->hasCaption(), baseName + ".dot", s->width(),s->height());
+ visitPreStart(m_t, s->hasCaption(), s->relPath() + shortName + "." + getDotImageExtension(), s->width(),s->height());
visitCaption(this, s->children());
visitPostEnd(m_t, s->hasCaption());
}
@@ -1365,6 +1742,7 @@ void DocbookDocVisitor::startDotFile(const QCString &fileName,
bool hasCaption
)
{
+DB_VIS_C
QCString baseName=fileName;
int i;
if ((i=baseName.findRev('/'))!=-1)
@@ -1385,6 +1763,7 @@ void DocbookDocVisitor::startDotFile(const QCString &fileName,
void DocbookDocVisitor::endDotFile(bool hasCaption)
{
+DB_VIS_C
if (m_hide) return;
m_t << endl;
visitPostEnd(m_t, hasCaption);
diff --git a/src/docbookvisitor.h b/src/docbookvisitor.h
index 6c7976c..714b679 100644
--- a/src/docbookvisitor.h
+++ b/src/docbookvisitor.h
@@ -26,11 +26,15 @@ class FTextStream;
class CodeOutputInterface;
class QCString;
+void visitPreStart(FTextStream &t, bool hasCaption, QCString name, QCString width, QCString height, bool inlineImage=FALSE);
+void visitPostEnd(FTextStream &t, bool hasCaption, bool inlineImage = FALSE);
+
/*! @brief Concrete visitor implementation for Docbook output. */
class DocbookDocVisitor : public DocVisitor
{
public:
DocbookDocVisitor(FTextStream &t,CodeOutputInterface &ci);
+ ~DocbookDocVisitor();
//--------------------------------------
// visitor functions for leaf nodes
//--------------------------------------
@@ -38,6 +42,7 @@ class DocbookDocVisitor : public DocVisitor
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
diff --git a/src/docparser.cpp b/src/docparser.cpp
index 4cf7c4e..b414e8f 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -26,6 +26,7 @@
#include <qdict.h>
#include <qregexp.h>
#include <ctype.h>
+#include <qcstringlist.h>
#include "doxygen.h"
#include "debug.h"
@@ -54,6 +55,9 @@
#include "growbuf.h"
#include "markdown.h"
#include "htmlentity.h"
+#include "emoji.h"
+
+#define TK_COMMAND_CHAR(token) ((token)==TK_COMMAND_AT ? '@' : '\\')
// debug off
#define DBG(x) do {} while(0)
@@ -265,7 +269,7 @@ static void unescapeCRef(QCString &s)
* copies the image to the output directory (which depends on the \a type
* parameter).
*/
-static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
+static QCString findAndCopyImage(const char *fileName,DocImage::Type type, bool warn = true)
{
QCString result;
bool ambig;
@@ -333,7 +337,7 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
}
else
{
- printf("Source & Destination are the same!\n");
+ printf("Source and Destination are the same!\n");
}
}
else
@@ -361,7 +365,7 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
return baseName;
}
}
- else if (ambig)
+ else if (ambig && warn)
{
QCString text;
text.sprintf("image file name %s is ambiguous.\n",qPrint(fileName));
@@ -372,7 +376,7 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
else
{
result=fileName;
- if (result.left(5)!="http:" && result.left(6)!="https:")
+ if (result.left(5)!="http:" && result.left(6)!="https:" && warn)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,
"image file %s is not found in IMAGE_PATH: "
@@ -865,7 +869,35 @@ static bool findDocsForMemberOrCompound(const char *commandName,
return FALSE;
}
//---------------------------------------------------------------------------
+inline void errorHandleDefaultToken(DocNode *parent,int tok,
+ QList<DocNode> &children,const char *txt)
+{
+ switch (tok)
+ {
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
+ children.append(new DocWord(parent,TK_COMMAND_CHAR(tok) + g_token->name));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a %s",
+ qPrint(TK_COMMAND_CHAR(tok) + g_token->name), txt);
+ break;
+ case TK_SYMBOL:
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found found as part of a %s",
+ qPrint(g_token->name), txt);
+ break;
+ case TK_EMOJI:
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported emoji '%s' found while handling command %s",
+ qPrint(g_token->name),txt);
+ break;
+ default:
+ children.append(new DocWord(parent,g_token->name));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s found as part of a %s",
+ tokToString(tok), txt);
+ break;
+ }
+}
+//---------------------------------------------------------------------------
// forward declaration
static bool defaultHandleToken(DocNode *parent,int tok,
QList<DocNode> &children,bool
@@ -875,6 +907,7 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
const QCString &cmdName)
{
DBG(("handleStyleArgument(%s)\n",qPrint(cmdName)));
+ QCString saveCmdName = cmdName;
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
@@ -900,14 +933,6 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
{
switch (tok)
{
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command \\%s as the argument of a \\%s command",
- qPrint(g_token->name),qPrint(cmdName));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found while handling command %s",
- qPrint(g_token->name),qPrint(cmdName));
- break;
case TK_HTMLTAG:
if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
{ // ignore </li> as the end of a style command
@@ -916,8 +941,7 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
return tok;
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s while handling command %s",
- tokToString(tok),qPrint(cmdName));
+ errorHandleDefaultToken(parent,tok,children,"\\" + saveCmdName + " command");
break;
}
break;
@@ -1050,16 +1074,18 @@ const char *DocStyleChange::styleString() const
{
switch (m_style)
{
- case DocStyleChange::Bold: return "b";
- case DocStyleChange::Italic: return "em";
- case DocStyleChange::Code: return "code";
- case DocStyleChange::Center: return "center";
- case DocStyleChange::Small: return "small";
- case DocStyleChange::Subscript: return "subscript";
- case DocStyleChange::Superscript: return "superscript";
- case DocStyleChange::Preformatted: return "pre";
+ case DocStyleChange::Bold: return "b";
+ case DocStyleChange::Italic: return "em";
+ case DocStyleChange::Code: return "code";
+ case DocStyleChange::Center: return "center";
+ case DocStyleChange::Small: return "small";
+ case DocStyleChange::Subscript: return "subscript";
+ case DocStyleChange::Superscript: return "superscript";
+ case DocStyleChange::Preformatted: return "pre";
case DocStyleChange::Div: return "div";
case DocStyleChange::Span: return "span";
+ case DocStyleChange::Strike: return "strike";
+ case DocStyleChange::Underline: return "u";
}
return "<invalid>";
}
@@ -1294,21 +1320,7 @@ static void defaultHandleTitleAndSize(const int cmd, DocNode *parent, QList<DocN
}
if (!defaultHandleToken(parent,tok,children))
{
- switch (tok)
- {
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\%s",
- qPrint(g_token->name), Mappers::cmdMapper->find(cmd).data());
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
- default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
- break;
- }
+ errorHandleDefaultToken(parent,tok,children,Mappers::cmdMapper->find(cmd).data());
}
}
// parse size attributes
@@ -1366,8 +1378,8 @@ static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children
handleWord)
{
DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
- if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
- tok==TK_COMMAND || tok==TK_HTMLTAG
+ if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_EMOJI || tok==TK_URL ||
+ tok==TK_COMMAND_AT || tok==TK_COMMAND_BS || tok==TK_HTMLTAG
)
{
DBG((" name=%s",qPrint(g_token->name)));
@@ -1377,7 +1389,9 @@ reparsetoken:
QCString tokenName = g_token->name;
switch (tok)
{
- case TK_COMMAND:
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
switch (Mappers::cmdMapper->map(tokenName))
{
case CMD_BSLASH:
@@ -1401,6 +1415,9 @@ reparsetoken:
case CMD_HASH:
children.append(new DocSymbol(parent,DocSymbol::Sym_Hash));
break;
+ case CMD_COLON:
+ children.append(new DocSymbol(parent,DocSymbol::Sym_Colon));
+ break;
case CMD_DCOLON:
children.append(new DocSymbol(parent,DocSymbol::Sym_DoubleColon));
break;
@@ -1561,6 +1578,9 @@ reparsetoken:
doctokenizerYYsetStatePara();
}
break;
+ case CMD_IMAGE:
+ ((DocPara *)parent) -> handleImage("image");
+ break;
default:
return FALSE;
}
@@ -1585,6 +1605,26 @@ reparsetoken:
handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
}
break;
+ case HTML_STRIKE:
+ if (!g_token->endTag)
+ {
+ handleStyleEnter(parent,children,DocStyleChange::Strike,&g_token->attribs);
+ }
+ else
+ {
+ handleStyleLeave(parent,children,DocStyleChange::Strike,tokenName);
+ }
+ break;
+ case HTML_UNDERLINE:
+ if (!g_token->endTag)
+ {
+ handleStyleEnter(parent,children,DocStyleChange::Underline,&g_token->attribs);
+ }
+ else
+ {
+ handleStyleLeave(parent,children,DocStyleChange::Underline,tokenName);
+ }
+ break;
case HTML_CODE:
case XML_C:
if (!g_token->endTag)
@@ -1669,6 +1709,19 @@ reparsetoken:
}
}
break;
+ case TK_EMOJI:
+ {
+ int s = DocEmoji::decodeEmoji(tokenName);
+ if (s!=0)
+ {
+ children.append(new DocEmoji(parent,s));
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ break;
case TK_WHITESPACE:
case TK_NEWPARA:
handlepara:
@@ -1727,7 +1780,8 @@ static void handleImg(DocNode *parent,QList<DocNode> &children,const HtmlAttribL
// and remove the src attribute
bool result = attrList.remove(index);
ASSERT(result);
- DocImage *img = new DocImage(parent,attrList,opt->value,DocImage::Html,opt->value);
+ DocImage::Type t = DocImage::Html;
+ DocImage *img = new DocImage(parent,attrList,findAndCopyImage(opt->value,t,false),t,opt->value);
children.append(img);
found = TRUE;
}
@@ -1746,6 +1800,12 @@ DocSymbol::SymType DocSymbol::decodeSymbol(const QCString &symName)
return HtmlEntityMapper::instance()->name2sym(symName);
}
+int DocEmoji::decodeEmoji(const QCString &symName)
+{
+ DBG(("decodeSymbol(%s)\n",qPrint(symName)));
+ return EmojiEntityMapper::instance()->name2sym(symName);
+}
+
//---------------------------------------------------------------------------
static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
@@ -1877,11 +1937,8 @@ DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Empty anchor label");
}
- if (newAnchor) // found <a name="label">
- {
- m_anchor = id;
- }
- else if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix)
+
+ if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix)
{
CiteInfo *cite = Doxygen::citeDict->find(id.mid(CiteConsts::anchorPrefix.length()));
if (cite)
@@ -1896,6 +1953,10 @@ DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
m_file = "invalid";
}
}
+ else if (newAnchor) // found <a name="label">
+ {
+ m_anchor = id;
+ }
else // found \anchor label
{
SectionInfo *sec = Doxygen::sectionDict->find(id);
@@ -2307,21 +2368,7 @@ void DocSecRefItem::parse()
{
if (!defaultHandleToken(this,tok,m_children))
{
- switch (tok)
- {
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\refitem",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
- default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
- break;
- }
+ errorHandleDefaultToken(this,tok,m_children,"\\refitem");
}
}
doctokenizerYYsetStatePara();
@@ -2369,7 +2416,7 @@ void DocSecRefList::parse()
// handle items
while (tok)
{
- if (tok==TK_COMMAND)
+ if (tok==TK_COMMAND_AT || tok == TK_COMMAND_BS)
{
switch (Mappers::cmdMapper->map(g_token->name))
{
@@ -2449,21 +2496,7 @@ void DocInternalRef::parse()
{
if (!defaultHandleToken(this,tok,m_children))
{
- switch (tok)
- {
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\ref",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
- default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
- break;
- }
+ errorHandleDefaultToken(this,tok,m_children,"\\ref");
}
}
@@ -2607,19 +2640,10 @@ void DocRef::parse()
{
switch (tok)
{
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\ref",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
case TK_HTMLTAG:
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
+ errorHandleDefaultToken(this,tok,m_children,"\\ref");
break;
}
}
@@ -2730,7 +2754,9 @@ QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
{
switch (tok)
{
- case TK_COMMAND:
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_ENDLINK:
@@ -2746,13 +2772,17 @@ QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
}
break;
case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found as part of a \\link",
+ qPrint(g_token->name));
+ break;
+ case TK_EMOJI:
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported emoji '%s' found",
qPrint(g_token->name));
break;
case TK_HTMLTAG:
if (g_token->name!="see" || !isXmlLink)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected xml/html command %s found",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected xml/html command %s found as part of a \\link",
qPrint(g_token->name));
}
goto endlink;
@@ -2930,21 +2960,7 @@ void DocVhdlFlow::parse()
{
if (!defaultHandleToken(this,tok,m_children))
{
- switch (tok)
- {
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\vhdlflow",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
- default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
- break;
- }
+ errorHandleDefaultToken(this,tok,m_children,"\\vhdlflow");
}
}
tok=doctokenizerYYlex();
@@ -2962,8 +2978,8 @@ void DocVhdlFlow::parse()
//---------------------------------------------------------------------------
DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QCString &name,
- Type t,const QCString &url, const bool inlineImage) :
- m_attribs(attribs), m_name(name),
+ Type t,const QCString &url, bool inlineImage) :
+ m_attribs(attribs), m_name(name),
m_type(t), m_relPath(g_relPath),
m_url(url), m_inlineImage(inlineImage)
{
@@ -2991,10 +3007,6 @@ int DocHtmlHeader::parse()
{
switch (tok)
{
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <h%d> tag",
- qPrint(g_token->name),m_level);
- break;
case TK_HTMLTAG:
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
@@ -3069,17 +3081,12 @@ int DocHtmlHeader::parse()
warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <h%d> context",
g_token->endTag?"/":"",qPrint(g_token->name),m_level);
}
-
}
break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
- break;
+ char tmp[20];
+ sprintf(tmp,"<h%d>tag",m_level);
+ errorHandleDefaultToken(this,tok,m_children,tmp);
}
}
}
@@ -3111,16 +3118,7 @@ int DocHRef::parse()
{
switch (tok)
{
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <a>..</a> block",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
case TK_HTMLTAG:
-
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_A && g_token->endTag) // found </a> tag
@@ -3135,8 +3133,7 @@ int DocHRef::parse()
}
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok),doctokenizerYYlineno);
+ errorHandleDefaultToken(this,tok,m_children,"<a>..</a> block");
break;
}
}
@@ -3269,29 +3266,45 @@ int DocIndexEntry::parse()
}
}
break;
- case TK_COMMAND:
- switch (Mappers::cmdMapper->map(g_token->name))
- {
- case CMD_BSLASH: m_entry+='\\'; break;
- case CMD_AT: m_entry+='@'; break;
- case CMD_LESS: m_entry+='<'; break;
- case CMD_GREATER: m_entry+='>'; break;
- case CMD_AMP: m_entry+='&'; break;
- case CMD_DOLLAR: m_entry+='$'; break;
- case CMD_HASH: m_entry+='#'; break;
- case CMD_DCOLON: m_entry+="::"; break;
- case CMD_PERCENT: m_entry+='%'; break;
- case CMD_NDASH: m_entry+="--"; break;
- case CMD_MDASH: m_entry+="---"; break;
- case CMD_QUOTE: m_entry+='"'; break;
- case CMD_PUNT: m_entry+='.'; break;
- case CMD_PLUS: m_entry+='+'; break;
- case CMD_MINUS: m_entry+='-'; break;
- default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command %s found as argument of \\addindex",
- qPrint(g_token->name));
- break;
- }
+ case TK_EMOJI:
+ {
+ int s = DocEmoji::decodeEmoji(g_token->name);
+ if (s != 0)
+ {
+ m_entry+=g_token->name;
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected emoji found as argument of \\addindex");
+ }
+ }
+ break;
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
+ switch (Mappers::cmdMapper->map(g_token->name))
+ {
+ case CMD_BSLASH: m_entry+='\\'; break;
+ case CMD_AT: m_entry+='@'; break;
+ case CMD_LESS: m_entry+='<'; break;
+ case CMD_GREATER: m_entry+='>'; break;
+ case CMD_AMP: m_entry+='&'; break;
+ case CMD_DOLLAR: m_entry+='$'; break;
+ case CMD_HASH: m_entry+='#'; break;
+ case CMD_COLON: m_entry+=":"; break;
+ case CMD_DCOLON: m_entry+="::"; break;
+ case CMD_PERCENT: m_entry+='%'; break;
+ case CMD_NDASH: m_entry+="--"; break;
+ case CMD_MDASH: m_entry+="---"; break;
+ case CMD_QUOTE: m_entry+='"'; break;
+ case CMD_PUNT: m_entry+='.'; break;
+ case CMD_PLUS: m_entry+='+'; break;
+ case CMD_MINUS: m_entry+='-'; break;
+ default:
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command %s found as argument of \\addindex",
+ qPrint(g_token->name));
+ break;
+ }
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
@@ -3357,14 +3370,6 @@ int DocHtmlCaption::parse()
{
switch (tok)
{
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <caption> tag",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
case TK_HTMLTAG:
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
@@ -3381,8 +3386,7 @@ int DocHtmlCaption::parse()
}
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
+ errorHandleDefaultToken(this,tok,m_children,"<caption> tag");
break;
}
}
@@ -3896,7 +3900,9 @@ int DocHtmlDescTitle::parse()
{
switch (tok)
{
- case TK_COMMAND:
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
{
QCString cmdName=g_token->name;
bool isJavaLink=FALSE;
@@ -3907,7 +3913,7 @@ int DocHtmlDescTitle::parse()
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
qPrint(g_token->name));
}
else
@@ -3916,7 +3922,7 @@ int DocHtmlDescTitle::parse()
tok=doctokenizerYYlex(); // get the reference id
if (tok!=TK_WORD)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of \\%s command",
tokToString(tok),qPrint(cmdName));
}
else
@@ -3937,7 +3943,7 @@ int DocHtmlDescTitle::parse()
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
qPrint(cmdName));
}
else
@@ -3946,7 +3952,7 @@ int DocHtmlDescTitle::parse()
tok=doctokenizerYYlex();
if (tok!=TK_WORD)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of \\%s command",
tokToString(tok),qPrint(cmdName));
}
else
@@ -3965,13 +3971,17 @@ int DocHtmlDescTitle::parse()
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <dt> tag",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command \\%s found as part of a <dt> tag",
qPrint(g_token->name));
}
}
break;
case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol \\%s found as part of a <dt> tag",
+ qPrint(g_token->name));
+ break;
+ case TK_EMOJI:
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported emoji '%s' found",
qPrint(g_token->name));
break;
case TK_HTMLTAG:
@@ -4012,7 +4022,7 @@ int DocHtmlDescTitle::parse()
}
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s found as part of a <dt> tag",
tokToString(tok));
break;
}
@@ -4517,21 +4527,7 @@ void DocTitle::parse()
{
if (!defaultHandleToken(this,tok,m_children))
{
- switch (tok)
- {
- case TK_COMMAND:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a title section",
- qPrint(g_token->name));
- break;
- case TK_SYMBOL:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
- qPrint(g_token->name));
- break;
- default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
- tokToString(tok));
- break;
- }
+ errorHandleDefaultToken(this,tok,m_children,"title section");
}
}
doctokenizerYYsetStatePara();
@@ -5241,7 +5237,31 @@ void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
{
DBG(("handleInclude(%s)\n",qPrint(cmdName)));
int tok=doctokenizerYYlex();
- if (tok!=TK_WHITESPACE)
+ if (tok==TK_WORD && g_token->name=="{")
+ {
+ doctokenizerYYsetStateOptions();
+ tok=doctokenizerYYlex();
+ doctokenizerYYsetStatePara();
+ QCStringList optList=QCStringList::split(",",g_token->name);
+ if (t==DocInclude::Include && optList.contains("lineno"))
+ {
+ t = DocInclude::IncWithLines;
+ }
+ else if (t==DocInclude::Snippet && optList.contains("lineno"))
+ {
+ t = DocInclude::SnipWithLines;
+ }
+ else if (t==DocInclude::Include && optList.contains("doc"))
+ {
+ t = DocInclude::IncludeDoc;
+ }
+ else if (t==DocInclude::Snippet && optList.contains("doc"))
+ {
+ t = DocInclude::SnippetDoc;
+ }
+ tok=doctokenizerYYlex();
+ }
+ else if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
qPrint(cmdName));
@@ -5405,7 +5425,7 @@ void DocPara::handleInheritDoc()
}
-int DocPara::handleCommand(const QCString &cmdName)
+int DocPara::handleCommand(const QCString &cmdName, const int tok)
{
DBG(("handleCommand(%s)\n",qPrint(cmdName)));
int retval = RetVal_OK;
@@ -5413,6 +5433,7 @@ int DocPara::handleCommand(const QCString &cmdName)
switch (cmdId)
{
case CMD_UNKNOWN:
+ m_children.append(new DocWord(this,TK_COMMAND_CHAR(tok) + cmdName));
warn_doc_error(g_fileName,doctokenizerYYlineno,"Found unknown command `\\%s'",qPrint(cmdName));
break;
case CMD_EMPHASIS:
@@ -5457,6 +5478,9 @@ int DocPara::handleCommand(const QCString &cmdName)
case CMD_PIPE:
m_children.append(new DocSymbol(this,DocSymbol::Sym_Pipe));
break;
+ case CMD_COLON:
+ m_children.append(new DocSymbol(this,DocSymbol::Sym_Colon));
+ break;
case CMD_DCOLON:
m_children.append(new DocSymbol(this,DocSymbol::Sym_DoubleColon));
break;
@@ -5950,6 +5974,12 @@ int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &ta
case HTML_BOLD:
handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
break;
+ case HTML_STRIKE:
+ handleStyleEnter(this,m_children,DocStyleChange::Strike,&g_token->attribs);
+ break;
+ case HTML_UNDERLINE:
+ handleStyleEnter(this,m_children,DocStyleChange::Underline,&g_token->attribs);
+ break;
case HTML_CODE:
if (/*getLanguageFromFileName(g_fileName)==SrcLangExt_CSharp ||*/ g_xmlComment)
// for C# source or inside a <summary> or <remark> section we
@@ -6359,6 +6389,12 @@ int DocPara::handleHtmlEndTag(const QCString &tagName)
case HTML_BOLD:
handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
break;
+ case HTML_STRIKE:
+ handleStyleLeave(this,m_children,DocStyleChange::Strike,"strike");
+ break;
+ case HTML_UNDERLINE:
+ handleStyleLeave(this,m_children,DocStyleChange::Underline,"u");
+ break;
case HTML_CODE:
handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
break;
@@ -6502,8 +6538,8 @@ int DocPara::parse()
{
reparsetoken:
DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
- if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
- tok==TK_COMMAND || tok==TK_HTMLTAG
+ if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_EMOJI || tok==TK_URL ||
+ tok==TK_COMMAND_AT || tok == TK_COMMAND_BS || tok==TK_HTMLTAG
)
{
DBG((" name=%s",qPrint(g_token->name)));
@@ -6601,7 +6637,7 @@ reparsetoken:
}
else // other section
{
- tok = TK_COMMAND;
+ tok = TK_COMMAND_BS;
}
DBG(("reparsing command %s\n",qPrint(g_token->name)));
goto reparsetoken;
@@ -6646,7 +6682,9 @@ reparsetoken:
"list items");
}
break;
- case TK_COMMAND:
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
{
// see if we have to start a simple section
int cmd = Mappers::cmdMapper->map(g_token->name);
@@ -6682,7 +6720,7 @@ reparsetoken:
}
// handle the command
- retval=handleCommand(g_token->name);
+ retval=handleCommand(g_token->name,tok);
DBG(("handleCommand returns %x\n",retval));
// check the return value
@@ -6700,7 +6738,7 @@ reparsetoken:
}
else // other section
{
- tok = TK_COMMAND;
+ tok = TK_COMMAND_BS;
}
DBG(("reparsing command %s\n",qPrint(g_token->name)));
goto reparsetoken;
@@ -6758,6 +6796,20 @@ reparsetoken:
}
break;
}
+ case TK_EMOJI:
+ {
+ int s = DocEmoji::decodeEmoji(g_token->name);
+ if (s!=0)
+ {
+ m_children.append(new DocEmoji(this,s));
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported emoji '%s' found",
+ qPrint(g_token->name));
+ }
+ break;
+ }
case TK_NEWPARA:
retval=TK_NEWPARA;
goto endparagraph;
@@ -6972,7 +7024,23 @@ void DocText::parse()
}
}
break;
- case TK_COMMAND:
+ case TK_EMOJI:
+ {
+ int s = DocSymbol::decodeSymbol(g_token->name);
+ if (s!=0)
+ {
+ m_children.append(new DocEmoji(this,s));
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported emoji '%s' found",
+ qPrint(g_token->name));
+ }
+ }
+ break;
+ case TK_COMMAND_AT:
+ // fall through
+ case TK_COMMAND_BS:
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_BSLASH:
@@ -6996,6 +7064,9 @@ void DocText::parse()
case CMD_HASH:
m_children.append(new DocSymbol(this,DocSymbol::Sym_Hash));
break;
+ case CMD_COLON:
+ m_children.append(new DocSymbol(this,DocSymbol::Sym_Colon));
+ break;
case CMD_DCOLON:
m_children.append(new DocSymbol(this,DocSymbol::Sym_DoubleColon));
break;
diff --git a/src/docparser.h b/src/docparser.h
index 69259d6..e98198d 100644
--- a/src/docparser.h
+++ b/src/docparser.h
@@ -140,7 +140,8 @@ class DocNode
Kind_HtmlBlockQuote = 49,
Kind_VhdlFlow = 50,
Kind_ParBlock = 51,
- Kind_DiaFile = 52
+ Kind_DiaFile = 52,
+ Kind_Emoji = 53
};
/*! Creates a new node */
DocNode() : m_parent(0), m_insidePre(FALSE) {}
@@ -367,7 +368,9 @@ class DocStyleChange : public DocNode
Superscript = (1<<6),
Preformatted = (1<<7),
Span = (1<<8),
- Div = (1<<9)
+ Div = (1<<9),
+ Strike = (1<<10),
+ Underline = (1<<11)
};
DocStyleChange(DocNode *parent,uint position,Style s,bool enable,
@@ -452,7 +455,7 @@ class DocSymbol : public DocNode
/* doxygen commands mapped */
Sym_BSlash, Sym_At, Sym_Less, Sym_Greater, Sym_Amp,
Sym_Dollar, Sym_Hash, Sym_DoubleColon, Sym_Percent, Sym_Pipe,
- Sym_Quot, Sym_Minus, Sym_Plus, Sym_Dot
+ Sym_Quot, Sym_Minus, Sym_Plus, Sym_Dot, Sym_Colon
};
enum PerlType { Perl_unknown = 0, Perl_string, Perl_char, Perl_symbol, Perl_umlaut,
Perl_acute, Perl_grave, Perl_circ, Perl_slash, Perl_tilde,
@@ -473,6 +476,21 @@ class DocSymbol : public DocNode
SymType m_symbol;
};
+/** Node representing a n emoji */
+class DocEmoji : public DocNode
+{
+ public:
+ DocEmoji(DocNode *parent,int s) :
+ m_symbol(s) { m_parent = parent; }
+ int emoji() const { return m_symbol; }
+ Kind kind() const { return Kind_Emoji; }
+ void accept(DocVisitor *v) { v->visit(this); }
+ static int decodeEmoji(const QCString &symName);
+
+ private:
+ int m_symbol;
+};
+
/** Node representing some amount of white space */
class DocWhiteSpace : public DocNode
{
@@ -705,6 +723,7 @@ class DocTitle : public CompAccept<DocTitle>
void parse();
void parseFromString(const QCString &title);
Kind kind() const { return Kind_Title; }
+ bool hasTitle() const { return !m_children.isEmpty(); }
private:
};
@@ -737,7 +756,7 @@ class DocImage : public CompAccept<DocImage>
public:
enum Type { Html, Latex, Rtf, DocBook };
DocImage(DocNode *parent,const HtmlAttribList &attribs,
- const QCString &name,Type t,const QCString &url=QCString(), const bool inlineImage = TRUE);
+ const QCString &name,Type t,const QCString &url=QCString(), bool inlineImage = TRUE);
Kind kind() const { return Kind_Image; }
Type type() const { return m_type; }
QCString name() const { return m_name; }
@@ -1092,6 +1111,7 @@ class DocSimpleSect : public CompAccept<DocSimpleSect>
int parseRcs();
int parseXml();
void appendLinkWord(const QCString &word);
+ bool hasTitle() const { return m_title->hasTitle(); }
private:
Type m_type;
@@ -1153,7 +1173,7 @@ class DocPara : public CompAccept<DocPara>
bool isFirst() const { return m_isFirst; }
bool isLast() const { return m_isLast; }
- int handleCommand(const QCString &cmdName);
+ int handleCommand(const QCString &cmdName,const int tok);
int handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs);
int handleHtmlEndTag(const QCString &tagName);
int handleSimpleSection(DocSimpleSect::Type t,bool xmlContext=FALSE);
@@ -1370,7 +1390,7 @@ class DocHtmlTable : public CompAccept<DocHtmlTable>
{
public:
DocHtmlTable(DocNode *parent,const HtmlAttribList &attribs)
- : m_attribs(attribs) { m_caption=0; m_parent = parent; }
+ : m_attribs(attribs) { m_caption=0; m_numCols=0; m_parent = parent; }
~DocHtmlTable() { delete m_caption; }
Kind kind() const { return Kind_HtmlTable; }
uint numRows() const { return m_children.count(); }
diff --git a/src/doctokenizer.h b/src/doctokenizer.h
index eb39906..f510c33 100644
--- a/src/doctokenizer.h
+++ b/src/doctokenizer.h
@@ -34,12 +34,14 @@ enum Tokens
TK_WHITESPACE = 3,
TK_LISTITEM = 4,
TK_ENDLIST = 5,
- TK_COMMAND = 6,
+ TK_COMMAND_AT = 6, //! Command starting with `@`
TK_HTMLTAG = 7,
TK_SYMBOL = 8,
TK_NEWPARA = 9,
TK_RCSTAG = 10,
TK_URL = 11,
+ TK_COMMAND_BS = 12, //! Command starting with `\`
+ TK_EMOJI = 13,
RetVal_OK = 0x10000,
RetVal_SimpleSec = 0x10001,
@@ -163,5 +165,6 @@ void doctokenizerYYendAutoList();
void doctokenizerYYsetStatePlantUML();
void doctokenizerYYsetStateSetScope();
void doctokenizerYYsetStatePlantUMLOpt();
+void doctokenizerYYsetStateOptions();
#endif
diff --git a/src/doctokenizer.l b/src/doctokenizer.l
index e6b8865..0a3c0cf 100644
--- a/src/doctokenizer.l
+++ b/src/doctokenizer.l
@@ -41,6 +41,8 @@
#define YY_NO_INPUT 1
#define YY_NO_UNISTD_H 1
+
+#define TK_COMMAND_SEL() (yytext[0] == '@' ? TK_COMMAND_AT : TK_COMMAND_BS)
//--------------------------------------------------------------------------
@@ -116,12 +118,14 @@ const char *tokToString(int token)
case TK_WHITESPACE: return "TK_WHITESPACE";
case TK_LISTITEM: return "TK_LISTITEM";
case TK_ENDLIST: return "TK_ENDLIST";
- case TK_COMMAND: return "TK_COMMAND";
+ case TK_COMMAND_AT: return "TK_COMMAND_AT";
case TK_HTMLTAG: return "TK_HTMLTAG";
case TK_SYMBOL: return "TK_SYMBOL";
case TK_NEWPARA: return "TK_NEWPARA";
case TK_RCSTAG: return "TK_RCSTAG";
case TK_URL: return "TK_URL";
+ case TK_COMMAND_BS: return "TK_COMMAND_BS";
+ case TK_EMOJI: return "TK_EMOJI";
}
return "ERROR";
}
@@ -332,6 +336,7 @@ CMD ("\\"|"@")
WS [ \t\r\n]
NONWS [^ \t\r\n]
BLANK [ \t\r]
+EMOJI (":"[a-z_A-Z0-9\x80-\xFF"'+()&\*\.!,#-]":"|":"[a-z_A-Z0-9\x80-\xFF"'+()&\*\.!,#-][a-z_A-Z0-9\x80-\xFF "'+()&\*\.!,#-]*[a-z_A-Z0-9\x80-\xFF"'+()&\*\.!,#-]":")
ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
LABELID [a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF\-]*
PHPTYPE [\\:a-z_A-Z0-9\x80-\xFF\-]+
@@ -358,6 +363,7 @@ SPCMD1 {CMD}([a-z_A-Z][a-z_A-Z0-9]*|{VERBATIM}|"--"|"---")
SPCMD2 {CMD}[\\@<>&$#%~".+|-]
SPCMD3 {CMD}form#[0-9]+
SPCMD4 {CMD}"::"
+SPCMD5 {CMD}":"
INOUT "inout"|"in"|"out"|("in"{BLANK}*","{BLANK}*"out")|("out"{BLANK}*","{BLANK}*"in")
PARAMIO {CMD}param{BLANK}*"["{BLANK}*{INOUT}{BLANK}*"]"
VARARGS "..."
@@ -388,14 +394,14 @@ LNKWORD3 ([0-9a-z_A-Z\-]+("/"|"\\"))*[0-9a-z_A-Z\-]+("."[0-9a-z_A-Z]+)+
CHARWORDQ [^ \t\n\r\\@<>()\[\]:;\?{}&%$#,."=']
ESCWORD ("%"{ID}(("::"|"."){ID})*)|("%'")
CHARWORDQ1 [^ \-+0-9\t\n\r\\@<>()\[\]:;\?{}&%$#,."=']
-WORD1 {ESCWORD}|{CHARWORDQ1}+|"{"|"}"|"'\"'"|("\""[^"\n]*\n?[^"\n]*"\"")
+WORD1 {ESCWORD}|{CHARWORDQ1}{CHARWORDQ}*|"{"|"}"|"'\"'"|("\""[^"\n]*\n?[^"\n]*"\"")
WORD2 "."|","|"("|")"|"["|"]"|":"|";"|"\?"|"="|"'"
WORD1NQ {ESCWORD}|{CHARWORDQ}+|"{"|"}"
WORD2NQ "."|","|"("|")"|"["|"]"|":"|";"|"\?"|"="|"'"
CAPTION [cC][aA][pP][tT][iI][oO][nN]
HTMLTAG "<"(("/")?){ID}({WS}+{ATTRIB})*{WS}*(("/")?)">"
-HTMLKEYL "strong"|"center"|"table"|"caption"|"small"|"code"|"dfn"|"var"|"img"|"pre"|"sub"|"sup"|"tr"|"td"|"th"|"ol"|"ul"|"li"|"tt"|"kbd"|"em"|"hr"|"dl"|"dt"|"dd"|"br"|"i"|"a"|"b"|"p"
-HTMLKEYU "STRONG"|"CENTER"|"TABLE"|"CAPTION"|"SMALL"|"CODE"|"DFN"|"VAR"|"IMG"|"PRE"|"SUB"|"SUP"|"TR"|"TD"|"TH"|"OL"|"UL"|"LI"|"TT"|"KBD"|"EM"|"HR"|"DL"|"DT"|"DD"|"BR"|"I"|"A"|"B"|"P"
+HTMLKEYL "strong"|"center"|"table"|"caption"|"small"|"code"|"dfn"|"var"|"img"|"pre"|"sub"|"sup"|"tr"|"td"|"th"|"ol"|"ul"|"li"|"tt"|"kbd"|"em"|"hr"|"dl"|"dt"|"dd"|"br"|"i"|"a"|"b"|"p"|"strike"|"u"
+HTMLKEYU "STRONG"|"CENTER"|"TABLE"|"CAPTION"|"SMALL"|"CODE"|"DFN"|"VAR"|"IMG"|"PRE"|"SUB"|"SUP"|"TR"|"TD"|"TH"|"OL"|"UL"|"LI"|"TT"|"KBD"|"EM"|"HR"|"DL"|"DT"|"DD"|"BR"|"I"|"A"|"B"|"P"|"STRIKE"|"U"
HTMLKEYW {HTMLKEYL}|{HTMLKEYU}
REFWORD2_PRE ("#"|"::")?((({ID}{TEMPLPART}?)|{ANONNS})("."|"#"|"::"|"-"|"/"))*({ID}{TEMPLPART}?(":")?)
REFWORD2 {REFWORD2_PRE}{FUNCARG2}?
@@ -403,8 +409,8 @@ REFWORD2_NOCV {REFWORD2_PRE}("("{FUNCPART}")")?
REFWORD3 ({ID}":")*{ID}":"?
REFWORD4_NOCV (({SCOPEPRE}*"operator"{OPMASKOP2})|(("::"|"#"){SCOPEPRE}*"operator"{OPMASKOP2}))
REFWORD4 {REFWORD4_NOCV}{CVSPEC}?
-REFWORD {LABELID}|{REFWORD2}|{REFWORD3}|{REFWORD4}
-REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
+REFWORD {FILEMASK}|{LABELID}|{REFWORD2}|{REFWORD3}|{REFWORD4}
+REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
%option noyywrap
%option yylineno
@@ -447,6 +453,7 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
%x St_Snippet
%x St_SetScope
%x St_SetScopeEnd
+%x St_Options
%x St_Sections
%s St_SecLabel1
@@ -557,11 +564,11 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
}
<St_Para>"{"{BLANK}*"@link"/{BLANK}+ {
g_token->name = "javalink";
- return TK_COMMAND;
+ return TK_COMMAND_AT;
}
<St_Para>"{"{BLANK}*"@inheritDoc"{BLANK}*"}" {
g_token->name = "inheritdoc";
- return TK_COMMAND;
+ return TK_COMMAND_AT;
}
<St_Para>"@_fakenl" { // artificial new line
yylineno++;
@@ -571,22 +578,23 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
bool ok;
g_token->id = QCString(yytext).right((int)yyleng-6).toInt(&ok);
ASSERT(ok);
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_Para>{CMD}"n"\n { /* \n followed by real newline */
yylineno++;
g_token->name = yytext+1;
g_token->name = g_token->name.stripWhiteSpace();
g_token->paramDir=TokenInfo::Unspecified;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_Para>{SPCMD1} |
<St_Para>{SPCMD2} |
+<St_Para>{SPCMD5} |
<St_Para>{SPCMD4} { /* special command */
g_token->name = yytext+1;
g_token->name = g_token->name.stripWhiteSpace();
g_token->paramDir=TokenInfo::Unspecified;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_Para>{PARAMIO} { /* param [in,out] command */
g_token->name = "param";
@@ -612,7 +620,7 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
{
g_token->paramDir=TokenInfo::Unspecified;
}
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_Para>("http:"|"https:"|"ftp:"|"file:"|"news:"){URLMASK}/\. { // URL.
g_token->name=yytext;
@@ -658,7 +666,8 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->text = tagName.mid(text_begin,text_end-text_begin);
return TK_RCSTAG;
}
-<St_Para,St_HtmlOnly>"$("{ID}")" { /* environment variable */
+<St_Para,St_HtmlOnly,St_ManOnly,St_LatexOnly,St_RtfOnly,St_XmlOnly,St_DbOnly>"$("{ID}")" | /* environment variable */
+<St_Para,St_HtmlOnly,St_ManOnly,St_LatexOnly,St_RtfOnly,St_XmlOnly,St_DbOnly>"$("{ID}"("{ID}"))" { /* environment variable */
QCString name = &yytext[2];
name = name.left(name.length()-1);
QCString value = portable_getenv(name);
@@ -672,6 +681,10 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->name = yytext;
return TK_SYMBOL;
}
+<St_Para,St_Text>{EMOJI} { /* emoji symbol */
+ g_token->name = yytext;
+ return TK_EMOJI;
+ }
/********* patterns for linkable words ******************/
@@ -731,7 +744,7 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
}
<St_Text>[\\@<>&$#%~] {
g_token->name = yytext;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_Para>({BLANK}*\n)+{BLANK}*\n/{LISTITEM} { /* skip trailing paragraph followed by new list item */
if (g_insidePre || g_autoListLevel==0)
@@ -918,13 +931,17 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->name = yytext;
return TK_SYMBOL;
}
+<St_TitleN>{EMOJI} { /* emoji */
+ g_token->name = yytext;
+ return TK_EMOJI;
+ }
<St_TitleN>{HTMLTAG} {
}
<St_TitleN>{SPCMD1} |
<St_TitleN>{SPCMD2} { /* special command */
g_token->name = yytext+1;
g_token->paramDir=TokenInfo::Unspecified;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_TitleN>{ID}"=" { /* attribute */
if (yytext[0]=='%') // strip % if present
@@ -954,11 +971,15 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->name = yytext;
return TK_SYMBOL;
}
+<St_TitleQ>{EMOJI} { /* emoji */
+ g_token->name = yytext;
+ return TK_EMOJI;
+ }
<St_TitleQ>{SPCMD1} |
<St_TitleQ>{SPCMD2} { /* special command */
g_token->name = yytext+1;
g_token->paramDir=TokenInfo::Unspecified;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_TitleQ>{WORD1NQ} |
<St_TitleQ>{WORD2NQ} { /* word */
@@ -1053,7 +1074,7 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
<St_IntRef>{BLANK}+"\"" {
BEGIN(St_Ref2);
}
-<St_SetScope>({SCOPEMASK}|{ANONNS}){BLANK} {
+<St_SetScope>({SCOPEMASK}|{ANONNS}){BLANK}|{FILEMASK} {
g_token->name = yytext;
g_token->name = g_token->name.stripWhiteSpace();
return TK_WORD;
@@ -1085,11 +1106,15 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->name = yytext;
return TK_SYMBOL;
}
+<St_Ref2>{EMOJI} { /* emoji */
+ g_token->name = yytext;
+ return TK_EMOJI;
+ }
<St_Ref2>{SPCMD1} |
<St_Ref2>{SPCMD2} { /* special command */
g_token->name = yytext+1;
g_token->paramDir=TokenInfo::Unspecified;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<St_Ref2>{WORD1NQ} |
<St_Ref2>{WORD2NQ} {
@@ -1147,6 +1172,16 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->chars=yytext;
return TK_WHITESPACE;
}
+<St_Options>{ID} {
+ g_token->name+=yytext;
+ }
+<St_Options>{WS}*","{WS}*
+<St_Options>{WS} { /* option separator */
+ g_token->name+=",";
+ }
+<St_Options>"}" {
+ return TK_WORD;
+ }
<St_File>{FILEMASK} {
g_token->name = yytext;
return TK_WORD;
@@ -1311,7 +1346,7 @@ REFWORD_NOCV {LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
<*>[\\@<>&$#%~"=] { /* unescaped special character */
//warn(g_fileName,yylineno,"Unexpected character `%s', assuming command \\%s was meant.",yytext,yytext);
g_token->name = yytext;
- return TK_COMMAND;
+ return TK_COMMAND_SEL();
}
<*>. {
warn(g_fileName,yylineno,"Unexpected character `%s'",yytext);
@@ -1509,6 +1544,12 @@ void doctokenizerYYsetStateSetScope()
BEGIN(St_SetScope);
}
+void doctokenizerYYsetStateOptions()
+{
+ g_token->name="";
+ BEGIN(St_Options);
+}
+
void doctokenizerYYcleanup()
{
yy_delete_buffer( YY_CURRENT_BUFFER );
diff --git a/src/docvisitor.h b/src/docvisitor.h
index 18fb743..d2318c9 100644
--- a/src/docvisitor.h
+++ b/src/docvisitor.h
@@ -37,6 +37,7 @@ class DocAutoListItem;
class DocPara;
class DocRoot;
class DocSymbol;
+class DocEmoji;
class DocURL;
class DocStyleChange;
class DocSimpleSect;
@@ -101,6 +102,7 @@ class DocVisitor
virtual void visit(DocWord *) = 0;
virtual void visit(DocWhiteSpace *) = 0;
virtual void visit(DocSymbol *) = 0;
+ virtual void visit(DocEmoji *) = 0;
virtual void visit(DocURL *) = 0;
virtual void visit(DocStyleChange *) = 0;
virtual void visit(DocVerbatim *) = 0;
diff --git a/src/dot.cpp b/src/dot.cpp
index 7b29569..f07a365 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -139,7 +139,7 @@ static const char svgZoomFooter[] =
" <path fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" d=\"M0,-3.0v7 M-2.5,-0.5L0,-3.0L2.5,-0.5\"/>\n"
" </g>\n"
" </g>\n"
-// link to orginial SVG
+// link to original SVG
" <svg viewBox=\"0 0 15 15\" width=\"100%\" height=\"30px\" preserveAspectRatio=\"xMaxYMin meet\">\n"
" <g id=\"arrow_out\" transform=\"scale(0.3 0.3)\">\n"
" <a xlink:href=\"$orgname\" target=\"_base\">\n"
@@ -1383,6 +1383,11 @@ bool DotManager::run()
setDotFontPath(Config_getString(RTF_OUTPUT));
setPath=TRUE;
}
+ else if (Config_getBool(GENERATE_DOCBOOK))
+ {
+ setDotFontPath(Config_getString(DOCBOOK_OUTPUT));
+ setPath=TRUE;
+ }
portable_sysTimerStart();
// fill work queue with dot operations
DotRunner *dr;
@@ -3242,29 +3247,15 @@ QCString DotClassGraph::writeGraph(FTextStream &out,
if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
{
out << "<para>" << endl;
- out << " <figure>" << endl;
- out << " <title>";
- switch (m_graphType)
- {
- case DotNode::Collaboration:
- out << "Collaboration graph";
- break;
- case DotNode::Inheritance:
- out << "Inheritance graph";
- break;
- default:
- ASSERT(0);
- break;
- }
- out << "</title>" << endl;
+ out << " <informalfigure>" << endl;
out << " <mediaobject>" << endl;
out << " <imageobject>" << endl;
out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"1\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
+ out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
out << "</imagedata>" << endl;
out << " </imageobject>" << endl;
out << " </mediaobject>" << endl;
- out << " </figure>" << endl;
+ out << " </informalfigure>" << endl;
out << "</para>" << endl;
}
else if (graphFormat==GOF_BITMAP && generateImageMap) // produce HTML to include the image
@@ -3601,17 +3592,15 @@ QCString DotInclDepGraph::writeGraph(FTextStream &out,
if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
{
out << "<para>" << endl;
- out << " <figure>" << endl;
- out << " <title>Dependency diagram";
- out << "</title>" << endl;
+ out << " <informalfigure>" << endl;
out << " <mediaobject>" << endl;
out << " <imageobject>" << endl;
out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"1\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
+ out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
out << "</imagedata>" << endl;
out << " </imageobject>" << endl;
out << " </mediaobject>" << endl;
- out << " </figure>" << endl;
+ out << " </informalfigure>" << endl;
out << "</para>" << endl;
}
else if (graphFormat==GOF_BITMAP && generateImageMap)
@@ -3922,17 +3911,15 @@ QCString DotCallGraph::writeGraph(FTextStream &out, GraphOutputFormat graphForma
if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
{
out << "<para>" << endl;
- out << " <figure>" << endl;
- out << " <title>Call diagram";
- out << "</title>" << endl;
+ out << " <informalfigure>" << endl;
out << " <mediaobject>" << endl;
out << " <imageobject>" << endl;
out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"1\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
+ out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
out << "</imagedata>" << endl;
out << " </imageobject>" << endl;
out << " </mediaobject>" << endl;
- out << " </figure>" << endl;
+ out << " </informalfigure>" << endl;
out << "</para>" << endl;
}
else if (graphFormat==GOF_BITMAP && generateImageMap)
@@ -4087,17 +4074,15 @@ QCString DotDirDeps::writeGraph(FTextStream &out,
if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
{
out << "<para>" << endl;
- out << " <figure>" << endl;
- out << " <title>Directory Dependency diagram";
- out << "</title>" << endl;
+ out << " <informalfigure>" << endl;
out << " <mediaobject>" << endl;
out << " <imageobject>" << endl;
out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"1\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
+ out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
out << "</imagedata>" << endl;
out << " </imageobject>" << endl;
out << " </mediaobject>" << endl;
- out << " </figure>" << endl;
+ out << " </informalfigure>" << endl;
out << "</para>" << endl;
}
else if (graphFormat==GOF_BITMAP && generateImageMap)
@@ -4650,17 +4635,15 @@ QCString DotGroupCollaboration::writeGraph( FTextStream &t,
if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
{
t << "<para>" << endl;
- t << " <figure>" << endl;
- t << " <title>Group Collaboration diagram";
- t << "</title>" << endl;
+ t << " <informalfigure>" << endl;
t << " <mediaobject>" << endl;
t << " <imageobject>" << endl;
t << " <imagedata";
- t << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"1\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
+ t << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
t << "</imagedata>" << endl;
t << " </imageobject>" << endl;
t << " </mediaobject>" << endl;
- t << " </figure>" << endl;
+ t << " </informalfigure>" << endl;
t << "</para>" << endl;
}
else if (graphFormat==GOF_BITMAP && writeImageMap)
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 68b49c2..9bf4f0f 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -103,6 +103,7 @@
#include "settings.h"
#include "context.h"
#include "fileparser.h"
+#include "emoji.h"
// provided by the generated file resources.cpp
extern void initResources();
@@ -167,6 +168,7 @@ bool Doxygen::suppressDocWarnings = FALSE;
Store *Doxygen::symbolStorage;
QCString Doxygen::objDBFileName;
QCString Doxygen::entryDBFileName;
+QCString Doxygen::filterDBFileName;
bool Doxygen::gatherDefines = TRUE;
IndexList *Doxygen::indexList;
int Doxygen::subpageNestingLevel = 0;
@@ -346,6 +348,7 @@ static STLInfo g_stlinfo[] =
{ "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
{ "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
{ "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
+ { "shared_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++14
{ "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
{ "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
{ "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
@@ -519,7 +522,7 @@ static void addSTLClasses(EntryNav *rootNav)
{
addSTLMember(classEntryNav,info->templType2,info->templName2);
}
- if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
+ if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" || fullName=="std::shared_ptr" ||
fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
{
Entry *memEntry = new Entry;
@@ -2186,6 +2189,8 @@ static void findUsingDeclImports(EntryNav *rootNav)
newMd->setDefinition(md->definition());
newMd->enableCallGraph(root->callGraph);
newMd->enableCallerGraph(root->callerGraph);
+ newMd->enableReferencedByRelation(root->referencedByRelation);
+ newMd->enableReferencesRelation(root->referencesRelation);
newMd->setBitfields(md->bitfieldString());
newMd->addSectionsToDefinition(root->anchors);
newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
@@ -2382,6 +2387,8 @@ static MemberDef *addVariableToClass(
md->setWriteAccessor(root->write);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
md->setHidden(root->hidden);
md->setArtificial(root->artificial);
md->setLanguage(root->lang);
@@ -2619,6 +2626,8 @@ static MemberDef *addVariableToFile(
md->setId(root->id);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
md->setExplicitExternal(root->explicitExternal);
//md->setOuterScope(fd);
if (!root->explicitExternal)
@@ -3132,6 +3141,8 @@ static void addInterfaceOrServiceToServiceOrSingleton(
md->setDefinition(def);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
Debug::print(Debug::Functions,0,
" Interface Member:\n"
@@ -3384,6 +3395,8 @@ static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
md->setDefinition(def);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
Debug::print(Debug::Functions,0,
" Func Member:\n"
@@ -3651,6 +3664,8 @@ static void buildFunctionList(EntryNav *rootNav)
md->enableCallGraph(md->hasCallGraph() || root->callGraph);
md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
+ md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
+ md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
// merge ingroup specifiers
if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
@@ -3770,6 +3785,8 @@ static void buildFunctionList(EntryNav *rootNav)
md->setDefinition(def);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
//if (root->mGrpId!=-1)
//{
// md->setMemberGroup(memberGroupDict[root->mGrpId]);
@@ -3921,8 +3938,13 @@ static void findFriends()
mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
+ mmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
+ mmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
+
fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
+ fmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
+ fmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
}
}
}
@@ -5322,6 +5344,8 @@ static void addMemberDocs(EntryNav *rootNav,
md->setDefinition(fDecl);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
ClassDef *cd=md->getClassDef();
NamespaceDef *nd=md->getNamespaceDef();
QCString fullName;
@@ -5414,6 +5438,8 @@ static void addMemberDocs(EntryNav *rootNav,
md->enableCallGraph(md->hasCallGraph() || root->callGraph);
md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
+ md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
+ md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
md->mergeMemberSpecifiers(root->spec);
md->addSectionsToDefinition(root->anchors);
@@ -6446,6 +6472,8 @@ static void findMember(EntryNav *rootNav,
md->setDefinition(funcDecl);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
md->setDocumentation(root->doc,root->docFile,root->docLine);
md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
@@ -6511,6 +6539,8 @@ static void findMember(EntryNav *rootNav,
md->setDefinition(funcDecl);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
QCString doc=getOverloadDocs();
doc+="<p>";
doc+=root->doc;
@@ -6715,6 +6745,8 @@ static void findMember(EntryNav *rootNav,
md->setDefinition(funcDecl);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
md->setDocumentation(root->doc,root->docFile,root->docLine);
md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
md->setDocsForDefinition(!root->proto);
@@ -6787,6 +6819,8 @@ localObjCMethod:
md->setDefinition(funcDecl);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
md->setDocumentation(root->doc,root->docFile,root->docLine);
md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
@@ -7129,6 +7163,8 @@ static void findEnums(EntryNav *rootNav)
md->setMemberGroupId(root->mGrpId);
md->enableCallGraph(root->callGraph);
md->enableCallerGraph(root->callerGraph);
+ md->enableReferencedByRelation(root->referencedByRelation);
+ md->enableReferencesRelation(root->referencesRelation);
//printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
md->setRefItems(root->sli);
//printf("found enum %s nd=%p\n",md->name().data(),nd);
@@ -7696,7 +7732,7 @@ static void computeMemberRelations()
// bmcd->name().data(),bmd->name().data(),bmd
// );
if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
- (bmd->virtualness()!=Normal ||
+ (bmd->virtualness()!=Normal || bmd->getLanguage()==SrcLangExt_Python ||
bmcd->compoundType()==ClassDef::Interface ||
bmcd->compoundType()==ClassDef::Protocol
) &&
@@ -8926,7 +8962,7 @@ static void generatePageDocs()
static void buildExampleList(EntryNav *rootNav)
{
- if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
+ if ((rootNav->section()==Entry::EXAMPLE_SEC || rootNav->section()==Entry::EXAMPLE_LINENO_SEC) && !rootNav->name().isEmpty())
{
rootNav->loadEntry(g_storage);
Entry *root = rootNav->entry();
@@ -8947,7 +8983,7 @@ static void buildExampleList(EntryNav *rootNav)
pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
pd->addSectionsToDefinition(root->anchors);
pd->setLanguage(root->lang);
- //pi->addSections(root->anchors);
+ pd->setShowLineNo(rootNav->section()==Entry::EXAMPLE_LINENO_SEC);
Doxygen::exampleSDict->inSort(root->name,pd);
//we don't add example to groups
@@ -8996,11 +9032,16 @@ static void generateExampleDocs()
g_outputList->docify(pd->name());
endTitle(*g_outputList,n,0);
g_outputList->startContents();
+ QCString lineNoOptStr;
+ if (pd->showLineNo())
+ {
+ lineNoOptStr="{lineno}";
+ }
g_outputList->generateDoc(pd->docFile(), // file
pd->docLine(), // startLine
pd, // context
0, // memberDef
- pd->documentation()+"\n\n\\include "+pd->name(), // docs
+ pd->documentation()+"\n\n\\include"+lineNoOptStr+" "+pd->name(), // docs
TRUE, // index words
TRUE, // is example
pd->name()
@@ -9146,7 +9187,24 @@ static void generateConfigFile(const char *configFile,bool shortList,
exit(1);
}
}
-
+static void compareDoxyfile()
+{
+ QFile f;
+ char configFile[2];
+ configFile[0] = '-';
+ configFile[1] = '\0';
+ bool fileOpened=openOutputFile(configFile,f);
+ if (fileOpened)
+ {
+ FTextStream t(&f);
+ Config::compareDoxyfile(t);
+ }
+ else
+ {
+ err("Cannot open file %s for writing\n",configFile);
+ exit(1);
+ }
+}
//----------------------------------------------------------------------------
// read and parse a tag file
@@ -9628,7 +9686,7 @@ int readDir(QFileInfo *fi,
{
fn = new FileName(cfi->absFilePath().utf8(),name);
fn->append(fd);
- if (fnList) fnList->inSort(fn);
+ if (fnList) fnList->append(fn);
fnDict->insert(name,fn);
}
}
@@ -9727,7 +9785,7 @@ int readFileOrDirectory(const char *s,
{
fn = new FileName(filePath,name);
fn->append(fd);
- if (fnList) fnList->inSort(fn);
+ if (fnList) fnList->append(fn);
fnDict->insert(name,fn);
}
}
@@ -9866,7 +9924,7 @@ static void escapeAliases()
while ((in=value.find("^^",p))!=-1)
{
newValue+=value.mid(p,in-p);
- newValue+="\n";
+ newValue+="@_linebr";
p=in+2;
}
newValue+=value.mid(p,value.length()-p);
@@ -10004,6 +10062,11 @@ static void usage(const char *name)
msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
msg("6) Use doxygen to generate a rtf extensions file\n");
msg(" RTF: %s -e rtf extensionsFile\n\n",name);
+ msg("7) Use doxygen to compare the used configuration file with the template configuration file\n");
+ msg(" %s -x [configFile]\n\n",name);
+ msg("8) Use doxygen to show a list of build in emoji.\n");
+ msg(" %s -f emoji outputFileName\n\n",name);
+ msg(" If - is used for outputFileName doxygen will write to standard output.\n\n");
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\n");
msg("-v print version string\n");
@@ -10204,10 +10267,11 @@ void readConfiguration(int argc, char **argv)
const char *layoutName=0;
const char *debugLabel;
const char *formatName;
+ const char *listName;
bool genConfig=FALSE;
bool shortList=FALSE;
+ bool diffList=FALSE;
bool updateConfig=FALSE;
- bool genLayout=FALSE;
int retVal;
while (optind<argc && argv[optind][0]=='-' &&
(isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
@@ -10220,10 +10284,12 @@ void readConfiguration(int argc, char **argv)
genConfig=TRUE;
break;
case 'l':
- genLayout=TRUE;
layoutName=getArg(argc,argv,optind);
if (!layoutName)
{ layoutName="DoxygenLayout.xml"; }
+ writeDefaultLayoutFile(layoutName);
+ cleanUpDoxygen();
+ exit(0);
break;
case 'd':
debugLabel=getArg(argc,argv,optind);
@@ -10242,6 +10308,9 @@ void readConfiguration(int argc, char **argv)
exit(1);
}
break;
+ case 'x':
+ diffList=TRUE;
+ break;
case 's':
shortList=TRUE;
break;
@@ -10276,6 +10345,34 @@ void readConfiguration(int argc, char **argv)
cleanUpDoxygen();
exit(1);
break;
+ case 'f':
+ listName=getArg(argc,argv,optind);
+ if (!listName)
+ {
+ err("option \"-f\" is missing list specifier.\n");
+ cleanUpDoxygen();
+ exit(1);
+ }
+ if (qstricmp(listName,"emoji")==0)
+ {
+ if (optind+1>=argc)
+ {
+ err("option \"-f emoji\" is missing an output file name\n");
+ cleanUpDoxygen();
+ exit(1);
+ }
+ QFile f;
+ if (openOutputFile(argv[optind+1],f))
+ {
+ EmojiEntityMapper::instance()->writeEmojiFile(f);
+ }
+ cleanUpDoxygen();
+ exit(0);
+ }
+ err("option \"-f\" has invalid list specifier.\n");
+ cleanUpDoxygen();
+ exit(1);
+ break;
case 'w':
formatName=getArg(argc,argv,optind);
if (!formatName)
@@ -10492,6 +10589,7 @@ void readConfiguration(int argc, char **argv)
exit(1);
}
}
+
if (genConfig && g_useOutputTemplate)
{
generateTemplateFiles("templates");
@@ -10505,12 +10603,6 @@ void readConfiguration(int argc, char **argv)
cleanUpDoxygen();
exit(0);
}
- if (genLayout)
- {
- writeDefaultLayoutFile(layoutName);
- cleanUpDoxygen();
- exit(0);
- }
if (!Config::parse(configName,updateConfig))
{
@@ -10519,6 +10611,13 @@ void readConfiguration(int argc, char **argv)
exit(1);
}
+ if (diffList)
+ {
+ compareDoxyfile();
+ cleanUpDoxygen();
+ exit(0);
+ }
+
if (updateConfig)
{
generateConfigFile(configName,shortList,TRUE);
@@ -10648,6 +10747,10 @@ static void stopDoxygen(int)
{
thisDir.remove(Doxygen::objDBFileName);
}
+ if (!Doxygen::filterDBFileName.isEmpty())
+ {
+ thisDir.remove(Doxygen::filterDBFileName);
+ }
killpg(0,SIGINT);
exit(1);
}
@@ -10748,6 +10851,10 @@ static void exitDoxygen()
{
thisDir.remove(Doxygen::objDBFileName);
}
+ if (!Doxygen::filterDBFileName.isEmpty())
+ {
+ thisDir.remove(Doxygen::filterDBFileName);
+ }
}
}
@@ -10923,6 +11030,7 @@ void searchInputFiles()
}
s=inputList.next();
}
+ Doxygen::inputNameList->sort();
delete killDict;
g_s.end();
}
@@ -10987,6 +11095,8 @@ void parseInput()
Doxygen::objDBFileName.prepend(outputDirectory+"/");
Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
Doxygen::entryDBFileName.prepend(outputDirectory+"/");
+ Doxygen::filterDBFileName.sprintf("doxygen_filterdb_%d.tmp",pid);
+ Doxygen::filterDBFileName.prepend(outputDirectory+"/");
if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
{
@@ -11100,14 +11210,20 @@ void parseInput()
// Notice: the order of the function calls below is very important!
- if (Config_getBool(GENERATE_HTML))
+ if (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX))
{
readFormulaRepository(Config_getString(HTML_OUTPUT));
}
if (Config_getBool(GENERATE_RTF))
{
// in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
- readFormulaRepository(Config_getString(RTF_OUTPUT),Config_getBool(GENERATE_HTML));
+ readFormulaRepository(Config_getString(RTF_OUTPUT),Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX));
+ }
+ if (Config_getBool(GENERATE_DOCBOOK))
+ {
+ // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
+ readFormulaRepository(Config_getString(DOCBOOK_OUTPUT),
+ (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX)) || Config_getBool(GENERATE_RTF));
}
/**************************************************************************
@@ -11456,6 +11572,7 @@ void generateOutput()
bool generateLatex = Config_getBool(GENERATE_LATEX);
bool generateMan = Config_getBool(GENERATE_MAN);
bool generateRtf = Config_getBool(GENERATE_RTF);
+ bool generateDocbook = Config_getBool(GENERATE_DOCBOOK);
g_outputList = new OutputList(TRUE);
@@ -11483,6 +11600,11 @@ void generateOutput()
g_outputList->add(new LatexGenerator);
LatexGenerator::init();
}
+ if (generateDocbook)
+ {
+ g_outputList->add(new DocbookGenerator);
+ DocbookGenerator::init();
+ }
if (generateMan)
{
g_outputList->add(new ManGenerator);
@@ -11509,6 +11631,7 @@ void generateOutput()
if (generateHtml) writeDoxFont(Config_getString(HTML_OUTPUT));
if (generateLatex) writeDoxFont(Config_getString(LATEX_OUTPUT));
+ if (generateDocbook) writeDoxFont(Config_getString(DOCBOOK_OUTPUT));
if (generateRtf) writeDoxFont(Config_getString(RTF_OUTPUT));
g_s.begin("Generating style sheet...\n");
@@ -11602,6 +11725,13 @@ void generateOutput()
g_s.end();
}
+ if (Doxygen::formulaList->count()>0 && generateDocbook)
+ {
+ g_s.begin("Generating bitmaps for formulas in Docbook...\n");
+ Doxygen::formulaList->generateBitmaps(Config_getString(DOCBOOK_OUTPUT));
+ g_s.end();
+ }
+
if (Config_getBool(SORT_GROUP_NAMES))
{
Doxygen::groupSDict->sort();
@@ -11634,6 +11764,8 @@ void generateOutput()
removeDoxFont(Config_getString(RTF_OUTPUT));
if (generateLatex)
removeDoxFont(Config_getString(LATEX_OUTPUT));
+ if (generateDocbook)
+ removeDoxFont(Config_getString(DOCBOOK_OUTPUT));
}
if (Config_getBool(GENERATE_XML))
@@ -11651,13 +11783,6 @@ void generateOutput()
g_s.end();
}
- if (Config_getBool(GENERATE_DOCBOOK))
- {
- g_s.begin("Generating Docbook output...\n");
- generateDocbook();
- g_s.end();
- }
-
if (Config_getBool(GENERATE_AUTOGEN_DEF))
{
g_s.begin("Generating AutoGen DEF output...\n");
@@ -11728,6 +11853,10 @@ void generateOutput()
copyLogo(Config_getString(LATEX_OUTPUT));
copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
}
+ if (generateDocbook)
+ {
+ copyLogo(Config_getString(DOCBOOK_OUTPUT));
+ }
if (generateRtf)
{
copyLogo(Config_getString(RTF_OUTPUT));
@@ -11806,6 +11935,7 @@ void generateOutput()
Doxygen::symbolStorage->close();
QDir thisDir;
thisDir.remove(Doxygen::objDBFileName);
+ thisDir.remove(Doxygen::filterDBFileName);
Config::deinit();
QTextCodec::deleteAllCodecs();
delete Doxygen::symbolMap;
diff --git a/src/doxygen.h b/src/doxygen.h
index 7bd05a4..4ff8a56 100644
--- a/src/doxygen.h
+++ b/src/doxygen.h
@@ -140,6 +140,7 @@ class Doxygen
static Store *symbolStorage;
static QCString objDBFileName;
static QCString entryDBFileName;
+ static QCString filterDBFileName;
static CiteDict *citeDict;
static bool gatherDefines;
static bool userComments;
diff --git a/src/emoji.cpp b/src/emoji.cpp
new file mode 100644
index 0000000..f10ebc5
--- /dev/null
+++ b/src/emoji.cpp
@@ -0,0 +1,3187 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2018 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 "emoji.h"
+#include "message.h"
+#include "ftextstream.h"
+#include "util.h"
+
+/* to generate the content of this table see the documentation at the end of this file */
+static struct emojiEntityInfo
+{
+ const char *githubName;
+ const char *unicodeName;
+ const char *code;
+} g_emojiEntities[] =
+{
+ {":+1:", ":thumbs up:", "&#x1f44d;"},
+ {":-1:", ":thumbs down:", "&#x1f44e;"},
+ {":100:", ":hundred points:", "&#x1f4af;"},
+ {":1234:", ":input numbers:", "&#x1f522;"},
+ {":1st_place_medal:", ":1st place medal:", "&#x1f947;"},
+ {":2nd_place_medal:", ":2nd place medal:", "&#x1f948;"},
+ {":3rd_place_medal:", ":3rd place medal:", "&#x1f949;"},
+ {":8ball:", ":pool 8 ball:", "&#x1f3b1;"},
+ {":a:", ":a button (blood type):", "&#x1f170;"},
+ {":ab:", ":ab button (blood type):", "&#x1f18e;"},
+ {":abc:", ":input latin letters:", "&#x1f524;"},
+ {":abcd:", ":input latin lowercase:", "&#x1f521;"},
+ {":accept:", ":japanese \"acceptable\" button:", "&#x1f251;"},
+ {":aerial_tramway:", ":aerial tramway:", "&#x1f6a1;"},
+ {":afghanistan:", ":flag afghanistan:", "&#x1f1e6;&#x1f1eb;"},
+ {":airplane:", ":airplane:", "&#x2708;"},
+ {":aland_islands:", ":flag Ã…land islands:", "&#x1f1e6;&#x1f1fd;"},
+ {":alarm_clock:", ":alarm clock:", "&#x23f0;"},
+ {":albania:", ":flag albania:", "&#x1f1e6;&#x1f1f1;"},
+ {":alembic:", ":alembic:", "&#x2697;"},
+ {":algeria:", ":flag algeria:", "&#x1f1e9;&#x1f1ff;"},
+ {":alien:", ":alien:", "&#x1f47d;"},
+ {":ambulance:", ":ambulance:", "&#x1f691;"},
+ {":american_samoa:", ":flag american samoa:", "&#x1f1e6;&#x1f1f8;"},
+ {":amphora:", ":amphora:", "&#x1f3fa;"},
+ {":anchor:", ":anchor:", "&#x2693;"},
+ {":andorra:", ":flag andorra:", "&#x1f1e6;&#x1f1e9;"},
+ {":angel:", ":baby angel:", "&#x1f47c;"},
+ {":anger:", ":anger symbol:", "&#x1f4a2;"},
+ {":angola:", ":flag angola:", "&#x1f1e6;&#x1f1f4;"},
+ {":angry:", ":angry face:", "&#x1f620;"},
+ {":anguilla:", ":flag anguilla:", "&#x1f1e6;&#x1f1ee;"},
+ {":anguished:", ":anguished face:", "&#x1f627;"},
+ {":ant:", ":ant:", "&#x1f41c;"},
+ {":antarctica:", ":flag antarctica:", "&#x1f1e6;&#x1f1f6;"},
+ {":antigua_barbuda:", ":flag antigua & barbuda:", "&#x1f1e6;&#x1f1ec;"},
+ {":apple:", ":red apple:", "&#x1f34e;"},
+ {":aquarius:", ":aquarius:", "&#x2652;"},
+ {":argentina:", ":flag argentina:", "&#x1f1e6;&#x1f1f7;"},
+ {":aries:", ":aries:", "&#x2648;"},
+ {":armenia:", ":flag armenia:", "&#x1f1e6;&#x1f1f2;"},
+ {":arrow_backward:", ":reverse button:", "&#x25c0;"},
+ {":arrow_double_down:", ":fast down button:", "&#x23ec;"},
+ {":arrow_double_up:", ":fast up button:", "&#x23eb;"},
+ {":arrow_down:", ":down arrow:", "&#x2b07;"},
+ {":arrow_down_small:", ":downwards button:", "&#x1f53d;"},
+ {":arrow_forward:", ":play button:", "&#x25b6;"},
+ {":arrow_heading_down:", ":right arrow curving down:", "&#x2935;"},
+ {":arrow_heading_up:", ":right arrow curving up:", "&#x2934;"},
+ {":arrow_left:", ":left arrow:", "&#x2b05;"},
+ {":arrow_lower_left:", ":down-left arrow:", "&#x2199;"},
+ {":arrow_lower_right:", ":down-right arrow:", "&#x2198;"},
+ {":arrow_right:", ":right arrow:", "&#x27a1;"},
+ {":arrow_right_hook:", ":left arrow curving right:", "&#x21aa;"},
+ {":arrow_up:", ":up arrow:", "&#x2b06;"},
+ {":arrow_up_down:", ":up-down arrow:", "&#x2195;"},
+ {":arrow_up_small:", ":upwards button:", "&#x1f53c;"},
+ {":arrow_upper_left:", ":up-left arrow:", "&#x2196;"},
+ {":arrow_upper_right:", ":up-right arrow:", "&#x2197;"},
+ {":arrows_clockwise:", ":clockwise vertical arrows:", "&#x1f503;"},
+ {":arrows_counterclockwise:", ":counterclockwise arrows button:", "&#x1f504;"},
+ {":art:", ":artist palette:", "&#x1f3a8;"},
+ {":articulated_lorry:", ":articulated lorry:", "&#x1f69b;"},
+ {":artificial_satellite:", ":satellite:", "&#x1f6f0;"},
+ {":aruba:", ":flag aruba:", "&#x1f1e6;&#x1f1fc;"},
+ {":asterisk:", ":keycap *:", "&#x002a;&#xfe0f;&#x20e3;"},
+ {":astonished:", ":astonished face:", "&#x1f632;"},
+ {":athletic_shoe:", ":running shoe:", "&#x1f45f;"},
+ {":atm:", ":atm sign:", "&#x1f3e7;"},
+ {":atom_symbol:", ":atom symbol:", "&#x269b;"},
+ {":australia:", ":flag australia:", "&#x1f1e6;&#x1f1fa;"},
+ {":austria:", ":flag austria:", "&#x1f1e6;&#x1f1f9;"},
+ {":avocado:", ":avocado:", "&#x1f951;"},
+ {":azerbaijan:", ":flag azerbaijan:", "&#x1f1e6;&#x1f1ff;"},
+ {":b:", ":b button (blood type):", "&#x1f171;"},
+ {":baby:", ":baby:", "&#x1f476;"},
+ {":baby_bottle:", ":baby bottle:", "&#x1f37c;"},
+ {":baby_chick:", ":baby chick:", "&#x1f424;"},
+ {":baby_symbol:", ":baby symbol:", "&#x1f6bc;"},
+ {":back:", ":back arrow:", "&#x1f519;"},
+ {":bacon:", ":bacon:", "&#x1f953;"},
+ {":badminton:", ":badminton:", "&#x1f3f8;"},
+ {":baggage_claim:", ":baggage claim:", "&#x1f6c4;"},
+ {":baguette_bread:", ":baguette bread:", "&#x1f956;"},
+ {":bahamas:", ":flag bahamas:", "&#x1f1e7;&#x1f1f8;"},
+ {":bahrain:", ":flag bahrain:", "&#x1f1e7;&#x1f1ed;"},
+ {":balance_scale:", ":balance scale:", "&#x2696;"},
+ {":balloon:", ":balloon:", "&#x1f388;"},
+ {":ballot_box:", ":ballot box with ballot:", "&#x1f5f3;"},
+ {":ballot_box_with_check:", ":ballot box with check:", "&#x2611;"},
+ {":bamboo:", ":pine decoration:", "&#x1f38d;"},
+ {":banana:", ":banana:", "&#x1f34c;"},
+ {":bangbang:", ":double exclamation mark:", "&#x203c;"},
+ {":bangladesh:", ":flag bangladesh:", "&#x1f1e7;&#x1f1e9;"},
+ {":bank:", ":bank:", "&#x1f3e6;"},
+ {":bar_chart:", ":bar chart:", "&#x1f4ca;"},
+ {":barbados:", ":flag barbados:", "&#x1f1e7;&#x1f1e7;"},
+ {":barber:", ":barber pole:", "&#x1f488;"},
+ {":baseball:", ":baseball:", "&#x26be;"},
+ {":basketball:", ":basketball:", "&#x1f3c0;"},
+ {":basketball_man:", ":person bouncing ball:", "&#x26f9;"},
+ {":basketball_woman:", ":woman bouncing ball:", "&#x26f9;&#xfe0f;&#x200d;&#x2640;&#xfe0f;"},
+ {":bat:", ":bat:", "&#x1f987;"},
+ {":bath:", ":person taking bath:", "&#x1f6c0;"},
+ {":bathtub:", ":bathtub:", "&#x1f6c1;"},
+ {":battery:", ":battery:", "&#x1f50b;"},
+ {":beach_umbrella:", ":beach with umbrella:", "&#x1f3d6;"},
+ {":bear:", ":bear face:", "&#x1f43b;"},
+ {":bed:", ":bed:", "&#x1f6cf;"},
+ {":bee:", ":honeybee:", "&#x1f41d;"},
+ {":beer:", ":beer mug:", "&#x1f37a;"},
+ {":beers:", ":clinking beer mugs:", "&#x1f37b;"},
+ {":beetle:", ":lady beetle:", "&#x1f41e;"},
+ {":beginner:", ":japanese symbol for beginner:", "&#x1f530;"},
+ {":belarus:", ":flag belarus:", "&#x1f1e7;&#x1f1fe;"},
+ {":belgium:", ":flag belgium:", "&#x1f1e7;&#x1f1ea;"},
+ {":belize:", ":flag belize:", "&#x1f1e7;&#x1f1ff;"},
+ {":bell:", ":bell:", "&#x1f514;"},
+ {":bellhop_bell:", ":bellhop bell:", "&#x1f6ce;"},
+ {":benin:", ":flag benin:", "&#x1f1e7;&#x1f1ef;"},
+ {":bento:", ":bento box:", "&#x1f371;"},
+ {":bermuda:", ":flag bermuda:", "&#x1f1e7;&#x1f1f2;"},
+ {":bhutan:", ":flag bhutan:", "&#x1f1e7;&#x1f1f9;"},
+ {":bicyclist:", ":person biking:", "&#x1f6b4;"},
+ {":bike:", ":bicycle:", "&#x1f6b2;"},
+ {":biking_man:", ":person biking:", "&#x1f6b4;"},
+ {":biking_woman:", ":woman biking:", "&#x1f6b4;&#x200d;&#x2640;&#xfe0f;"},
+ {":bikini:", ":bikini:", "&#x1f459;"},
+ {":biohazard:", ":biohazard:", "&#x2623;"},
+ {":bird:", ":bird:", "&#x1f426;"},
+ {":birthday:", ":birthday cake:", "&#x1f382;"},
+ {":black_circle:", ":black circle:", "&#x26ab;"},
+ {":black_flag:", ":black flag:", "&#x1f3f4;"},
+ {":black_heart:", ":black heart:", "&#x1f5a4;"},
+ {":black_joker:", ":joker:", "&#x1f0cf;"},
+ {":black_large_square:", ":black large square:", "&#x2b1b;"},
+ {":black_medium_small_square:", ":black medium-small square:", "&#x25fe;"},
+ {":black_medium_square:", ":black medium square:", "&#x25fc;"},
+ {":black_nib:", ":black nib:", "&#x2712;"},
+ {":black_small_square:", ":black small square:", "&#x25aa;"},
+ {":black_square_button:", ":black square button:", "&#x1f532;"},
+ {":blonde_man:", ":person blond hair:", "&#x1f471;"},
+ {":blonde_woman:", ":woman blond hair:", "&#x1f471;&#x200d;&#x2640;&#xfe0f;"},
+ {":blossom:", ":blossom:", "&#x1f33c;"},
+ {":blowfish:", ":blowfish:", "&#x1f421;"},
+ {":blue_book:", ":blue book:", "&#x1f4d8;"},
+ {":blue_car:", ":sport utility vehicle:", "&#x1f699;"},
+ {":blue_heart:", ":blue heart:", "&#x1f499;"},
+ {":blush:", ":smiling face with smiling eyes:", "&#x1f60a;"},
+ {":boar:", ":boar:", "&#x1f417;"},
+ {":boat:", ":sailboat:", "&#x26f5;"},
+ {":bolivia:", ":flag bolivia:", "&#x1f1e7;&#x1f1f4;"},
+ {":bomb:", ":bomb:", "&#x1f4a3;"},
+ {":book:", ":open book:", "&#x1f4d6;"},
+ {":bookmark:", ":bookmark:", "&#x1f516;"},
+ {":bookmark_tabs:", ":bookmark tabs:", "&#x1f4d1;"},
+ {":books:", ":books:", "&#x1f4da;"},
+ {":boom:", ":collision:", "&#x1f4a5;"},
+ {":boot:", ":woman's boot:", "&#x1f462;"},
+ {":bosnia_herzegovina:", ":flag bosnia & herzegovina:", "&#x1f1e7;&#x1f1e6;"},
+ {":botswana:", ":flag botswana:", "&#x1f1e7;&#x1f1fc;"},
+ {":bouquet:", ":bouquet:", "&#x1f490;"},
+ {":bow:", ":person bowing:", "&#x1f647;"},
+ {":bow_and_arrow:", ":bow and arrow:", "&#x1f3f9;"},
+ {":bowing_man:", ":person bowing:", "&#x1f647;"},
+ {":bowing_woman:", ":woman bowing:", "&#x1f647;&#x200d;&#x2640;&#xfe0f;"},
+ {":bowling:", ":bowling:", "&#x1f3b3;"},
+ {":boxing_glove:", ":boxing glove:", "&#x1f94a;"},
+ {":boy:", ":boy:", "&#x1f466;"},
+ {":brazil:", ":flag brazil:", "&#x1f1e7;&#x1f1f7;"},
+ {":bread:", ":bread:", "&#x1f35e;"},
+ {":bride_with_veil:", ":bride with veil:", "&#x1f470;"},
+ {":bridge_at_night:", ":bridge at night:", "&#x1f309;"},
+ {":briefcase:", ":briefcase:", "&#x1f4bc;"},
+ {":british_indian_ocean_territory:", ":flag british indian ocean territory:", "&#x1f1ee;&#x1f1f4;"},
+ {":british_virgin_islands:", ":flag british virgin islands:", "&#x1f1fb;&#x1f1ec;"},
+ {":broken_heart:", ":broken heart:", "&#x1f494;"},
+ {":brunei:", ":flag brunei:", "&#x1f1e7;&#x1f1f3;"},
+ {":bug:", ":bug:", "&#x1f41b;"},
+ {":building_construction:", ":building construction:", "&#x1f3d7;"},
+ {":bulb:", ":light bulb:", "&#x1f4a1;"},
+ {":bulgaria:", ":flag bulgaria:", "&#x1f1e7;&#x1f1ec;"},
+ {":bullettrain_front:", ":bullet train:", "&#x1f685;"},
+ {":bullettrain_side:", ":high-speed train:", "&#x1f684;"},
+ {":burkina_faso:", ":flag burkina faso:", "&#x1f1e7;&#x1f1eb;"},
+ {":burrito:", ":burrito:", "&#x1f32f;"},
+ {":burundi:", ":flag burundi:", "&#x1f1e7;&#x1f1ee;"},
+ {":bus:", ":bus:", "&#x1f68c;"},
+ {":business_suit_levitating:", ":man in suit levitating:", "&#x1f574;"},
+ {":busstop:", ":bus stop:", "&#x1f68f;"},
+ {":bust_in_silhouette:", ":bust in silhouette:", "&#x1f464;"},
+ {":busts_in_silhouette:", ":busts in silhouette:", "&#x1f465;"},
+ {":butterfly:", ":butterfly:", "&#x1f98b;"},
+ {":cactus:", ":cactus:", "&#x1f335;"},
+ {":cake:", ":shortcake:", "&#x1f370;"},
+ {":calendar:", ":tear-off calendar:", "&#x1f4c6;"},
+ {":call_me_hand:", ":call me hand:", "&#x1f919;"},
+ {":calling:", ":mobile phone with arrow:", "&#x1f4f2;"},
+ {":cambodia:", ":flag cambodia:", "&#x1f1f0;&#x1f1ed;"},
+ {":camel:", ":two-hump camel:", "&#x1f42b;"},
+ {":camera:", ":camera:", "&#x1f4f7;"},
+ {":camera_flash:", ":camera with flash:", "&#x1f4f8;"},
+ {":cameroon:", ":flag cameroon:", "&#x1f1e8;&#x1f1f2;"},
+ {":camping:", ":camping:", "&#x1f3d5;"},
+ {":canada:", ":flag canada:", "&#x1f1e8;&#x1f1e6;"},
+ {":canary_islands:", ":flag canary islands:", "&#x1f1ee;&#x1f1e8;"},
+ {":cancer:", ":cancer:", "&#x264b;"},
+ {":candle:", ":candle:", "&#x1f56f;"},
+ {":candy:", ":candy:", "&#x1f36c;"},
+ {":canoe:", ":canoe:", "&#x1f6f6;"},
+ {":cape_verde:", ":flag cape verde:", "&#x1f1e8;&#x1f1fb;"},
+ {":capital_abcd:", ":input latin uppercase:", "&#x1f520;"},
+ {":capricorn:", ":capricorn:", "&#x2651;"},
+ {":car:", ":automobile:", "&#x1f697;"},
+ {":card_file_box:", ":card file box:", "&#x1f5c3;"},
+ {":card_index:", ":card index:", "&#x1f4c7;"},
+ {":card_index_dividers:", ":card index dividers:", "&#x1f5c2;"},
+ {":caribbean_netherlands:", ":flag caribbean netherlands:", "&#x1f1e7;&#x1f1f6;"},
+ {":carousel_horse:", ":carousel horse:", "&#x1f3a0;"},
+ {":carrot:", ":carrot:", "&#x1f955;"},
+ {":cat:", ":cat face:", "&#x1f431;"},
+ {":cat2:", ":cat:", "&#x1f408;"},
+ {":cayman_islands:", ":flag cayman islands:", "&#x1f1f0;&#x1f1fe;"},
+ {":cd:", ":optical disk:", "&#x1f4bf;"},
+ {":central_african_republic:", ":flag central african republic:", "&#x1f1e8;&#x1f1eb;"},
+ {":chad:", ":flag chad:", "&#x1f1f9;&#x1f1e9;"},
+ {":chains:", ":chains:", "&#x26d3;"},
+ {":champagne:", ":bottle with popping cork:", "&#x1f37e;"},
+ {":chart:", ":chart increasing with yen:", "&#x1f4b9;"},
+ {":chart_with_downwards_trend:", ":chart decreasing:", "&#x1f4c9;"},
+ {":chart_with_upwards_trend:", ":chart increasing:", "&#x1f4c8;"},
+ {":checkered_flag:", ":chequered flag:", "&#x1f3c1;"},
+ {":cheese:", ":cheese wedge:", "&#x1f9c0;"},
+ {":cherries:", ":cherries:", "&#x1f352;"},
+ {":cherry_blossom:", ":cherry blossom:", "&#x1f338;"},
+ {":chestnut:", ":chestnut:", "&#x1f330;"},
+ {":chicken:", ":chicken:", "&#x1f414;"},
+ {":children_crossing:", ":children crossing:", "&#x1f6b8;"},
+ {":chile:", ":flag chile:", "&#x1f1e8;&#x1f1f1;"},
+ {":chipmunk:", ":chipmunk:", "&#x1f43f;"},
+ {":chocolate_bar:", ":chocolate bar:", "&#x1f36b;"},
+ {":christmas_island:", ":flag christmas island:", "&#x1f1e8;&#x1f1fd;"},
+ {":christmas_tree:", ":christmas tree:", "&#x1f384;"},
+ {":church:", ":church:", "&#x26ea;"},
+ {":cinema:", ":cinema:", "&#x1f3a6;"},
+ {":circus_tent:", ":circus tent:", "&#x1f3aa;"},
+ {":city_sunrise:", ":sunset:", "&#x1f307;"},
+ {":city_sunset:", ":cityscape at dusk:", "&#x1f306;"},
+ {":cityscape:", ":cityscape:", "&#x1f3d9;"},
+ {":cl:", ":cl button:", "&#x1f191;"},
+ {":clamp:", ":clamp:", "&#x1f5dc;"},
+ {":clap:", ":clapping hands:", "&#x1f44f;"},
+ {":clapper:", ":clapper board:", "&#x1f3ac;"},
+ {":classical_building:", ":classical building:", "&#x1f3db;"},
+ {":clinking_glasses:", ":clinking glasses:", "&#x1f942;"},
+ {":clipboard:", ":clipboard:", "&#x1f4cb;"},
+ {":clock1:", ":one o'clock:", "&#x1f550;"},
+ {":clock10:", ":ten o'clock:", "&#x1f559;"},
+ {":clock1030:", ":ten-thirty:", "&#x1f565;"},
+ {":clock11:", ":eleven o'clock:", "&#x1f55a;"},
+ {":clock1130:", ":eleven-thirty:", "&#x1f566;"},
+ {":clock12:", ":twelve o'clock:", "&#x1f55b;"},
+ {":clock1230:", ":twelve-thirty:", "&#x1f567;"},
+ {":clock130:", ":one-thirty:", "&#x1f55c;"},
+ {":clock2:", ":two o'clock:", "&#x1f551;"},
+ {":clock230:", ":two-thirty:", "&#x1f55d;"},
+ {":clock3:", ":three o'clock:", "&#x1f552;"},
+ {":clock330:", ":three-thirty:", "&#x1f55e;"},
+ {":clock4:", ":four o'clock:", "&#x1f553;"},
+ {":clock430:", ":four-thirty:", "&#x1f55f;"},
+ {":clock5:", ":five o'clock:", "&#x1f554;"},
+ {":clock530:", ":five-thirty:", "&#x1f560;"},
+ {":clock6:", ":six o'clock:", "&#x1f555;"},
+ {":clock630:", ":six-thirty:", "&#x1f561;"},
+ {":clock7:", ":seven o'clock:", "&#x1f556;"},
+ {":clock730:", ":seven-thirty:", "&#x1f562;"},
+ {":clock8:", ":eight o'clock:", "&#x1f557;"},
+ {":clock830:", ":eight-thirty:", "&#x1f563;"},
+ {":clock9:", ":nine o'clock:", "&#x1f558;"},
+ {":clock930:", ":nine-thirty:", "&#x1f564;"},
+ {":closed_book:", ":closed book:", "&#x1f4d5;"},
+ {":closed_lock_with_key:", ":locked with key:", "&#x1f510;"},
+ {":closed_umbrella:", ":closed umbrella:", "&#x1f302;"},
+ {":cloud:", ":cloud:", "&#x2601;"},
+ {":cloud_with_lightning:", ":cloud with lightning:", "&#x1f329;"},
+ {":cloud_with_lightning_and_rain:", ":cloud with lightning and rain:", "&#x26c8;"},
+ {":cloud_with_rain:", ":cloud with rain:", "&#x1f327;"},
+ {":cloud_with_snow:", ":cloud with snow:", "&#x1f328;"},
+ {":clown_face:", ":clown face:", "&#x1f921;"},
+ {":clubs:", ":club suit:", "&#x2663;"},
+ {":cn:", ":flag china:", "&#x1f1e8;&#x1f1f3;"},
+ {":cocktail:", ":cocktail glass:", "&#x1f378;"},
+ {":cocos_islands:", ":flag cocos (keeling) islands:", "&#x1f1e8;&#x1f1e8;"},
+ {":coffee:", ":hot beverage:", "&#x2615;"},
+ {":coffin:", ":coffin:", "&#x26b0;"},
+ {":cold_sweat:", ":anxious face with sweat:", "&#x1f630;"},
+ {":collision:", ":collision:", "&#x1f4a5;"},
+ {":colombia:", ":flag colombia:", "&#x1f1e8;&#x1f1f4;"},
+ {":comet:", ":comet:", "&#x2604;"},
+ {":comoros:", ":flag comoros:", "&#x1f1f0;&#x1f1f2;"},
+ {":computer:", ":laptop computer:", "&#x1f4bb;"},
+ {":computer_mouse:", ":computer mouse:", "&#x1f5b1;"},
+ {":confetti_ball:", ":confetti ball:", "&#x1f38a;"},
+ {":confounded:", ":confounded face:", "&#x1f616;"},
+ {":confused:", ":confused face:", "&#x1f615;"},
+ {":congo_brazzaville:", ":flag congo - brazzaville:", "&#x1f1e8;&#x1f1ec;"},
+ {":congo_kinshasa:", ":flag congo - kinshasa:", "&#x1f1e8;&#x1f1e9;"},
+ {":congratulations:", ":japanese \"congratulations\" button:", "&#x3297;"},
+ {":construction:", ":construction:", "&#x1f6a7;"},
+ {":construction_worker:", ":construction worker:", "&#x1f477;"},
+ {":construction_worker_man:", ":construction worker:", "&#x1f477;"},
+ {":construction_worker_woman:", ":woman construction worker:", "&#x1f477;&#x200d;&#x2640;&#xfe0f;"},
+ {":control_knobs:", ":control knobs:", "&#x1f39b;"},
+ {":convenience_store:", ":convenience store:", "&#x1f3ea;"},
+ {":cook_islands:", ":flag cook islands:", "&#x1f1e8;&#x1f1f0;"},
+ {":cookie:", ":cookie:", "&#x1f36a;"},
+ {":cool:", ":cool button:", "&#x1f192;"},
+ {":cop:", ":police officer:", "&#x1f46e;"},
+ {":copyright:", ":copyright:", "&#x00a9;"},
+ {":corn:", ":ear of corn:", "&#x1f33d;"},
+ {":costa_rica:", ":flag costa rica:", "&#x1f1e8;&#x1f1f7;"},
+ {":cote_divoire:", ":flag côte d'ivoire:", "&#x1f1e8;&#x1f1ee;"},
+ {":couch_and_lamp:", ":couch and lamp:", "&#x1f6cb;"},
+ {":couple:", ":man and woman holding hands:", "&#x1f46b;"},
+ {":couple_with_heart:", ":couple with heart:", "&#x1f491;"},
+ {":couple_with_heart_man_man:", ":kiss man, man:", "&#x1f468;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f48b;&#x200d;&#x1f468;"},
+ {":couple_with_heart_woman_man:", ":couple with heart:", "&#x1f491;"},
+ {":couple_with_heart_woman_woman:", ":kiss woman, woman:", "&#x1f469;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f48b;&#x200d;&#x1f469;"},
+ {":couplekiss_man_man:", ":kiss man, man:", "&#x1f468;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f48b;&#x200d;&#x1f468;"},
+ {":couplekiss_man_woman:", ":kiss:", "&#x1f48f;"},
+ {":couplekiss_woman_woman:", ":kiss woman, woman:", "&#x1f469;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f48b;&#x200d;&#x1f469;"},
+ {":cow:", ":cow face:", "&#x1f42e;"},
+ {":cow2:", ":cow:", "&#x1f404;"},
+ {":cowboy_hat_face:", ":cowboy hat face:", "&#x1f920;"},
+ {":crab:", ":crab:", "&#x1f980;"},
+ {":crayon:", ":crayon:", "&#x1f58d;"},
+ {":credit_card:", ":credit card:", "&#x1f4b3;"},
+ {":crescent_moon:", ":crescent moon:", "&#x1f319;"},
+ {":cricket:", ":cricket game:", "&#x1f3cf;"},
+ {":croatia:", ":flag croatia:", "&#x1f1ed;&#x1f1f7;"},
+ {":crocodile:", ":crocodile:", "&#x1f40a;"},
+ {":croissant:", ":croissant:", "&#x1f950;"},
+ {":crossed_fingers:", ":crossed fingers:", "&#x1f91e;"},
+ {":crossed_flags:", ":crossed flags:", "&#x1f38c;"},
+ {":crossed_swords:", ":crossed swords:", "&#x2694;"},
+ {":crown:", ":crown:", "&#x1f451;"},
+ {":cry:", ":crying face:", "&#x1f622;"},
+ {":crying_cat_face:", ":crying cat face:", "&#x1f63f;"},
+ {":crystal_ball:", ":crystal ball:", "&#x1f52e;"},
+ {":cuba:", ":flag cuba:", "&#x1f1e8;&#x1f1fa;"},
+ {":cucumber:", ":cucumber:", "&#x1f952;"},
+ {":cupid:", ":heart with arrow:", "&#x1f498;"},
+ {":curacao:", ":flag curaçao:", "&#x1f1e8;&#x1f1fc;"},
+ {":curly_loop:", ":curly loop:", "&#x27b0;"},
+ {":currency_exchange:", ":currency exchange:", "&#x1f4b1;"},
+ {":curry:", ":curry rice:", "&#x1f35b;"},
+ {":custard:", ":custard:", "&#x1f36e;"},
+ {":customs:", ":customs:", "&#x1f6c3;"},
+ {":cyclone:", ":cyclone:", "&#x1f300;"},
+ {":cyprus:", ":flag cyprus:", "&#x1f1e8;&#x1f1fe;"},
+ {":czech_republic:", ":flag czechia:", "&#x1f1e8;&#x1f1ff;"},
+ {":dagger:", ":dagger:", "&#x1f5e1;"},
+ {":dancer:", ":woman dancing:", "&#x1f483;"},
+ {":dancers:", ":people with bunny ears:", "&#x1f46f;"},
+ {":dancing_men:", ":men with bunny ears:", "&#x1f46f;&#x200d;&#x2642;&#xfe0f;"},
+ {":dancing_women:", ":people with bunny ears:", "&#x1f46f;"},
+ {":dango:", ":dango:", "&#x1f361;"},
+ {":dark_sunglasses:", ":sunglasses:", "&#x1f576;"},
+ {":dart:", ":direct hit:", "&#x1f3af;"},
+ {":dash:", ":dashing away:", "&#x1f4a8;"},
+ {":date:", ":calendar:", "&#x1f4c5;"},
+ {":de:", ":flag germany:", "&#x1f1e9;&#x1f1ea;"},
+ {":deciduous_tree:", ":deciduous tree:", "&#x1f333;"},
+ {":deer:", ":deer:", "&#x1f98c;"},
+ {":denmark:", ":flag denmark:", "&#x1f1e9;&#x1f1f0;"},
+ {":department_store:", ":department store:", "&#x1f3ec;"},
+ {":derelict_house:", ":derelict house:", "&#x1f3da;"},
+ {":desert:", ":desert:", "&#x1f3dc;"},
+ {":desert_island:", ":desert island:", "&#x1f3dd;"},
+ {":desktop_computer:", ":desktop computer:", "&#x1f5a5;"},
+ {":detective:", ":detective:", "&#x1f575;"},
+ {":diamond_shape_with_a_dot_inside:", ":diamond with a dot:", "&#x1f4a0;"},
+ {":diamonds:", ":diamond suit:", "&#x2666;"},
+ {":disappointed:", ":disappointed face:", "&#x1f61e;"},
+ {":disappointed_relieved:", ":sad but relieved face:", "&#x1f625;"},
+ {":dizzy:", ":dizzy:", "&#x1f4ab;"},
+ {":dizzy_face:", ":dizzy face:", "&#x1f635;"},
+ {":djibouti:", ":flag djibouti:", "&#x1f1e9;&#x1f1ef;"},
+ {":do_not_litter:", ":no littering:", "&#x1f6af;"},
+ {":dog:", ":dog face:", "&#x1f436;"},
+ {":dog2:", ":dog:", "&#x1f415;"},
+ {":dollar:", ":dollar banknote:", "&#x1f4b5;"},
+ {":dolls:", ":japanese dolls:", "&#x1f38e;"},
+ {":dolphin:", ":dolphin:", "&#x1f42c;"},
+ {":dominica:", ":flag dominica:", "&#x1f1e9;&#x1f1f2;"},
+ {":dominican_republic:", ":flag dominican republic:", "&#x1f1e9;&#x1f1f4;"},
+ {":door:", ":door:", "&#x1f6aa;"},
+ {":doughnut:", ":doughnut:", "&#x1f369;"},
+ {":dove:", ":dove:", "&#x1f54a;"},
+ {":dragon:", ":dragon:", "&#x1f409;"},
+ {":dragon_face:", ":dragon face:", "&#x1f432;"},
+ {":dress:", ":dress:", "&#x1f457;"},
+ {":dromedary_camel:", ":camel:", "&#x1f42a;"},
+ {":drooling_face:", ":drooling face:", "&#x1f924;"},
+ {":droplet:", ":droplet:", "&#x1f4a7;"},
+ {":drum:", ":drum:", "&#x1f941;"},
+ {":duck:", ":duck:", "&#x1f986;"},
+ {":dvd:", ":dvd:", "&#x1f4c0;"},
+ {":e-mail:", ":e-mail:", "&#x1f4e7;"},
+ {":eagle:", ":eagle:", "&#x1f985;"},
+ {":ear:", ":ear:", "&#x1f442;"},
+ {":ear_of_rice:", ":sheaf of rice:", "&#x1f33e;"},
+ {":earth_africa:", ":globe showing europe-africa:", "&#x1f30d;"},
+ {":earth_americas:", ":globe showing americas:", "&#x1f30e;"},
+ {":earth_asia:", ":globe showing asia-australia:", "&#x1f30f;"},
+ {":ecuador:", ":flag ecuador:", "&#x1f1ea;&#x1f1e8;"},
+ {":egg:", ":egg:", "&#x1f95a;"},
+ {":eggplant:", ":eggplant:", "&#x1f346;"},
+ {":egypt:", ":flag egypt:", "&#x1f1ea;&#x1f1ec;"},
+ {":eight:", ":keycap 8:", "&#x0038;&#xfe0f;&#x20e3;"},
+ {":eight_pointed_black_star:", ":eight-pointed star:", "&#x2734;"},
+ {":eight_spoked_asterisk:", ":eight-spoked asterisk:", "&#x2733;"},
+ {":el_salvador:", ":flag el salvador:", "&#x1f1f8;&#x1f1fb;"},
+ {":electric_plug:", ":electric plug:", "&#x1f50c;"},
+ {":elephant:", ":elephant:", "&#x1f418;"},
+ {":email:", ":envelope:", "&#x2709;"},
+ {":end:", ":end arrow:", "&#x1f51a;"},
+ {":envelope:", ":envelope:", "&#x2709;"},
+ {":envelope_with_arrow:", ":envelope with arrow:", "&#x1f4e9;"},
+ {":equatorial_guinea:", ":flag equatorial guinea:", "&#x1f1ec;&#x1f1f6;"},
+ {":eritrea:", ":flag eritrea:", "&#x1f1ea;&#x1f1f7;"},
+ {":es:", ":flag spain:", "&#x1f1ea;&#x1f1f8;"},
+ {":estonia:", ":flag estonia:", "&#x1f1ea;&#x1f1ea;"},
+ {":ethiopia:", ":flag ethiopia:", "&#x1f1ea;&#x1f1f9;"},
+ {":eu:", ":flag european union:", "&#x1f1ea;&#x1f1fa;"},
+ {":euro:", ":euro banknote:", "&#x1f4b6;"},
+ {":european_castle:", ":castle:", "&#x1f3f0;"},
+ {":european_post_office:", ":post office:", "&#x1f3e4;"},
+ {":european_union:", ":flag european union:", "&#x1f1ea;&#x1f1fa;"},
+ {":evergreen_tree:", ":evergreen tree:", "&#x1f332;"},
+ {":exclamation:", ":exclamation mark:", "&#x2757;"},
+ {":expressionless:", ":expressionless face:", "&#x1f611;"},
+ {":eye:", ":eye in speech bubble:", "&#x1f441;&#xfe0f;&#x200d;&#x1f5e8;&#xfe0f;"},
+ {":eye_speech_bubble:", ":eye in speech bubble:", "&#x1f441;&#xfe0f;&#x200d;&#x1f5e8;&#xfe0f;"},
+ {":eyeglasses:", ":glasses:", "&#x1f453;"},
+ {":eyes:", ":eyes:", "&#x1f440;"},
+ {":face_with_head_bandage:", ":face with head-bandage:", "&#x1f915;"},
+ {":face_with_thermometer:", ":face with thermometer:", "&#x1f912;"},
+ {":facepunch:", ":oncoming fist:", "&#x1f44a;"},
+ {":factory:", ":factory:", "&#x1f3ed;"},
+ {":falkland_islands:", ":flag falkland islands:", "&#x1f1eb;&#x1f1f0;"},
+ {":fallen_leaf:", ":fallen leaf:", "&#x1f342;"},
+ {":family:", ":family:", "&#x1f46a;"},
+ {":family_man_boy:", ":family man, woman, boy:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f466;"},
+ {":family_man_boy_boy:", ":family man, woman, boy, boy:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {":family_man_girl:", ":family man, woman, girl:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f467;"},
+ {":family_man_girl_boy:", ":family man, woman, girl, boy:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {":family_man_girl_girl:", ":family man, woman, girl, girl:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {":family_man_man_boy:", ":family man, man, boy:", "&#x1f468;&#x200d;&#x1f468;&#x200d;&#x1f466;"},
+ {":family_man_man_boy_boy:", ":family man, man, boy, boy:", "&#x1f468;&#x200d;&#x1f468;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {":family_man_man_girl:", ":family man, man, girl:", "&#x1f468;&#x200d;&#x1f468;&#x200d;&#x1f467;"},
+ {":family_man_man_girl_boy:", ":family man, man, girl, boy:", "&#x1f468;&#x200d;&#x1f468;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {":family_man_man_girl_girl:", ":family man, man, girl, girl:", "&#x1f468;&#x200d;&#x1f468;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {":family_man_woman_boy:", ":family:", "&#x1f46a;"},
+ {":family_man_woman_boy_boy:", ":family man, woman, boy, boy:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {":family_man_woman_girl:", ":family man, woman, girl:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f467;"},
+ {":family_man_woman_girl_boy:", ":family man, woman, girl, boy:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {":family_man_woman_girl_girl:", ":family man, woman, girl, girl:", "&#x1f468;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {":family_woman_boy:", ":family woman, woman, boy:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f466;"},
+ {":family_woman_boy_boy:", ":family woman, woman, boy, boy:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {":family_woman_girl:", ":family woman, woman, girl:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f467;"},
+ {":family_woman_girl_boy:", ":family woman, woman, girl, boy:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {":family_woman_girl_girl:", ":family woman, woman, girl, girl:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {":family_woman_woman_boy:", ":family woman, woman, boy:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f466;"},
+ {":family_woman_woman_boy_boy:", ":family woman, woman, boy, boy:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {":family_woman_woman_girl:", ":family woman, woman, girl:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f467;"},
+ {":family_woman_woman_girl_boy:", ":family woman, woman, girl, boy:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {":family_woman_woman_girl_girl:", ":family woman, woman, girl, girl:", "&#x1f469;&#x200d;&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {":faroe_islands:", ":flag faroe islands:", "&#x1f1eb;&#x1f1f4;"},
+ {":fast_forward:", ":fast-forward button:", "&#x23e9;"},
+ {":fax:", ":fax machine:", "&#x1f4e0;"},
+ {":fearful:", ":fearful face:", "&#x1f628;"},
+ {":feet:", ":paw prints:", "&#x1f43e;"},
+ {":female_detective:", ":woman detective:", "&#x1f575;&#xfe0f;&#x200d;&#x2640;&#xfe0f;"},
+ {":ferris_wheel:", ":ferris wheel:", "&#x1f3a1;"},
+ {":ferry:", ":ferry:", "&#x26f4;"},
+ {":field_hockey:", ":field hockey:", "&#x1f3d1;"},
+ {":fiji:", ":flag fiji:", "&#x1f1eb;&#x1f1ef;"},
+ {":file_cabinet:", ":file cabinet:", "&#x1f5c4;"},
+ {":file_folder:", ":file folder:", "&#x1f4c1;"},
+ {":film_projector:", ":film projector:", "&#x1f4fd;"},
+ {":film_strip:", ":film frames:", "&#x1f39e;"},
+ {":finland:", ":flag finland:", "&#x1f1eb;&#x1f1ee;"},
+ {":fire:", ":fire:", "&#x1f525;"},
+ {":fire_engine:", ":fire engine:", "&#x1f692;"},
+ {":fireworks:", ":fireworks:", "&#x1f386;"},
+ {":first_quarter_moon:", ":first quarter moon:", "&#x1f313;"},
+ {":first_quarter_moon_with_face:", ":first quarter moon face:", "&#x1f31b;"},
+ {":fish:", ":fish:", "&#x1f41f;"},
+ {":fish_cake:", ":fish cake with swirl:", "&#x1f365;"},
+ {":fishing_pole_and_fish:", ":fishing pole:", "&#x1f3a3;"},
+ {":fist:", ":raised fist:", "&#x270a;"},
+ {":fist_left:", ":left-facing fist:", "&#x1f91b;"},
+ {":fist_oncoming:", ":oncoming fist:", "&#x1f44a;"},
+ {":fist_raised:", ":raised fist:", "&#x270a;"},
+ {":fist_right:", ":right-facing fist:", "&#x1f91c;"},
+ {":five:", ":keycap 5:", "&#x0035;&#xfe0f;&#x20e3;"},
+ {":flags:", ":carp streamer:", "&#x1f38f;"},
+ {":flashlight:", ":flashlight:", "&#x1f526;"},
+ {":fleur_de_lis:", ":fleur-de-lis:", "&#x269c;"},
+ {":flight_arrival:", ":airplane arrival:", "&#x1f6ec;"},
+ {":flight_departure:", ":airplane departure:", "&#x1f6eb;"},
+ {":flipper:", ":dolphin:", "&#x1f42c;"},
+ {":floppy_disk:", ":floppy disk:", "&#x1f4be;"},
+ {":flower_playing_cards:", ":flower playing cards:", "&#x1f3b4;"},
+ {":flushed:", ":flushed face:", "&#x1f633;"},
+ {":fog:", ":fog:", "&#x1f32b;"},
+ {":foggy:", ":foggy:", "&#x1f301;"},
+ {":football:", ":american football:", "&#x1f3c8;"},
+ {":footprints:", ":footprints:", "&#x1f463;"},
+ {":fork_and_knife:", ":fork and knife:", "&#x1f374;"},
+ {":fountain:", ":fountain:", "&#x26f2;"},
+ {":fountain_pen:", ":fountain pen:", "&#x1f58b;"},
+ {":four:", ":keycap 4:", "&#x0034;&#xfe0f;&#x20e3;"},
+ {":four_leaf_clover:", ":four leaf clover:", "&#x1f340;"},
+ {":fox_face:", ":fox face:", "&#x1f98a;"},
+ {":fr:", ":flag france:", "&#x1f1eb;&#x1f1f7;"},
+ {":framed_picture:", ":framed picture:", "&#x1f5bc;"},
+ {":free:", ":free button:", "&#x1f193;"},
+ {":french_guiana:", ":flag french guiana:", "&#x1f1ec;&#x1f1eb;"},
+ {":french_polynesia:", ":flag french polynesia:", "&#x1f1f5;&#x1f1eb;"},
+ {":french_southern_territories:", ":flag french southern territories:", "&#x1f1f9;&#x1f1eb;"},
+ {":fried_egg:", ":cooking:", "&#x1f373;"},
+ {":fried_shrimp:", ":fried shrimp:", "&#x1f364;"},
+ {":fries:", ":french fries:", "&#x1f35f;"},
+ {":frog:", ":frog face:", "&#x1f438;"},
+ {":frowning:", ":frowning face with open mouth:", "&#x1f626;"},
+ {":frowning_face:", ":frowning face:", "&#x2639;"},
+ {":frowning_man:", ":man frowning:", "&#x1f64d;&#x200d;&#x2642;&#xfe0f;"},
+ {":frowning_woman:", ":person frowning:", "&#x1f64d;"},
+ {":fu:", ":middle finger:", "&#x1f595;"},
+ {":fuelpump:", ":fuel pump:", "&#x26fd;"},
+ {":full_moon:", ":full moon:", "&#x1f315;"},
+ {":full_moon_with_face:", ":full moon face:", "&#x1f31d;"},
+ {":funeral_urn:", ":funeral urn:", "&#x26b1;"},
+ {":gabon:", ":flag gabon:", "&#x1f1ec;&#x1f1e6;"},
+ {":gambia:", ":flag gambia:", "&#x1f1ec;&#x1f1f2;"},
+ {":game_die:", ":game die:", "&#x1f3b2;"},
+ {":gb:", ":flag united kingdom:", "&#x1f1ec;&#x1f1e7;"},
+ {":gear:", ":gear:", "&#x2699;"},
+ {":gem:", ":gem stone:", "&#x1f48e;"},
+ {":gemini:", ":gemini:", "&#x264a;"},
+ {":georgia:", ":flag georgia:", "&#x1f1ec;&#x1f1ea;"},
+ {":ghana:", ":flag ghana:", "&#x1f1ec;&#x1f1ed;"},
+ {":ghost:", ":ghost:", "&#x1f47b;"},
+ {":gibraltar:", ":flag gibraltar:", "&#x1f1ec;&#x1f1ee;"},
+ {":gift:", ":wrapped gift:", "&#x1f381;"},
+ {":gift_heart:", ":heart with ribbon:", "&#x1f49d;"},
+ {":girl:", ":girl:", "&#x1f467;"},
+ {":globe_with_meridians:", ":globe with meridians:", "&#x1f310;"},
+ {":goal_net:", ":goal net:", "&#x1f945;"},
+ {":goat:", ":goat:", "&#x1f410;"},
+ {":golf:", ":flag in hole:", "&#x26f3;"},
+ {":golfing_man:", ":person golfing:", "&#x1f3cc;"},
+ {":golfing_woman:", ":woman golfing:", "&#x1f3cc;&#xfe0f;&#x200d;&#x2640;&#xfe0f;"},
+ {":gorilla:", ":gorilla:", "&#x1f98d;"},
+ {":grapes:", ":grapes:", "&#x1f347;"},
+ {":greece:", ":flag greece:", "&#x1f1ec;&#x1f1f7;"},
+ {":green_apple:", ":green apple:", "&#x1f34f;"},
+ {":green_book:", ":green book:", "&#x1f4d7;"},
+ {":green_heart:", ":green heart:", "&#x1f49a;"},
+ {":green_salad:", ":green salad:", "&#x1f957;"},
+ {":greenland:", ":flag greenland:", "&#x1f1ec;&#x1f1f1;"},
+ {":grenada:", ":flag grenada:", "&#x1f1ec;&#x1f1e9;"},
+ {":grey_exclamation:", ":white exclamation mark:", "&#x2755;"},
+ {":grey_question:", ":white question mark:", "&#x2754;"},
+ {":grimacing:", ":grimacing face:", "&#x1f62c;"},
+ {":grin:", ":beaming face with smiling eyes:", "&#x1f601;"},
+ {":grinning:", ":grinning face:", "&#x1f600;"},
+ {":guadeloupe:", ":flag guadeloupe:", "&#x1f1ec;&#x1f1f5;"},
+ {":guam:", ":flag guam:", "&#x1f1ec;&#x1f1fa;"},
+ {":guardsman:", ":guard:", "&#x1f482;"},
+ {":guardswoman:", ":woman guard:", "&#x1f482;&#x200d;&#x2640;&#xfe0f;"},
+ {":guatemala:", ":flag guatemala:", "&#x1f1ec;&#x1f1f9;"},
+ {":guernsey:", ":flag guernsey:", "&#x1f1ec;&#x1f1ec;"},
+ {":guinea:", ":flag guinea:", "&#x1f1ec;&#x1f1f3;"},
+ {":guinea_bissau:", ":flag guinea-bissau:", "&#x1f1ec;&#x1f1fc;"},
+ {":guitar:", ":guitar:", "&#x1f3b8;"},
+ {":gun:", ":pistol:", "&#x1f52b;"},
+ {":guyana:", ":flag guyana:", "&#x1f1ec;&#x1f1fe;"},
+ {":haircut:", ":person getting haircut:", "&#x1f487;"},
+ {":haircut_man:", ":man getting haircut:", "&#x1f487;&#x200d;&#x2642;&#xfe0f;"},
+ {":haircut_woman:", ":person getting haircut:", "&#x1f487;"},
+ {":haiti:", ":flag haiti:", "&#x1f1ed;&#x1f1f9;"},
+ {":hamburger:", ":hamburger:", "&#x1f354;"},
+ {":hammer:", ":hammer:", "&#x1f528;"},
+ {":hammer_and_pick:", ":hammer and pick:", "&#x2692;"},
+ {":hammer_and_wrench:", ":hammer and wrench:", "&#x1f6e0;"},
+ {":hamster:", ":hamster face:", "&#x1f439;"},
+ {":hand:", ":raised hand:", "&#x270b;"},
+ {":handbag:", ":handbag:", "&#x1f45c;"},
+ {":handshake:", ":handshake:", "&#x1f91d;"},
+ {":hankey:", ":pile of poo:", "&#x1f4a9;"},
+ {":hash:", ":keycap #:", "&#x0023;&#xfe0f;&#x20e3;"},
+ {":hatched_chick:", ":front-facing baby chick:", "&#x1f425;"},
+ {":hatching_chick:", ":hatching chick:", "&#x1f423;"},
+ {":headphones:", ":headphone:", "&#x1f3a7;"},
+ {":hear_no_evil:", ":hear-no-evil monkey:", "&#x1f649;"},
+ {":heart:", ":red heart:", "&#x2764;"},
+ {":heart_decoration:", ":heart decoration:", "&#x1f49f;"},
+ {":heart_eyes:", ":smiling face with heart-eyes:", "&#x1f60d;"},
+ {":heart_eyes_cat:", ":smiling cat face with heart-eyes:", "&#x1f63b;"},
+ {":heartbeat:", ":beating heart:", "&#x1f493;"},
+ {":heartpulse:", ":growing heart:", "&#x1f497;"},
+ {":hearts:", ":heart suit:", "&#x2665;"},
+ {":heavy_check_mark:", ":heavy check mark:", "&#x2714;"},
+ {":heavy_division_sign:", ":heavy division sign:", "&#x2797;"},
+ {":heavy_dollar_sign:", ":heavy dollar sign:", "&#x1f4b2;"},
+ {":heavy_exclamation_mark:", ":exclamation mark:", "&#x2757;"},
+ {":heavy_heart_exclamation:", ":heavy heart exclamation:", "&#x2763;"},
+ {":heavy_minus_sign:", ":heavy minus sign:", "&#x2796;"},
+ {":heavy_multiplication_x:", ":heavy multiplication x:", "&#x2716;"},
+ {":heavy_plus_sign:", ":heavy plus sign:", "&#x2795;"},
+ {":helicopter:", ":helicopter:", "&#x1f681;"},
+ {":herb:", ":herb:", "&#x1f33f;"},
+ {":hibiscus:", ":hibiscus:", "&#x1f33a;"},
+ {":high_brightness:", ":bright button:", "&#x1f506;"},
+ {":high_heel:", ":high-heeled shoe:", "&#x1f460;"},
+ {":hocho:", ":kitchen knife:", "&#x1f52a;"},
+ {":hole:", ":hole:", "&#x1f573;"},
+ {":honduras:", ":flag honduras:", "&#x1f1ed;&#x1f1f3;"},
+ {":honey_pot:", ":honey pot:", "&#x1f36f;"},
+ {":honeybee:", ":honeybee:", "&#x1f41d;"},
+ {":hong_kong:", ":flag hong kong sar china:", "&#x1f1ed;&#x1f1f0;"},
+ {":horse:", ":horse face:", "&#x1f434;"},
+ {":horse_racing:", ":horse racing:", "&#x1f3c7;"},
+ {":hospital:", ":hospital:", "&#x1f3e5;"},
+ {":hot_pepper:", ":hot pepper:", "&#x1f336;"},
+ {":hotdog:", ":hot dog:", "&#x1f32d;"},
+ {":hotel:", ":hotel:", "&#x1f3e8;"},
+ {":hotsprings:", ":hot springs:", "&#x2668;"},
+ {":hourglass:", ":hourglass done:", "&#x231b;"},
+ {":hourglass_flowing_sand:", ":hourglass not done:", "&#x23f3;"},
+ {":house:", ":house:", "&#x1f3e0;"},
+ {":house_with_garden:", ":house with garden:", "&#x1f3e1;"},
+ {":houses:", ":houses:", "&#x1f3d8;"},
+ {":hugs:", ":hugging face:", "&#x1f917;"},
+ {":hungary:", ":flag hungary:", "&#x1f1ed;&#x1f1fa;"},
+ {":hushed:", ":hushed face:", "&#x1f62f;"},
+ {":ice_cream:", ":ice cream:", "&#x1f368;"},
+ {":ice_hockey:", ":ice hockey:", "&#x1f3d2;"},
+ {":ice_skate:", ":ice skate:", "&#x26f8;"},
+ {":icecream:", ":soft ice cream:", "&#x1f366;"},
+ {":iceland:", ":flag iceland:", "&#x1f1ee;&#x1f1f8;"},
+ {":id:", ":id button:", "&#x1f194;"},
+ {":ideograph_advantage:", ":japanese \"bargain\" button:", "&#x1f250;"},
+ {":imp:", ":angry face with horns:", "&#x1f47f;"},
+ {":inbox_tray:", ":inbox tray:", "&#x1f4e5;"},
+ {":incoming_envelope:", ":incoming envelope:", "&#x1f4e8;"},
+ {":india:", ":flag india:", "&#x1f1ee;&#x1f1f3;"},
+ {":indonesia:", ":flag indonesia:", "&#x1f1ee;&#x1f1e9;"},
+ {":information_desk_person:", ":person tipping hand:", "&#x1f481;"},
+ {":information_source:", ":information:", "&#x2139;"},
+ {":innocent:", ":smiling face with halo:", "&#x1f607;"},
+ {":interrobang:", ":exclamation question mark:", "&#x2049;"},
+ {":iphone:", ":mobile phone:", "&#x1f4f1;"},
+ {":iran:", ":flag iran:", "&#x1f1ee;&#x1f1f7;"},
+ {":iraq:", ":flag iraq:", "&#x1f1ee;&#x1f1f6;"},
+ {":ireland:", ":flag ireland:", "&#x1f1ee;&#x1f1ea;"},
+ {":isle_of_man:", ":flag isle of man:", "&#x1f1ee;&#x1f1f2;"},
+ {":israel:", ":flag israel:", "&#x1f1ee;&#x1f1f1;"},
+ {":it:", ":flag italy:", "&#x1f1ee;&#x1f1f9;"},
+ {":izakaya_lantern:", ":red paper lantern:", "&#x1f3ee;"},
+ {":jack_o_lantern:", ":jack-o-lantern:", "&#x1f383;"},
+ {":jamaica:", ":flag jamaica:", "&#x1f1ef;&#x1f1f2;"},
+ {":japan:", ":map of japan:", "&#x1f5fe;"},
+ {":japanese_castle:", ":japanese castle:", "&#x1f3ef;"},
+ {":japanese_goblin:", ":goblin:", "&#x1f47a;"},
+ {":japanese_ogre:", ":ogre:", "&#x1f479;"},
+ {":jeans:", ":jeans:", "&#x1f456;"},
+ {":jersey:", ":flag jersey:", "&#x1f1ef;&#x1f1ea;"},
+ {":jordan:", ":flag jordan:", "&#x1f1ef;&#x1f1f4;"},
+ {":joy:", ":face with tears of joy:", "&#x1f602;"},
+ {":joy_cat:", ":cat face with tears of joy:", "&#x1f639;"},
+ {":joystick:", ":joystick:", "&#x1f579;"},
+ {":jp:", ":flag japan:", "&#x1f1ef;&#x1f1f5;"},
+ {":kaaba:", ":kaaba:", "&#x1f54b;"},
+ {":kazakhstan:", ":flag kazakhstan:", "&#x1f1f0;&#x1f1ff;"},
+ {":kenya:", ":flag kenya:", "&#x1f1f0;&#x1f1ea;"},
+ {":key:", ":key:", "&#x1f511;"},
+ {":keyboard:", ":keyboard:", "&#x2328;"},
+ {":keycap_ten:", ":keycap 10:", "&#x1f51f;"},
+ {":kick_scooter:", ":kick scooter:", "&#x1f6f4;"},
+ {":kimono:", ":kimono:", "&#x1f458;"},
+ {":kiribati:", ":flag kiribati:", "&#x1f1f0;&#x1f1ee;"},
+ {":kiss:", ":kiss mark:", "&#x1f48b;"},
+ {":kissing:", ":kissing face:", "&#x1f617;"},
+ {":kissing_cat:", ":kissing cat face:", "&#x1f63d;"},
+ {":kissing_closed_eyes:", ":kissing face with closed eyes:", "&#x1f61a;"},
+ {":kissing_heart:", ":face blowing a kiss:", "&#x1f618;"},
+ {":kissing_smiling_eyes:", ":kissing face with smiling eyes:", "&#x1f619;"},
+ {":kiwi_fruit:", ":kiwi fruit:", "&#x1f95d;"},
+ {":knife:", ":kitchen knife:", "&#x1f52a;"},
+ {":koala:", ":koala:", "&#x1f428;"},
+ {":koko:", ":japanese \"here\" button:", "&#x1f201;"},
+ {":kosovo:", ":flag kosovo:", "&#x1f1fd;&#x1f1f0;"},
+ {":kr:", ":flag south korea:", "&#x1f1f0;&#x1f1f7;"},
+ {":kuwait:", ":flag kuwait:", "&#x1f1f0;&#x1f1fc;"},
+ {":kyrgyzstan:", ":flag kyrgyzstan:", "&#x1f1f0;&#x1f1ec;"},
+ {":label:", ":label:", "&#x1f3f7;"},
+ {":lantern:", ":red paper lantern:", "&#x1f3ee;"},
+ {":laos:", ":flag laos:", "&#x1f1f1;&#x1f1e6;"},
+ {":large_blue_circle:", ":blue circle:", "&#x1f535;"},
+ {":large_blue_diamond:", ":large blue diamond:", "&#x1f537;"},
+ {":large_orange_diamond:", ":large orange diamond:", "&#x1f536;"},
+ {":last_quarter_moon:", ":last quarter moon:", "&#x1f317;"},
+ {":last_quarter_moon_with_face:", ":last quarter moon face:", "&#x1f31c;"},
+ {":latin_cross:", ":latin cross:", "&#x271d;"},
+ {":latvia:", ":flag latvia:", "&#x1f1f1;&#x1f1fb;"},
+ {":laughing:", ":grinning squinting face:", "&#x1f606;"},
+ {":leaves:", ":leaf fluttering in wind:", "&#x1f343;"},
+ {":lebanon:", ":flag lebanon:", "&#x1f1f1;&#x1f1e7;"},
+ {":ledger:", ":ledger:", "&#x1f4d2;"},
+ {":left_luggage:", ":left luggage:", "&#x1f6c5;"},
+ {":left_right_arrow:", ":left-right arrow:", "&#x2194;"},
+ {":leftwards_arrow_with_hook:", ":right arrow curving left:", "&#x21a9;"},
+ {":lemon:", ":lemon:", "&#x1f34b;"},
+ {":leo:", ":leo:", "&#x264c;"},
+ {":leopard:", ":leopard:", "&#x1f406;"},
+ {":lesotho:", ":flag lesotho:", "&#x1f1f1;&#x1f1f8;"},
+ {":level_slider:", ":level slider:", "&#x1f39a;"},
+ {":liberia:", ":flag liberia:", "&#x1f1f1;&#x1f1f7;"},
+ {":libra:", ":libra:", "&#x264e;"},
+ {":libya:", ":flag libya:", "&#x1f1f1;&#x1f1fe;"},
+ {":liechtenstein:", ":flag liechtenstein:", "&#x1f1f1;&#x1f1ee;"},
+ {":light_rail:", ":light rail:", "&#x1f688;"},
+ {":link:", ":link:", "&#x1f517;"},
+ {":lion:", ":lion face:", "&#x1f981;"},
+ {":lips:", ":mouth:", "&#x1f444;"},
+ {":lipstick:", ":lipstick:", "&#x1f484;"},
+ {":lithuania:", ":flag lithuania:", "&#x1f1f1;&#x1f1f9;"},
+ {":lizard:", ":lizard:", "&#x1f98e;"},
+ {":lock:", ":locked:", "&#x1f512;"},
+ {":lock_with_ink_pen:", ":locked with pen:", "&#x1f50f;"},
+ {":lollipop:", ":lollipop:", "&#x1f36d;"},
+ {":loop:", ":double curly loop:", "&#x27bf;"},
+ {":loud_sound:", ":speaker high volume:", "&#x1f50a;"},
+ {":loudspeaker:", ":loudspeaker:", "&#x1f4e2;"},
+ {":love_hotel:", ":love hotel:", "&#x1f3e9;"},
+ {":love_letter:", ":love letter:", "&#x1f48c;"},
+ {":low_brightness:", ":dim button:", "&#x1f505;"},
+ {":luxembourg:", ":flag luxembourg:", "&#x1f1f1;&#x1f1fa;"},
+ {":lying_face:", ":lying face:", "&#x1f925;"},
+ {":m:", ":circled m:", "&#x24c2;"},
+ {":macau:", ":flag macau sar china:", "&#x1f1f2;&#x1f1f4;"},
+ {":macedonia:", ":flag macedonia:", "&#x1f1f2;&#x1f1f0;"},
+ {":madagascar:", ":flag madagascar:", "&#x1f1f2;&#x1f1ec;"},
+ {":mag:", ":magnifying glass tilted left:", "&#x1f50d;"},
+ {":mag_right:", ":magnifying glass tilted right:", "&#x1f50e;"},
+ {":mahjong:", ":mahjong red dragon:", "&#x1f004;"},
+ {":mailbox:", ":closed mailbox with raised flag:", "&#x1f4eb;"},
+ {":mailbox_closed:", ":closed mailbox with lowered flag:", "&#x1f4ea;"},
+ {":mailbox_with_mail:", ":open mailbox with raised flag:", "&#x1f4ec;"},
+ {":mailbox_with_no_mail:", ":open mailbox with lowered flag:", "&#x1f4ed;"},
+ {":malawi:", ":flag malawi:", "&#x1f1f2;&#x1f1fc;"},
+ {":malaysia:", ":flag malaysia:", "&#x1f1f2;&#x1f1fe;"},
+ {":maldives:", ":flag maldives:", "&#x1f1f2;&#x1f1fb;"},
+ {":male_detective:", ":detective:", "&#x1f575;"},
+ {":mali:", ":flag mali:", "&#x1f1f2;&#x1f1f1;"},
+ {":malta:", ":flag malta:", "&#x1f1f2;&#x1f1f9;"},
+ {":man:", ":man:", "&#x1f468;"},
+ {":man_artist:", ":man artist:", "&#x1f468;&#x200d;&#x1f3a8;"},
+ {":man_astronaut:", ":man astronaut:", "&#x1f468;&#x200d;&#x1f680;"},
+ {":man_cartwheeling:", ":man cartwheeling:", "&#x1f938;&#x200d;&#x2642;&#xfe0f;"},
+ {":man_cook:", ":man cook:", "&#x1f468;&#x200d;&#x1f373;"},
+ {":man_dancing:", ":man dancing:", "&#x1f57a;"},
+ {":man_facepalming:", ":man facepalming:", "&#x1f926;&#x200d;&#x2642;&#xfe0f;"},
+ {":man_factory_worker:", ":man factory worker:", "&#x1f468;&#x200d;&#x1f3ed;"},
+ {":man_farmer:", ":man farmer:", "&#x1f468;&#x200d;&#x1f33e;"},
+ {":man_firefighter:", ":man firefighter:", "&#x1f468;&#x200d;&#x1f692;"},
+ {":man_health_worker:", ":man health worker:", "&#x1f468;&#x200d;&#x2695;&#xfe0f;"},
+ {":man_in_tuxedo:", ":man in tuxedo:", "&#x1f935;"},
+ {":man_judge:", ":man judge:", "&#x1f468;&#x200d;&#x2696;&#xfe0f;"},
+ {":man_juggling:", ":man juggling:", "&#x1f939;&#x200d;&#x2642;&#xfe0f;"},
+ {":man_mechanic:", ":man mechanic:", "&#x1f468;&#x200d;&#x1f527;"},
+ {":man_office_worker:", ":man office worker:", "&#x1f468;&#x200d;&#x1f4bc;"},
+ {":man_pilot:", ":man pilot:", "&#x1f468;&#x200d;&#x2708;&#xfe0f;"},
+ {":man_playing_handball:", ":man playing handball:", "&#x1f93e;&#x200d;&#x2642;&#xfe0f;"},
+ {":man_playing_water_polo:", ":man playing water polo:", "&#x1f93d;&#x200d;&#x2642;&#xfe0f;"},
+ {":man_scientist:", ":man scientist:", "&#x1f468;&#x200d;&#x1f52c;"},
+ {":man_shrugging:", ":man shrugging:", "&#x1f937;&#x200d;&#x2642;&#xfe0f;"},
+ {":man_singer:", ":man singer:", "&#x1f468;&#x200d;&#x1f3a4;"},
+ {":man_student:", ":man student:", "&#x1f468;&#x200d;&#x1f393;"},
+ {":man_teacher:", ":man teacher:", "&#x1f468;&#x200d;&#x1f3eb;"},
+ {":man_technologist:", ":man technologist:", "&#x1f468;&#x200d;&#x1f4bb;"},
+ {":man_with_gua_pi_mao:", ":man with chinese cap:", "&#x1f472;"},
+ {":man_with_turban:", ":person wearing turban:", "&#x1f473;"},
+ {":mandarin:", ":tangerine:", "&#x1f34a;"},
+ {":mans_shoe:", ":man's shoe:", "&#x1f45e;"},
+ {":mantelpiece_clock:", ":mantelpiece clock:", "&#x1f570;"},
+ {":maple_leaf:", ":maple leaf:", "&#x1f341;"},
+ {":marshall_islands:", ":flag marshall islands:", "&#x1f1f2;&#x1f1ed;"},
+ {":martial_arts_uniform:", ":martial arts uniform:", "&#x1f94b;"},
+ {":martinique:", ":flag martinique:", "&#x1f1f2;&#x1f1f6;"},
+ {":mask:", ":face with medical mask:", "&#x1f637;"},
+ {":massage:", ":person getting massage:", "&#x1f486;"},
+ {":massage_man:", ":man getting massage:", "&#x1f486;&#x200d;&#x2642;&#xfe0f;"},
+ {":massage_woman:", ":person getting massage:", "&#x1f486;"},
+ {":mauritania:", ":flag mauritania:", "&#x1f1f2;&#x1f1f7;"},
+ {":mauritius:", ":flag mauritius:", "&#x1f1f2;&#x1f1fa;"},
+ {":mayotte:", ":flag mayotte:", "&#x1f1fe;&#x1f1f9;"},
+ {":meat_on_bone:", ":meat on bone:", "&#x1f356;"},
+ {":medal_military:", ":military medal:", "&#x1f396;"},
+ {":medal_sports:", ":sports medal:", "&#x1f3c5;"},
+ {":mega:", ":megaphone:", "&#x1f4e3;"},
+ {":melon:", ":melon:", "&#x1f348;"},
+ {":memo:", ":memo:", "&#x1f4dd;"},
+ {":men_wrestling:", ":men wrestling:", "&#x1f93c;&#x200d;&#x2642;&#xfe0f;"},
+ {":menorah:", ":menorah:", "&#x1f54e;"},
+ {":mens:", ":men's room:", "&#x1f6b9;"},
+ {":metal:", ":sign of the horns:", "&#x1f918;"},
+ {":metro:", ":metro:", "&#x1f687;"},
+ {":mexico:", ":flag mexico:", "&#x1f1f2;&#x1f1fd;"},
+ {":micronesia:", ":flag micronesia:", "&#x1f1eb;&#x1f1f2;"},
+ {":microphone:", ":microphone:", "&#x1f3a4;"},
+ {":microscope:", ":microscope:", "&#x1f52c;"},
+ {":middle_finger:", ":middle finger:", "&#x1f595;"},
+ {":milk_glass:", ":glass of milk:", "&#x1f95b;"},
+ {":milky_way:", ":milky way:", "&#x1f30c;"},
+ {":minibus:", ":minibus:", "&#x1f690;"},
+ {":minidisc:", ":computer disk:", "&#x1f4bd;"},
+ {":mobile_phone_off:", ":mobile phone off:", "&#x1f4f4;"},
+ {":moldova:", ":flag moldova:", "&#x1f1f2;&#x1f1e9;"},
+ {":monaco:", ":flag monaco:", "&#x1f1f2;&#x1f1e8;"},
+ {":money_mouth_face:", ":money-mouth face:", "&#x1f911;"},
+ {":money_with_wings:", ":money with wings:", "&#x1f4b8;"},
+ {":moneybag:", ":money bag:", "&#x1f4b0;"},
+ {":mongolia:", ":flag mongolia:", "&#x1f1f2;&#x1f1f3;"},
+ {":monkey:", ":monkey:", "&#x1f412;"},
+ {":monkey_face:", ":monkey face:", "&#x1f435;"},
+ {":monorail:", ":monorail:", "&#x1f69d;"},
+ {":montenegro:", ":flag montenegro:", "&#x1f1f2;&#x1f1ea;"},
+ {":montserrat:", ":flag montserrat:", "&#x1f1f2;&#x1f1f8;"},
+ {":moon:", ":waxing gibbous moon:", "&#x1f314;"},
+ {":morocco:", ":flag morocco:", "&#x1f1f2;&#x1f1e6;"},
+ {":mortar_board:", ":graduation cap:", "&#x1f393;"},
+ {":mosque:", ":mosque:", "&#x1f54c;"},
+ {":motor_boat:", ":motor boat:", "&#x1f6e5;"},
+ {":motor_scooter:", ":motor scooter:", "&#x1f6f5;"},
+ {":motorcycle:", ":motorcycle:", "&#x1f3cd;"},
+ {":motorway:", ":motorway:", "&#x1f6e3;"},
+ {":mount_fuji:", ":mount fuji:", "&#x1f5fb;"},
+ {":mountain:", ":mountain:", "&#x26f0;"},
+ {":mountain_bicyclist:", ":person mountain biking:", "&#x1f6b5;"},
+ {":mountain_biking_man:", ":person mountain biking:", "&#x1f6b5;"},
+ {":mountain_biking_woman:", ":woman mountain biking:", "&#x1f6b5;&#x200d;&#x2640;&#xfe0f;"},
+ {":mountain_cableway:", ":mountain cableway:", "&#x1f6a0;"},
+ {":mountain_railway:", ":mountain railway:", "&#x1f69e;"},
+ {":mountain_snow:", ":snow-capped mountain:", "&#x1f3d4;"},
+ {":mouse:", ":mouse face:", "&#x1f42d;"},
+ {":mouse2:", ":mouse:", "&#x1f401;"},
+ {":movie_camera:", ":movie camera:", "&#x1f3a5;"},
+ {":moyai:", ":moai:", "&#x1f5ff;"},
+ {":mozambique:", ":flag mozambique:", "&#x1f1f2;&#x1f1ff;"},
+ {":mrs_claus:", ":mrs. claus:", "&#x1f936;"},
+ {":muscle:", ":flexed biceps:", "&#x1f4aa;"},
+ {":mushroom:", ":mushroom:", "&#x1f344;"},
+ {":musical_keyboard:", ":musical keyboard:", "&#x1f3b9;"},
+ {":musical_note:", ":musical note:", "&#x1f3b5;"},
+ {":musical_score:", ":musical score:", "&#x1f3bc;"},
+ {":mute:", ":muted speaker:", "&#x1f507;"},
+ {":myanmar:", ":flag myanmar (burma):", "&#x1f1f2;&#x1f1f2;"},
+ {":nail_care:", ":nail polish:", "&#x1f485;"},
+ {":name_badge:", ":name badge:", "&#x1f4db;"},
+ {":namibia:", ":flag namibia:", "&#x1f1f3;&#x1f1e6;"},
+ {":national_park:", ":national park:", "&#x1f3de;"},
+ {":nauru:", ":flag nauru:", "&#x1f1f3;&#x1f1f7;"},
+ {":nauseated_face:", ":nauseated face:", "&#x1f922;"},
+ {":necktie:", ":necktie:", "&#x1f454;"},
+ {":negative_squared_cross_mark:", ":cross mark button:", "&#x274e;"},
+ {":nepal:", ":flag nepal:", "&#x1f1f3;&#x1f1f5;"},
+ {":nerd_face:", ":nerd face:", "&#x1f913;"},
+ {":netherlands:", ":flag netherlands:", "&#x1f1f3;&#x1f1f1;"},
+ {":neutral_face:", ":neutral face:", "&#x1f610;"},
+ {":new:", ":new button:", "&#x1f195;"},
+ {":new_caledonia:", ":flag new caledonia:", "&#x1f1f3;&#x1f1e8;"},
+ {":new_moon:", ":new moon:", "&#x1f311;"},
+ {":new_moon_with_face:", ":new moon face:", "&#x1f31a;"},
+ {":new_zealand:", ":flag new zealand:", "&#x1f1f3;&#x1f1ff;"},
+ {":newspaper:", ":newspaper:", "&#x1f4f0;"},
+ {":newspaper_roll:", ":rolled-up newspaper:", "&#x1f5de;"},
+ {":next_track_button:", ":next track button:", "&#x23ed;"},
+ {":ng:", ":ng button:", "&#x1f196;"},
+ {":ng_man:", ":man gesturing no:", "&#x1f645;&#x200d;&#x2642;&#xfe0f;"},
+ {":ng_woman:", ":person gesturing no:", "&#x1f645;"},
+ {":nicaragua:", ":flag nicaragua:", "&#x1f1f3;&#x1f1ee;"},
+ {":niger:", ":flag niger:", "&#x1f1f3;&#x1f1ea;"},
+ {":nigeria:", ":flag nigeria:", "&#x1f1f3;&#x1f1ec;"},
+ {":night_with_stars:", ":night with stars:", "&#x1f303;"},
+ {":nine:", ":keycap 9:", "&#x0039;&#xfe0f;&#x20e3;"},
+ {":niue:", ":flag niue:", "&#x1f1f3;&#x1f1fa;"},
+ {":no_bell:", ":bell with slash:", "&#x1f515;"},
+ {":no_bicycles:", ":no bicycles:", "&#x1f6b3;"},
+ {":no_entry:", ":no entry:", "&#x26d4;"},
+ {":no_entry_sign:", ":prohibited:", "&#x1f6ab;"},
+ {":no_good:", ":person gesturing no:", "&#x1f645;"},
+ {":no_good_man:", ":man gesturing no:", "&#x1f645;&#x200d;&#x2642;&#xfe0f;"},
+ {":no_good_woman:", ":person gesturing no:", "&#x1f645;"},
+ {":no_mobile_phones:", ":no mobile phones:", "&#x1f4f5;"},
+ {":no_mouth:", ":face without mouth:", "&#x1f636;"},
+ {":no_pedestrians:", ":no pedestrians:", "&#x1f6b7;"},
+ {":no_smoking:", ":no smoking:", "&#x1f6ad;"},
+ {":non-potable_water:", ":non-potable water:", "&#x1f6b1;"},
+ {":norfolk_island:", ":flag norfolk island:", "&#x1f1f3;&#x1f1eb;"},
+ {":north_korea:", ":flag north korea:", "&#x1f1f0;&#x1f1f5;"},
+ {":northern_mariana_islands:", ":flag northern mariana islands:", "&#x1f1f2;&#x1f1f5;"},
+ {":norway:", ":flag norway:", "&#x1f1f3;&#x1f1f4;"},
+ {":nose:", ":nose:", "&#x1f443;"},
+ {":notebook:", ":notebook:", "&#x1f4d3;"},
+ {":notebook_with_decorative_cover:", ":notebook with decorative cover:", "&#x1f4d4;"},
+ {":notes:", ":musical notes:", "&#x1f3b6;"},
+ {":nut_and_bolt:", ":nut and bolt:", "&#x1f529;"},
+ {":o:", ":heavy large circle:", "&#x2b55;"},
+ {":o2:", ":o button (blood type):", "&#x1f17e;"},
+ {":ocean:", ":water wave:", "&#x1f30a;"},
+ {":octopus:", ":octopus:", "&#x1f419;"},
+ {":oden:", ":oden:", "&#x1f362;"},
+ {":office:", ":office building:", "&#x1f3e2;"},
+ {":oil_drum:", ":oil drum:", "&#x1f6e2;"},
+ {":ok:", ":ok button:", "&#x1f197;"},
+ {":ok_hand:", ":ok hand:", "&#x1f44c;"},
+ {":ok_man:", ":man gesturing ok:", "&#x1f646;&#x200d;&#x2642;&#xfe0f;"},
+ {":ok_woman:", ":person gesturing ok:", "&#x1f646;"},
+ {":old_key:", ":old key:", "&#x1f5dd;"},
+ {":older_man:", ":old man:", "&#x1f474;"},
+ {":older_woman:", ":old woman:", "&#x1f475;"},
+ {":om:", ":om:", "&#x1f549;"},
+ {":oman:", ":flag oman:", "&#x1f1f4;&#x1f1f2;"},
+ {":on:", ":on! arrow:", "&#x1f51b;"},
+ {":oncoming_automobile:", ":oncoming automobile:", "&#x1f698;"},
+ {":oncoming_bus:", ":oncoming bus:", "&#x1f68d;"},
+ {":oncoming_police_car:", ":oncoming police car:", "&#x1f694;"},
+ {":oncoming_taxi:", ":oncoming taxi:", "&#x1f696;"},
+ {":one:", ":keycap 1:", "&#x0031;&#xfe0f;&#x20e3;"},
+ {":open_book:", ":open book:", "&#x1f4d6;"},
+ {":open_file_folder:", ":open file folder:", "&#x1f4c2;"},
+ {":open_hands:", ":open hands:", "&#x1f450;"},
+ {":open_mouth:", ":face with open mouth:", "&#x1f62e;"},
+ {":open_umbrella:", ":umbrella:", "&#x2602;"},
+ {":ophiuchus:", ":ophiuchus:", "&#x26ce;"},
+ {":orange:", ":tangerine:", "&#x1f34a;"},
+ {":orange_book:", ":orange book:", "&#x1f4d9;"},
+ {":orthodox_cross:", ":orthodox cross:", "&#x2626;"},
+ {":outbox_tray:", ":outbox tray:", "&#x1f4e4;"},
+ {":owl:", ":owl:", "&#x1f989;"},
+ {":ox:", ":ox:", "&#x1f402;"},
+ {":package:", ":package:", "&#x1f4e6;"},
+ {":page_facing_up:", ":page facing up:", "&#x1f4c4;"},
+ {":page_with_curl:", ":page with curl:", "&#x1f4c3;"},
+ {":pager:", ":pager:", "&#x1f4df;"},
+ {":paintbrush:", ":paintbrush:", "&#x1f58c;"},
+ {":pakistan:", ":flag pakistan:", "&#x1f1f5;&#x1f1f0;"},
+ {":palau:", ":flag palau:", "&#x1f1f5;&#x1f1fc;"},
+ {":palestinian_territories:", ":flag palestinian territories:", "&#x1f1f5;&#x1f1f8;"},
+ {":palm_tree:", ":palm tree:", "&#x1f334;"},
+ {":panama:", ":flag panama:", "&#x1f1f5;&#x1f1e6;"},
+ {":pancakes:", ":pancakes:", "&#x1f95e;"},
+ {":panda_face:", ":panda face:", "&#x1f43c;"},
+ {":paperclip:", ":paperclip:", "&#x1f4ce;"},
+ {":paperclips:", ":linked paperclips:", "&#x1f587;"},
+ {":papua_new_guinea:", ":flag papua new guinea:", "&#x1f1f5;&#x1f1ec;"},
+ {":paraguay:", ":flag paraguay:", "&#x1f1f5;&#x1f1fe;"},
+ {":parasol_on_ground:", ":umbrella on ground:", "&#x26f1;"},
+ {":parking:", ":p button:", "&#x1f17f;"},
+ {":part_alternation_mark:", ":part alternation mark:", "&#x303d;"},
+ {":partly_sunny:", ":sun behind cloud:", "&#x26c5;"},
+ {":passenger_ship:", ":passenger ship:", "&#x1f6f3;"},
+ {":passport_control:", ":passport control:", "&#x1f6c2;"},
+ {":pause_button:", ":pause button:", "&#x23f8;"},
+ {":paw_prints:", ":paw prints:", "&#x1f43e;"},
+ {":peace_symbol:", ":peace symbol:", "&#x262e;"},
+ {":peach:", ":peach:", "&#x1f351;"},
+ {":peanuts:", ":peanuts:", "&#x1f95c;"},
+ {":pear:", ":pear:", "&#x1f350;"},
+ {":pen:", ":pen:", "&#x1f58a;"},
+ {":pencil:", ":memo:", "&#x1f4dd;"},
+ {":pencil2:", ":pencil:", "&#x270f;"},
+ {":penguin:", ":penguin:", "&#x1f427;"},
+ {":pensive:", ":pensive face:", "&#x1f614;"},
+ {":performing_arts:", ":performing arts:", "&#x1f3ad;"},
+ {":persevere:", ":persevering face:", "&#x1f623;"},
+ {":person_fencing:", ":person fencing:", "&#x1f93a;"},
+ {":person_frowning:", ":person frowning:", "&#x1f64d;"},
+ {":person_with_blond_hair:", ":person blond hair:", "&#x1f471;"},
+ {":person_with_pouting_face:", ":person pouting:", "&#x1f64e;"},
+ {":peru:", ":flag peru:", "&#x1f1f5;&#x1f1ea;"},
+ {":philippines:", ":flag philippines:", "&#x1f1f5;&#x1f1ed;"},
+ {":phone:", ":telephone:", "&#x260e;"},
+ {":pick:", ":pick:", "&#x26cf;"},
+ {":pig:", ":pig face:", "&#x1f437;"},
+ {":pig2:", ":pig:", "&#x1f416;"},
+ {":pig_nose:", ":pig nose:", "&#x1f43d;"},
+ {":pill:", ":pill:", "&#x1f48a;"},
+ {":pineapple:", ":pineapple:", "&#x1f34d;"},
+ {":ping_pong:", ":ping pong:", "&#x1f3d3;"},
+ {":pisces:", ":pisces:", "&#x2653;"},
+ {":pitcairn_islands:", ":flag pitcairn islands:", "&#x1f1f5;&#x1f1f3;"},
+ {":pizza:", ":pizza:", "&#x1f355;"},
+ {":place_of_worship:", ":place of worship:", "&#x1f6d0;"},
+ {":plate_with_cutlery:", ":fork and knife with plate:", "&#x1f37d;"},
+ {":play_or_pause_button:", ":play or pause button:", "&#x23ef;"},
+ {":point_down:", ":backhand index pointing down:", "&#x1f447;"},
+ {":point_left:", ":backhand index pointing left:", "&#x1f448;"},
+ {":point_right:", ":backhand index pointing right:", "&#x1f449;"},
+ {":point_up:", ":index pointing up:", "&#x261d;"},
+ {":point_up_2:", ":backhand index pointing up:", "&#x1f446;"},
+ {":poland:", ":flag poland:", "&#x1f1f5;&#x1f1f1;"},
+ {":police_car:", ":police car:", "&#x1f693;"},
+ {":policeman:", ":police officer:", "&#x1f46e;"},
+ {":policewoman:", ":woman police officer:", "&#x1f46e;&#x200d;&#x2640;&#xfe0f;"},
+ {":poodle:", ":poodle:", "&#x1f429;"},
+ {":poop:", ":pile of poo:", "&#x1f4a9;"},
+ {":popcorn:", ":popcorn:", "&#x1f37f;"},
+ {":portugal:", ":flag portugal:", "&#x1f1f5;&#x1f1f9;"},
+ {":post_office:", ":japanese post office:", "&#x1f3e3;"},
+ {":postal_horn:", ":postal horn:", "&#x1f4ef;"},
+ {":postbox:", ":postbox:", "&#x1f4ee;"},
+ {":potable_water:", ":potable water:", "&#x1f6b0;"},
+ {":potato:", ":potato:", "&#x1f954;"},
+ {":pouch:", ":clutch bag:", "&#x1f45d;"},
+ {":poultry_leg:", ":poultry leg:", "&#x1f357;"},
+ {":pound:", ":pound banknote:", "&#x1f4b7;"},
+ {":pout:", ":pouting face:", "&#x1f621;"},
+ {":pouting_cat:", ":pouting cat face:", "&#x1f63e;"},
+ {":pouting_man:", ":man pouting:", "&#x1f64e;&#x200d;&#x2642;&#xfe0f;"},
+ {":pouting_woman:", ":person pouting:", "&#x1f64e;"},
+ {":pray:", ":folded hands:", "&#x1f64f;"},
+ {":prayer_beads:", ":prayer beads:", "&#x1f4ff;"},
+ {":pregnant_woman:", ":pregnant woman:", "&#x1f930;"},
+ {":previous_track_button:", ":last track button:", "&#x23ee;"},
+ {":prince:", ":prince:", "&#x1f934;"},
+ {":princess:", ":princess:", "&#x1f478;"},
+ {":printer:", ":printer:", "&#x1f5a8;"},
+ {":puerto_rico:", ":flag puerto rico:", "&#x1f1f5;&#x1f1f7;"},
+ {":punch:", ":oncoming fist:", "&#x1f44a;"},
+ {":purple_heart:", ":purple heart:", "&#x1f49c;"},
+ {":purse:", ":purse:", "&#x1f45b;"},
+ {":pushpin:", ":pushpin:", "&#x1f4cc;"},
+ {":put_litter_in_its_place:", ":litter in bin sign:", "&#x1f6ae;"},
+ {":qatar:", ":flag qatar:", "&#x1f1f6;&#x1f1e6;"},
+ {":question:", ":question mark:", "&#x2753;"},
+ {":rabbit:", ":rabbit face:", "&#x1f430;"},
+ {":rabbit2:", ":rabbit:", "&#x1f407;"},
+ {":racehorse:", ":horse:", "&#x1f40e;"},
+ {":racing_car:", ":racing car:", "&#x1f3ce;"},
+ {":radio:", ":radio:", "&#x1f4fb;"},
+ {":radio_button:", ":radio button:", "&#x1f518;"},
+ {":radioactive:", ":radioactive:", "&#x2622;"},
+ {":rage:", ":pouting face:", "&#x1f621;"},
+ {":railway_car:", ":railway car:", "&#x1f683;"},
+ {":railway_track:", ":railway track:", "&#x1f6e4;"},
+ {":rainbow:", ":rainbow:", "&#x1f308;"},
+ {":rainbow_flag:", ":rainbow flag:", "&#x1f3f3;&#xfe0f;&#x200d;&#x1f308;"},
+ {":raised_back_of_hand:", ":raised back of hand:", "&#x1f91a;"},
+ {":raised_hand:", ":raised hand:", "&#x270b;"},
+ {":raised_hand_with_fingers_splayed:", ":hand with fingers splayed:", "&#x1f590;"},
+ {":raised_hands:", ":raising hands:", "&#x1f64c;"},
+ {":raising_hand:", ":person raising hand:", "&#x1f64b;"},
+ {":raising_hand_man:", ":man raising hand:", "&#x1f64b;&#x200d;&#x2642;&#xfe0f;"},
+ {":raising_hand_woman:", ":person raising hand:", "&#x1f64b;"},
+ {":ram:", ":ram:", "&#x1f40f;"},
+ {":ramen:", ":steaming bowl:", "&#x1f35c;"},
+ {":rat:", ":rat:", "&#x1f400;"},
+ {":record_button:", ":record button:", "&#x23fa;"},
+ {":recycle:", ":recycling symbol:", "&#x267b;"},
+ {":red_car:", ":automobile:", "&#x1f697;"},
+ {":red_circle:", ":red circle:", "&#x1f534;"},
+ {":registered:", ":registered:", "&#x00ae;"},
+ {":relaxed:", ":smiling face:", "&#x263a;"},
+ {":relieved:", ":relieved face:", "&#x1f60c;"},
+ {":reminder_ribbon:", ":reminder ribbon:", "&#x1f397;"},
+ {":repeat:", ":repeat button:", "&#x1f501;"},
+ {":repeat_one:", ":repeat single button:", "&#x1f502;"},
+ {":rescue_worker_helmet:", ":rescue worker's helmet:", "&#x26d1;"},
+ {":restroom:", ":restroom:", "&#x1f6bb;"},
+ {":reunion:", ":flag réunion:", "&#x1f1f7;&#x1f1ea;"},
+ {":revolving_hearts:", ":revolving hearts:", "&#x1f49e;"},
+ {":rewind:", ":fast reverse button:", "&#x23ea;"},
+ {":rhinoceros:", ":rhinoceros:", "&#x1f98f;"},
+ {":ribbon:", ":ribbon:", "&#x1f380;"},
+ {":rice:", ":cooked rice:", "&#x1f35a;"},
+ {":rice_ball:", ":rice ball:", "&#x1f359;"},
+ {":rice_cracker:", ":rice cracker:", "&#x1f358;"},
+ {":rice_scene:", ":moon viewing ceremony:", "&#x1f391;"},
+ {":right_anger_bubble:", ":right anger bubble:", "&#x1f5ef;"},
+ {":ring:", ":ring:", "&#x1f48d;"},
+ {":robot:", ":robot face:", "&#x1f916;"},
+ {":rocket:", ":rocket:", "&#x1f680;"},
+ {":rofl:", ":rolling on the floor laughing:", "&#x1f923;"},
+ {":roll_eyes:", ":face with rolling eyes:", "&#x1f644;"},
+ {":roller_coaster:", ":roller coaster:", "&#x1f3a2;"},
+ {":romania:", ":flag romania:", "&#x1f1f7;&#x1f1f4;"},
+ {":rooster:", ":rooster:", "&#x1f413;"},
+ {":rose:", ":rose:", "&#x1f339;"},
+ {":rosette:", ":rosette:", "&#x1f3f5;"},
+ {":rotating_light:", ":police car light:", "&#x1f6a8;"},
+ {":round_pushpin:", ":round pushpin:", "&#x1f4cd;"},
+ {":rowboat:", ":person rowing boat:", "&#x1f6a3;"},
+ {":rowing_man:", ":person rowing boat:", "&#x1f6a3;"},
+ {":rowing_woman:", ":woman rowing boat:", "&#x1f6a3;&#x200d;&#x2640;&#xfe0f;"},
+ {":ru:", ":flag russia:", "&#x1f1f7;&#x1f1fa;"},
+ {":rugby_football:", ":rugby football:", "&#x1f3c9;"},
+ {":runner:", ":person running:", "&#x1f3c3;"},
+ {":running:", ":person running:", "&#x1f3c3;"},
+ {":running_man:", ":person running:", "&#x1f3c3;"},
+ {":running_shirt_with_sash:", ":running shirt:", "&#x1f3bd;"},
+ {":running_woman:", ":woman running:", "&#x1f3c3;&#x200d;&#x2640;&#xfe0f;"},
+ {":rwanda:", ":flag rwanda:", "&#x1f1f7;&#x1f1fc;"},
+ {":sa:", ":japanese \"service charge\" button:", "&#x1f202;"},
+ {":sagittarius:", ":sagittarius:", "&#x2650;"},
+ {":sailboat:", ":sailboat:", "&#x26f5;"},
+ {":sake:", ":sake:", "&#x1f376;"},
+ {":samoa:", ":flag samoa:", "&#x1f1fc;&#x1f1f8;"},
+ {":san_marino:", ":flag san marino:", "&#x1f1f8;&#x1f1f2;"},
+ {":sandal:", ":woman's sandal:", "&#x1f461;"},
+ {":santa:", ":santa claus:", "&#x1f385;"},
+ {":sao_tome_principe:", ":flag são tomé & príncipe:", "&#x1f1f8;&#x1f1f9;"},
+ {":satellite:", ":satellite antenna:", "&#x1f4e1;"},
+ {":satisfied:", ":grinning squinting face:", "&#x1f606;"},
+ {":saudi_arabia:", ":flag saudi arabia:", "&#x1f1f8;&#x1f1e6;"},
+ {":saxophone:", ":saxophone:", "&#x1f3b7;"},
+ {":school:", ":school:", "&#x1f3eb;"},
+ {":school_satchel:", ":backpack:", "&#x1f392;"},
+ {":scissors:", ":scissors:", "&#x2702;"},
+ {":scorpion:", ":scorpion:", "&#x1f982;"},
+ {":scorpius:", ":scorpio:", "&#x264f;"},
+ {":scream:", ":face screaming in fear:", "&#x1f631;"},
+ {":scream_cat:", ":weary cat face:", "&#x1f640;"},
+ {":scroll:", ":scroll:", "&#x1f4dc;"},
+ {":seat:", ":seat:", "&#x1f4ba;"},
+ {":secret:", ":japanese \"secret\" button:", "&#x3299;"},
+ {":see_no_evil:", ":see-no-evil monkey:", "&#x1f648;"},
+ {":seedling:", ":seedling:", "&#x1f331;"},
+ {":selfie:", ":selfie:", "&#x1f933;"},
+ {":senegal:", ":flag senegal:", "&#x1f1f8;&#x1f1f3;"},
+ {":serbia:", ":flag serbia:", "&#x1f1f7;&#x1f1f8;"},
+ {":seven:", ":keycap 7:", "&#x0037;&#xfe0f;&#x20e3;"},
+ {":seychelles:", ":flag seychelles:", "&#x1f1f8;&#x1f1e8;"},
+ {":shallow_pan_of_food:", ":shallow pan of food:", "&#x1f958;"},
+ {":shamrock:", ":shamrock:", "&#x2618;"},
+ {":shark:", ":shark:", "&#x1f988;"},
+ {":shaved_ice:", ":shaved ice:", "&#x1f367;"},
+ {":sheep:", ":ewe:", "&#x1f411;"},
+ {":shell:", ":spiral shell:", "&#x1f41a;"},
+ {":shield:", ":shield:", "&#x1f6e1;"},
+ {":shinto_shrine:", ":shinto shrine:", "&#x26e9;"},
+ {":ship:", ":ship:", "&#x1f6a2;"},
+ {":shirt:", ":t-shirt:", "&#x1f455;"},
+ {":shit:", ":pile of poo:", "&#x1f4a9;"},
+ {":shoe:", ":man's shoe:", "&#x1f45e;"},
+ {":shopping:", ":shopping bags:", "&#x1f6cd;"},
+ {":shopping_cart:", ":shopping cart:", "&#x1f6d2;"},
+ {":shower:", ":shower:", "&#x1f6bf;"},
+ {":shrimp:", ":shrimp:", "&#x1f990;"},
+ {":sierra_leone:", ":flag sierra leone:", "&#x1f1f8;&#x1f1f1;"},
+ {":signal_strength:", ":antenna bars:", "&#x1f4f6;"},
+ {":singapore:", ":flag singapore:", "&#x1f1f8;&#x1f1ec;"},
+ {":sint_maarten:", ":flag sint maarten:", "&#x1f1f8;&#x1f1fd;"},
+ {":six:", ":keycap 6:", "&#x0036;&#xfe0f;&#x20e3;"},
+ {":six_pointed_star:", ":dotted six-pointed star:", "&#x1f52f;"},
+ {":ski:", ":skis:", "&#x1f3bf;"},
+ {":skier:", ":skier:", "&#x26f7;"},
+ {":skull:", ":skull:", "&#x1f480;"},
+ {":skull_and_crossbones:", ":skull and crossbones:", "&#x2620;"},
+ {":sleeping:", ":sleeping face:", "&#x1f634;"},
+ {":sleeping_bed:", ":person in bed:", "&#x1f6cc;"},
+ {":sleepy:", ":sleepy face:", "&#x1f62a;"},
+ {":slightly_frowning_face:", ":slightly frowning face:", "&#x1f641;"},
+ {":slightly_smiling_face:", ":slightly smiling face:", "&#x1f642;"},
+ {":slot_machine:", ":slot machine:", "&#x1f3b0;"},
+ {":slovakia:", ":flag slovakia:", "&#x1f1f8;&#x1f1f0;"},
+ {":slovenia:", ":flag slovenia:", "&#x1f1f8;&#x1f1ee;"},
+ {":small_airplane:", ":small airplane:", "&#x1f6e9;"},
+ {":small_blue_diamond:", ":small blue diamond:", "&#x1f539;"},
+ {":small_orange_diamond:", ":small orange diamond:", "&#x1f538;"},
+ {":small_red_triangle:", ":red triangle pointed up:", "&#x1f53a;"},
+ {":small_red_triangle_down:", ":red triangle pointed down:", "&#x1f53b;"},
+ {":smile:", ":grinning face with smiling eyes:", "&#x1f604;"},
+ {":smile_cat:", ":grinning cat face with smiling eyes:", "&#x1f638;"},
+ {":smiley:", ":grinning face with big eyes:", "&#x1f603;"},
+ {":smiley_cat:", ":grinning cat face:", "&#x1f63a;"},
+ {":smiling_imp:", ":smiling face with horns:", "&#x1f608;"},
+ {":smirk:", ":smirking face:", "&#x1f60f;"},
+ {":smirk_cat:", ":cat face with wry smile:", "&#x1f63c;"},
+ {":smoking:", ":cigarette:", "&#x1f6ac;"},
+ {":snail:", ":snail:", "&#x1f40c;"},
+ {":snake:", ":snake:", "&#x1f40d;"},
+ {":sneezing_face:", ":sneezing face:", "&#x1f927;"},
+ {":snowboarder:", ":snowboarder:", "&#x1f3c2;"},
+ {":snowflake:", ":snowflake:", "&#x2744;"},
+ {":snowman:", ":snowman without snow:", "&#x26c4;"},
+ {":snowman_with_snow:", ":snowman:", "&#x2603;"},
+ {":sob:", ":loudly crying face:", "&#x1f62d;"},
+ {":soccer:", ":soccer ball:", "&#x26bd;"},
+ {":solomon_islands:", ":flag solomon islands:", "&#x1f1f8;&#x1f1e7;"},
+ {":somalia:", ":flag somalia:", "&#x1f1f8;&#x1f1f4;"},
+ {":soon:", ":soon arrow:", "&#x1f51c;"},
+ {":sos:", ":sos button:", "&#x1f198;"},
+ {":sound:", ":speaker medium volume:", "&#x1f509;"},
+ {":south_africa:", ":flag south africa:", "&#x1f1ff;&#x1f1e6;"},
+ {":south_georgia_south_sandwich_islands:", ":flag south georgia & south sandwich islands:", "&#x1f1ec;&#x1f1f8;"},
+ {":south_sudan:", ":flag south sudan:", "&#x1f1f8;&#x1f1f8;"},
+ {":space_invader:", ":alien monster:", "&#x1f47e;"},
+ {":spades:", ":spade suit:", "&#x2660;"},
+ {":spaghetti:", ":spaghetti:", "&#x1f35d;"},
+ {":sparkle:", ":sparkle:", "&#x2747;"},
+ {":sparkler:", ":sparkler:", "&#x1f387;"},
+ {":sparkles:", ":sparkles:", "&#x2728;"},
+ {":sparkling_heart:", ":sparkling heart:", "&#x1f496;"},
+ {":speak_no_evil:", ":speak-no-evil monkey:", "&#x1f64a;"},
+ {":speaker:", ":speaker low volume:", "&#x1f508;"},
+ {":speaking_head:", ":speaking head:", "&#x1f5e3;"},
+ {":speech_balloon:", ":speech balloon:", "&#x1f4ac;"},
+ {":speedboat:", ":speedboat:", "&#x1f6a4;"},
+ {":spider:", ":spider:", "&#x1f577;"},
+ {":spider_web:", ":spider web:", "&#x1f578;"},
+ {":spiral_calendar:", ":spiral calendar:", "&#x1f5d3;"},
+ {":spiral_notepad:", ":spiral notepad:", "&#x1f5d2;"},
+ {":spoon:", ":spoon:", "&#x1f944;"},
+ {":squid:", ":squid:", "&#x1f991;"},
+ {":sri_lanka:", ":flag sri lanka:", "&#x1f1f1;&#x1f1f0;"},
+ {":st_barthelemy:", ":flag st. barthélemy:", "&#x1f1e7;&#x1f1f1;"},
+ {":st_helena:", ":flag st. helena:", "&#x1f1f8;&#x1f1ed;"},
+ {":st_kitts_nevis:", ":flag st. kitts & nevis:", "&#x1f1f0;&#x1f1f3;"},
+ {":st_lucia:", ":flag st. lucia:", "&#x1f1f1;&#x1f1e8;"},
+ {":st_pierre_miquelon:", ":flag st. pierre & miquelon:", "&#x1f1f5;&#x1f1f2;"},
+ {":st_vincent_grenadines:", ":flag st. vincent & grenadines:", "&#x1f1fb;&#x1f1e8;"},
+ {":stadium:", ":stadium:", "&#x1f3df;"},
+ {":star:", ":star:", "&#x2b50;"},
+ {":star2:", ":glowing star:", "&#x1f31f;"},
+ {":star_and_crescent:", ":star and crescent:", "&#x262a;"},
+ {":star_of_david:", ":star of david:", "&#x2721;"},
+ {":stars:", ":shooting star:", "&#x1f320;"},
+ {":station:", ":station:", "&#x1f689;"},
+ {":statue_of_liberty:", ":statue of liberty:", "&#x1f5fd;"},
+ {":steam_locomotive:", ":locomotive:", "&#x1f682;"},
+ {":stew:", ":pot of food:", "&#x1f372;"},
+ {":stop_button:", ":stop button:", "&#x23f9;"},
+ {":stop_sign:", ":stop sign:", "&#x1f6d1;"},
+ {":stopwatch:", ":stopwatch:", "&#x23f1;"},
+ {":straight_ruler:", ":straight ruler:", "&#x1f4cf;"},
+ {":strawberry:", ":strawberry:", "&#x1f353;"},
+ {":stuck_out_tongue:", ":face with tongue:", "&#x1f61b;"},
+ {":stuck_out_tongue_closed_eyes:", ":squinting face with tongue:", "&#x1f61d;"},
+ {":stuck_out_tongue_winking_eye:", ":winking face with tongue:", "&#x1f61c;"},
+ {":studio_microphone:", ":studio microphone:", "&#x1f399;"},
+ {":stuffed_flatbread:", ":stuffed flatbread:", "&#x1f959;"},
+ {":sudan:", ":flag sudan:", "&#x1f1f8;&#x1f1e9;"},
+ {":sun_behind_large_cloud:", ":sun behind large cloud:", "&#x1f325;"},
+ {":sun_behind_rain_cloud:", ":sun behind rain cloud:", "&#x1f326;"},
+ {":sun_behind_small_cloud:", ":sun behind small cloud:", "&#x1f324;"},
+ {":sun_with_face:", ":sun with face:", "&#x1f31e;"},
+ {":sunflower:", ":sunflower:", "&#x1f33b;"},
+ {":sunglasses:", ":smiling face with sunglasses:", "&#x1f60e;"},
+ {":sunny:", ":sun:", "&#x2600;"},
+ {":sunrise:", ":sunrise:", "&#x1f305;"},
+ {":sunrise_over_mountains:", ":sunrise over mountains:", "&#x1f304;"},
+ {":surfer:", ":person surfing:", "&#x1f3c4;"},
+ {":surfing_man:", ":person surfing:", "&#x1f3c4;"},
+ {":surfing_woman:", ":woman surfing:", "&#x1f3c4;&#x200d;&#x2640;&#xfe0f;"},
+ {":suriname:", ":flag suriname:", "&#x1f1f8;&#x1f1f7;"},
+ {":sushi:", ":sushi:", "&#x1f363;"},
+ {":suspension_railway:", ":suspension railway:", "&#x1f69f;"},
+ {":swaziland:", ":flag swaziland:", "&#x1f1f8;&#x1f1ff;"},
+ {":sweat:", ":downcast face with sweat:", "&#x1f613;"},
+ {":sweat_drops:", ":sweat droplets:", "&#x1f4a6;"},
+ {":sweat_smile:", ":grinning face with sweat:", "&#x1f605;"},
+ {":sweden:", ":flag sweden:", "&#x1f1f8;&#x1f1ea;"},
+ {":sweet_potato:", ":roasted sweet potato:", "&#x1f360;"},
+ {":swimmer:", ":person swimming:", "&#x1f3ca;"},
+ {":swimming_man:", ":person swimming:", "&#x1f3ca;"},
+ {":swimming_woman:", ":woman swimming:", "&#x1f3ca;&#x200d;&#x2640;&#xfe0f;"},
+ {":switzerland:", ":flag switzerland:", "&#x1f1e8;&#x1f1ed;"},
+ {":symbols:", ":input symbols:", "&#x1f523;"},
+ {":synagogue:", ":synagogue:", "&#x1f54d;"},
+ {":syria:", ":flag syria:", "&#x1f1f8;&#x1f1fe;"},
+ {":syringe:", ":syringe:", "&#x1f489;"},
+ {":taco:", ":taco:", "&#x1f32e;"},
+ {":tada:", ":party popper:", "&#x1f389;"},
+ {":taiwan:", ":flag taiwan:", "&#x1f1f9;&#x1f1fc;"},
+ {":tajikistan:", ":flag tajikistan:", "&#x1f1f9;&#x1f1ef;"},
+ {":tanabata_tree:", ":tanabata tree:", "&#x1f38b;"},
+ {":tangerine:", ":tangerine:", "&#x1f34a;"},
+ {":tanzania:", ":flag tanzania:", "&#x1f1f9;&#x1f1ff;"},
+ {":taurus:", ":taurus:", "&#x2649;"},
+ {":taxi:", ":taxi:", "&#x1f695;"},
+ {":tea:", ":teacup without handle:", "&#x1f375;"},
+ {":telephone:", ":telephone:", "&#x260e;"},
+ {":telephone_receiver:", ":telephone receiver:", "&#x1f4de;"},
+ {":telescope:", ":telescope:", "&#x1f52d;"},
+ {":tennis:", ":tennis:", "&#x1f3be;"},
+ {":tent:", ":tent:", "&#x26fa;"},
+ {":thailand:", ":flag thailand:", "&#x1f1f9;&#x1f1ed;"},
+ {":thermometer:", ":thermometer:", "&#x1f321;"},
+ {":thinking:", ":thinking face:", "&#x1f914;"},
+ {":thought_balloon:", ":thought balloon:", "&#x1f4ad;"},
+ {":three:", ":keycap 3:", "&#x0033;&#xfe0f;&#x20e3;"},
+ {":thumbsdown:", ":thumbs down:", "&#x1f44e;"},
+ {":thumbsup:", ":thumbs up:", "&#x1f44d;"},
+ {":ticket:", ":ticket:", "&#x1f3ab;"},
+ {":tickets:", ":admission tickets:", "&#x1f39f;"},
+ {":tiger:", ":tiger face:", "&#x1f42f;"},
+ {":tiger2:", ":tiger:", "&#x1f405;"},
+ {":timer_clock:", ":timer clock:", "&#x23f2;"},
+ {":timor_leste:", ":flag timor-leste:", "&#x1f1f9;&#x1f1f1;"},
+ {":tipping_hand_man:", ":man tipping hand:", "&#x1f481;&#x200d;&#x2642;&#xfe0f;"},
+ {":tipping_hand_woman:", ":person tipping hand:", "&#x1f481;"},
+ {":tired_face:", ":tired face:", "&#x1f62b;"},
+ {":tm:", ":trade mark:", "&#x2122;"},
+ {":togo:", ":flag togo:", "&#x1f1f9;&#x1f1ec;"},
+ {":toilet:", ":toilet:", "&#x1f6bd;"},
+ {":tokelau:", ":flag tokelau:", "&#x1f1f9;&#x1f1f0;"},
+ {":tokyo_tower:", ":tokyo tower:", "&#x1f5fc;"},
+ {":tomato:", ":tomato:", "&#x1f345;"},
+ {":tonga:", ":flag tonga:", "&#x1f1f9;&#x1f1f4;"},
+ {":tongue:", ":tongue:", "&#x1f445;"},
+ {":top:", ":top arrow:", "&#x1f51d;"},
+ {":tophat:", ":top hat:", "&#x1f3a9;"},
+ {":tornado:", ":tornado:", "&#x1f32a;"},
+ {":tr:", ":flag turkey:", "&#x1f1f9;&#x1f1f7;"},
+ {":trackball:", ":trackball:", "&#x1f5b2;"},
+ {":tractor:", ":tractor:", "&#x1f69c;"},
+ {":traffic_light:", ":horizontal traffic light:", "&#x1f6a5;"},
+ {":train:", ":tram car:", "&#x1f68b;"},
+ {":train2:", ":train:", "&#x1f686;"},
+ {":tram:", ":tram:", "&#x1f68a;"},
+ {":triangular_flag_on_post:", ":triangular flag:", "&#x1f6a9;"},
+ {":triangular_ruler:", ":triangular ruler:", "&#x1f4d0;"},
+ {":trident:", ":trident emblem:", "&#x1f531;"},
+ {":trinidad_tobago:", ":flag trinidad & tobago:", "&#x1f1f9;&#x1f1f9;"},
+ {":triumph:", ":face with steam from nose:", "&#x1f624;"},
+ {":trolleybus:", ":trolleybus:", "&#x1f68e;"},
+ {":trophy:", ":trophy:", "&#x1f3c6;"},
+ {":tropical_drink:", ":tropical drink:", "&#x1f379;"},
+ {":tropical_fish:", ":tropical fish:", "&#x1f420;"},
+ {":truck:", ":delivery truck:", "&#x1f69a;"},
+ {":trumpet:", ":trumpet:", "&#x1f3ba;"},
+ {":tshirt:", ":t-shirt:", "&#x1f455;"},
+ {":tulip:", ":tulip:", "&#x1f337;"},
+ {":tumbler_glass:", ":tumbler glass:", "&#x1f943;"},
+ {":tunisia:", ":flag tunisia:", "&#x1f1f9;&#x1f1f3;"},
+ {":turkey:", ":turkey:", "&#x1f983;"},
+ {":turkmenistan:", ":flag turkmenistan:", "&#x1f1f9;&#x1f1f2;"},
+ {":turks_caicos_islands:", ":flag turks & caicos islands:", "&#x1f1f9;&#x1f1e8;"},
+ {":turtle:", ":turtle:", "&#x1f422;"},
+ {":tuvalu:", ":flag tuvalu:", "&#x1f1f9;&#x1f1fb;"},
+ {":tv:", ":television:", "&#x1f4fa;"},
+ {":twisted_rightwards_arrows:", ":shuffle tracks button:", "&#x1f500;"},
+ {":two:", ":keycap 2:", "&#x0032;&#xfe0f;&#x20e3;"},
+ {":two_hearts:", ":two hearts:", "&#x1f495;"},
+ {":two_men_holding_hands:", ":two men holding hands:", "&#x1f46c;"},
+ {":two_women_holding_hands:", ":two women holding hands:", "&#x1f46d;"},
+ {":u5272:", ":japanese \"discount\" button:", "&#x1f239;"},
+ {":u5408:", ":japanese \"passing grade\" button:", "&#x1f234;"},
+ {":u55b6:", ":japanese \"open for business\" button:", "&#x1f23a;"},
+ {":u6307:", ":japanese \"reserved\" button:", "&#x1f22f;"},
+ {":u6708:", ":japanese \"monthly amount\" button:", "&#x1f237;"},
+ {":u6709:", ":japanese \"not free of charge\" button:", "&#x1f236;"},
+ {":u6e80:", ":japanese \"no vacancy\" button:", "&#x1f235;"},
+ {":u7121:", ":japanese \"free of charge\" button:", "&#x1f21a;"},
+ {":u7533:", ":japanese \"application\" button:", "&#x1f238;"},
+ {":u7981:", ":japanese \"prohibited\" button:", "&#x1f232;"},
+ {":u7a7a:", ":japanese \"vacancy\" button:", "&#x1f233;"},
+ {":uganda:", ":flag uganda:", "&#x1f1fa;&#x1f1ec;"},
+ {":uk:", ":flag united kingdom:", "&#x1f1ec;&#x1f1e7;"},
+ {":ukraine:", ":flag ukraine:", "&#x1f1fa;&#x1f1e6;"},
+ {":umbrella:", ":umbrella with rain drops:", "&#x2614;"},
+ {":unamused:", ":unamused face:", "&#x1f612;"},
+ {":underage:", ":no one under eighteen:", "&#x1f51e;"},
+ {":unicorn:", ":unicorn face:", "&#x1f984;"},
+ {":united_arab_emirates:", ":flag united arab emirates:", "&#x1f1e6;&#x1f1ea;"},
+ {":unlock:", ":unlocked:", "&#x1f513;"},
+ {":up:", ":up! button:", "&#x1f199;"},
+ {":upside_down_face:", ":upside-down face:", "&#x1f643;"},
+ {":uruguay:", ":flag uruguay:", "&#x1f1fa;&#x1f1fe;"},
+ {":us:", ":flag united states:", "&#x1f1fa;&#x1f1f8;"},
+ {":us_virgin_islands:", ":flag u.s. virgin islands:", "&#x1f1fb;&#x1f1ee;"},
+ {":uzbekistan:", ":flag uzbekistan:", "&#x1f1fa;&#x1f1ff;"},
+ {":v:", ":victory hand:", "&#x270c;"},
+ {":vanuatu:", ":flag vanuatu:", "&#x1f1fb;&#x1f1fa;"},
+ {":vatican_city:", ":flag vatican city:", "&#x1f1fb;&#x1f1e6;"},
+ {":venezuela:", ":flag venezuela:", "&#x1f1fb;&#x1f1ea;"},
+ {":vertical_traffic_light:", ":vertical traffic light:", "&#x1f6a6;"},
+ {":vhs:", ":videocassette:", "&#x1f4fc;"},
+ {":vibration_mode:", ":vibration mode:", "&#x1f4f3;"},
+ {":video_camera:", ":video camera:", "&#x1f4f9;"},
+ {":video_game:", ":video game:", "&#x1f3ae;"},
+ {":vietnam:", ":flag vietnam:", "&#x1f1fb;&#x1f1f3;"},
+ {":violin:", ":violin:", "&#x1f3bb;"},
+ {":virgo:", ":virgo:", "&#x264d;"},
+ {":volcano:", ":volcano:", "&#x1f30b;"},
+ {":volleyball:", ":volleyball:", "&#x1f3d0;"},
+ {":vs:", ":vs button:", "&#x1f19a;"},
+ {":vulcan_salute:", ":vulcan salute:", "&#x1f596;"},
+ {":walking:", ":person walking:", "&#x1f6b6;"},
+ {":walking_man:", ":person walking:", "&#x1f6b6;"},
+ {":walking_woman:", ":woman walking:", "&#x1f6b6;&#x200d;&#x2640;&#xfe0f;"},
+ {":wallis_futuna:", ":flag wallis & futuna:", "&#x1f1fc;&#x1f1eb;"},
+ {":waning_crescent_moon:", ":waning crescent moon:", "&#x1f318;"},
+ {":waning_gibbous_moon:", ":waning gibbous moon:", "&#x1f316;"},
+ {":warning:", ":warning:", "&#x26a0;"},
+ {":wastebasket:", ":wastebasket:", "&#x1f5d1;"},
+ {":watch:", ":watch:", "&#x231a;"},
+ {":water_buffalo:", ":water buffalo:", "&#x1f403;"},
+ {":watermelon:", ":watermelon:", "&#x1f349;"},
+ {":wave:", ":waving hand:", "&#x1f44b;"},
+ {":wavy_dash:", ":wavy dash:", "&#x3030;"},
+ {":waxing_crescent_moon:", ":waxing crescent moon:", "&#x1f312;"},
+ {":waxing_gibbous_moon:", ":waxing gibbous moon:", "&#x1f314;"},
+ {":wc:", ":water closet:", "&#x1f6be;"},
+ {":weary:", ":weary face:", "&#x1f629;"},
+ {":wedding:", ":wedding:", "&#x1f492;"},
+ {":weight_lifting_man:", ":person lifting weights:", "&#x1f3cb;"},
+ {":weight_lifting_woman:", ":woman lifting weights:", "&#x1f3cb;&#xfe0f;&#x200d;&#x2640;&#xfe0f;"},
+ {":western_sahara:", ":flag western sahara:", "&#x1f1ea;&#x1f1ed;"},
+ {":whale:", ":spouting whale:", "&#x1f433;"},
+ {":whale2:", ":whale:", "&#x1f40b;"},
+ {":wheel_of_dharma:", ":wheel of dharma:", "&#x2638;"},
+ {":wheelchair:", ":wheelchair symbol:", "&#x267f;"},
+ {":white_check_mark:", ":white heavy check mark:", "&#x2705;"},
+ {":white_circle:", ":white circle:", "&#x26aa;"},
+ {":white_flag:", ":white flag:", "&#x1f3f3;"},
+ {":white_flower:", ":white flower:", "&#x1f4ae;"},
+ {":white_large_square:", ":white large square:", "&#x2b1c;"},
+ {":white_medium_small_square:", ":white medium-small square:", "&#x25fd;"},
+ {":white_medium_square:", ":white medium square:", "&#x25fb;"},
+ {":white_small_square:", ":white small square:", "&#x25ab;"},
+ {":white_square_button:", ":white square button:", "&#x1f533;"},
+ {":wilted_flower:", ":wilted flower:", "&#x1f940;"},
+ {":wind_chime:", ":wind chime:", "&#x1f390;"},
+ {":wind_face:", ":wind face:", "&#x1f32c;"},
+ {":wine_glass:", ":wine glass:", "&#x1f377;"},
+ {":wink:", ":winking face:", "&#x1f609;"},
+ {":wolf:", ":wolf face:", "&#x1f43a;"},
+ {":woman:", ":woman:", "&#x1f469;"},
+ {":woman_artist:", ":woman artist:", "&#x1f469;&#x200d;&#x1f3a8;"},
+ {":woman_astronaut:", ":woman astronaut:", "&#x1f469;&#x200d;&#x1f680;"},
+ {":woman_cartwheeling:", ":woman cartwheeling:", "&#x1f938;&#x200d;&#x2640;&#xfe0f;"},
+ {":woman_cook:", ":woman cook:", "&#x1f469;&#x200d;&#x1f373;"},
+ {":woman_facepalming:", ":woman facepalming:", "&#x1f926;&#x200d;&#x2640;&#xfe0f;"},
+ {":woman_factory_worker:", ":woman factory worker:", "&#x1f469;&#x200d;&#x1f3ed;"},
+ {":woman_farmer:", ":woman farmer:", "&#x1f469;&#x200d;&#x1f33e;"},
+ {":woman_firefighter:", ":woman firefighter:", "&#x1f469;&#x200d;&#x1f692;"},
+ {":woman_health_worker:", ":woman health worker:", "&#x1f469;&#x200d;&#x2695;&#xfe0f;"},
+ {":woman_judge:", ":woman judge:", "&#x1f469;&#x200d;&#x2696;&#xfe0f;"},
+ {":woman_juggling:", ":woman juggling:", "&#x1f939;&#x200d;&#x2640;&#xfe0f;"},
+ {":woman_mechanic:", ":woman mechanic:", "&#x1f469;&#x200d;&#x1f527;"},
+ {":woman_office_worker:", ":woman office worker:", "&#x1f469;&#x200d;&#x1f4bc;"},
+ {":woman_pilot:", ":woman pilot:", "&#x1f469;&#x200d;&#x2708;&#xfe0f;"},
+ {":woman_playing_handball:", ":woman playing handball:", "&#x1f93e;&#x200d;&#x2640;&#xfe0f;"},
+ {":woman_playing_water_polo:", ":woman playing water polo:", "&#x1f93d;&#x200d;&#x2640;&#xfe0f;"},
+ {":woman_scientist:", ":woman scientist:", "&#x1f469;&#x200d;&#x1f52c;"},
+ {":woman_shrugging:", ":woman shrugging:", "&#x1f937;&#x200d;&#x2640;&#xfe0f;"},
+ {":woman_singer:", ":woman singer:", "&#x1f469;&#x200d;&#x1f3a4;"},
+ {":woman_student:", ":woman student:", "&#x1f469;&#x200d;&#x1f393;"},
+ {":woman_teacher:", ":woman teacher:", "&#x1f469;&#x200d;&#x1f3eb;"},
+ {":woman_technologist:", ":woman technologist:", "&#x1f469;&#x200d;&#x1f4bb;"},
+ {":woman_with_turban:", ":woman wearing turban:", "&#x1f473;&#x200d;&#x2640;&#xfe0f;"},
+ {":womans_clothes:", ":woman's clothes:", "&#x1f45a;"},
+ {":womans_hat:", ":woman's hat:", "&#x1f452;"},
+ {":women_wrestling:", ":women wrestling:", "&#x1f93c;&#x200d;&#x2640;&#xfe0f;"},
+ {":womens:", ":women's room:", "&#x1f6ba;"},
+ {":world_map:", ":world map:", "&#x1f5fa;"},
+ {":worried:", ":worried face:", "&#x1f61f;"},
+ {":wrench:", ":wrench:", "&#x1f527;"},
+ {":writing_hand:", ":writing hand:", "&#x270d;"},
+ {":x:", ":cross mark:", "&#x274c;"},
+ {":yellow_heart:", ":yellow heart:", "&#x1f49b;"},
+ {":yemen:", ":flag yemen:", "&#x1f1fe;&#x1f1ea;"},
+ {":yen:", ":yen banknote:", "&#x1f4b4;"},
+ {":yin_yang:", ":yin yang:", "&#x262f;"},
+ {":yum:", ":face savoring food:", "&#x1f60b;"},
+ {":zambia:", ":flag zambia:", "&#x1f1ff;&#x1f1f2;"},
+ {":zap:", ":high voltage:", "&#x26a1;"},
+ {":zero:", ":keycap 0:", "&#x0030;&#xfe0f;&#x20e3;"},
+ {":zimbabwe:", ":flag zimbabwe:", "&#x1f1ff;&#x1f1fc;"},
+ {":zipper_mouth_face:", ":zipper-mouth face:", "&#x1f910;"},
+ {":zzz:", ":zzz:", "&#x1f4a4;"},
+ {"", ":smiling face with 3 hearts:", "&#x1f970;"},
+ {"", ":star-struck:", "&#x1f929;"},
+ {"", ":zany face:", "&#x1f92a;"},
+ {"", ":face with hand over mouth:", "&#x1f92d;"},
+ {"", ":shushing face:", "&#x1f92b;"},
+ {"", ":face with raised eyebrow:", "&#x1f928;"},
+ {"", ":face vomiting:", "&#x1f92e;"},
+ {"", ":hot face:", "&#x1f975;"},
+ {"", ":cold face:", "&#x1f976;"},
+ {"", ":woozy face:", "&#x1f974;"},
+ {"", ":exploding head:", "&#x1f92f;"},
+ {"", ":partying face:", "&#x1f973;"},
+ {"", ":face with monocle:", "&#x1f9d0;"},
+ {"", ":pleading face:", "&#x1f97a;"},
+ {"", ":face with symbols on mouth:", "&#x1f92c;"},
+ {"", ":orange heart:", "&#x1f9e1;"},
+ {"", ":left speech bubble:", "&#x1f5e8;"},
+ {"", ":love-you gesture:", "&#x1f91f;"},
+ {"", ":palms up together:", "&#x1f932;"},
+ {"", ":leg:", "&#x1f9b5;"},
+ {"", ":foot:", "&#x1f9b6;"},
+ {"", ":brain:", "&#x1f9e0;"},
+ {"", ":tooth:", "&#x1f9b7;"},
+ {"", ":bone:", "&#x1f9b4;"},
+ {"", ":eye:", "&#x1f441;"},
+ {"", ":child:", "&#x1f9d2;"},
+ {"", ":person:", "&#x1f9d1;"},
+ {"", ":man blond hair:", "&#x1f471;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man red hair:", "&#x1f468;&#x200d;&#x1f9b0;"},
+ {"", ":man curly hair:", "&#x1f468;&#x200d;&#x1f9b1;"},
+ {"", ":man white hair:", "&#x1f468;&#x200d;&#x1f9b3;"},
+ {"", ":man bald:", "&#x1f468;&#x200d;&#x1f9b2;"},
+ {"", ":man beard:", "&#x1f9d4;"},
+ {"", ":woman red hair:", "&#x1f469;&#x200d;&#x1f9b0;"},
+ {"", ":woman curly hair:", "&#x1f469;&#x200d;&#x1f9b1;"},
+ {"", ":woman white hair:", "&#x1f469;&#x200d;&#x1f9b3;"},
+ {"", ":woman bald:", "&#x1f469;&#x200d;&#x1f9b2;"},
+ {"", ":older person:", "&#x1f9d3;"},
+ {"", ":woman frowning:", "&#x1f64d;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman pouting:", "&#x1f64e;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing no:", "&#x1f645;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing ok:", "&#x1f646;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman tipping hand:", "&#x1f481;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman raising hand:", "&#x1f64b;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":man bowing:", "&#x1f647;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":person facepalming:", "&#x1f926;"},
+ {"", ":person shrugging:", "&#x1f937;"},
+ {"", ":man police officer:", "&#x1f46e;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man detective:", "&#x1f575;&#xfe0f;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man guard:", "&#x1f482;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man construction worker:", "&#x1f477;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man wearing turban:", "&#x1f473;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman with headscarf:", "&#x1f9d5;"},
+ {"", ":breast-feeding:", "&#x1f931;"},
+ {"", ":superhero:", "&#x1f9b8;"},
+ {"", ":man superhero:", "&#x1f9b8;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman superhero:", "&#x1f9b8;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":supervillain:", "&#x1f9b9;"},
+ {"", ":man supervillain:", "&#x1f9b9;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman supervillain:", "&#x1f9b9;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":mage:", "&#x1f9d9;"},
+ {"", ":man mage:", "&#x1f9d9;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman mage:", "&#x1f9d9;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":fairy:", "&#x1f9da;"},
+ {"", ":man fairy:", "&#x1f9da;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman fairy:", "&#x1f9da;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":vampire:", "&#x1f9db;"},
+ {"", ":man vampire:", "&#x1f9db;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman vampire:", "&#x1f9db;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":merperson:", "&#x1f9dc;"},
+ {"", ":merman:", "&#x1f9dc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":mermaid:", "&#x1f9dc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":elf:", "&#x1f9dd;"},
+ {"", ":man elf:", "&#x1f9dd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman elf:", "&#x1f9dd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":genie:", "&#x1f9de;"},
+ {"", ":man genie:", "&#x1f9de;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman genie:", "&#x1f9de;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":zombie:", "&#x1f9df;"},
+ {"", ":man zombie:", "&#x1f9df;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman zombie:", "&#x1f9df;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting massage:", "&#x1f486;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting haircut:", "&#x1f487;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":man walking:", "&#x1f6b6;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man running:", "&#x1f3c3;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":women with bunny ears:", "&#x1f46f;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person in steamy room:", "&#x1f9d6;"},
+ {"", ":man in steamy room:", "&#x1f9d6;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman in steamy room:", "&#x1f9d6;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person climbing:", "&#x1f9d7;"},
+ {"", ":man climbing:", "&#x1f9d7;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman climbing:", "&#x1f9d7;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":man golfing:", "&#x1f3cc;&#xfe0f;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man surfing:", "&#x1f3c4;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man rowing boat:", "&#x1f6a3;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man swimming:", "&#x1f3ca;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bouncing ball:", "&#x26f9;&#xfe0f;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man lifting weights:", "&#x1f3cb;&#xfe0f;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man biking:", "&#x1f6b4;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mountain biking:", "&#x1f6b5;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":person cartwheeling:", "&#x1f938;"},
+ {"", ":people wrestling:", "&#x1f93c;"},
+ {"", ":person playing water polo:", "&#x1f93d;"},
+ {"", ":person playing handball:", "&#x1f93e;"},
+ {"", ":person juggling:", "&#x1f939;"},
+ {"", ":person in lotus position:", "&#x1f9d8;"},
+ {"", ":man in lotus position:", "&#x1f9d8;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman in lotus position:", "&#x1f9d8;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":kiss woman, man:", "&#x1f469;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f48b;&#x200d;&#x1f468;"},
+ {"", ":couple with heart woman, man:", "&#x1f469;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f468;"},
+ {"", ":couple with heart man, man:", "&#x1f468;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f468;"},
+ {"", ":couple with heart woman, woman:", "&#x1f469;&#x200d;&#x2764;&#xfe0f;&#x200d;&#x1f469;"},
+ {"", ":family man, boy:", "&#x1f468;&#x200d;&#x1f466;"},
+ {"", ":family man, boy, boy:", "&#x1f468;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {"", ":family man, girl:", "&#x1f468;&#x200d;&#x1f467;"},
+ {"", ":family man, girl, boy:", "&#x1f468;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {"", ":family man, girl, girl:", "&#x1f468;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {"", ":family woman, boy:", "&#x1f469;&#x200d;&#x1f466;"},
+ {"", ":family woman, boy, boy:", "&#x1f469;&#x200d;&#x1f466;&#x200d;&#x1f466;"},
+ {"", ":family woman, girl:", "&#x1f469;&#x200d;&#x1f467;"},
+ {"", ":family woman, girl, boy:", "&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f466;"},
+ {"", ":family woman, girl, girl:", "&#x1f469;&#x200d;&#x1f467;&#x200d;&#x1f467;"},
+ {"", ":red hair:", "&#x1f9b0;"},
+ {"", ":curly hair:", "&#x1f9b1;"},
+ {"", ":white hair:", "&#x1f9b3;"},
+ {"", ":bald:", "&#x1f9b2;"},
+ {"", ":female sign:", "&#x2640;"},
+ {"", ":male sign:", "&#x2642;"},
+ {"", ":raccoon:", "&#x1f99d;"},
+ {"", ":zebra:", "&#x1f993;"},
+ {"", ":llama:", "&#x1f999;"},
+ {"", ":giraffe:", "&#x1f992;"},
+ {"", ":hippopotamus:", "&#x1f99b;"},
+ {"", ":hedgehog:", "&#x1f994;"},
+ {"", ":kangaroo:", "&#x1f998;"},
+ {"", ":badger:", "&#x1f9a1;"},
+ {"", ":swan:", "&#x1f9a2;"},
+ {"", ":peacock:", "&#x1f99a;"},
+ {"", ":parrot:", "&#x1f99c;"},
+ {"", ":sauropod:", "&#x1f995;"},
+ {"", ":t-rex:", "&#x1f996;"},
+ {"", ":cricket:", "&#x1f997;"},
+ {"", ":mosquito:", "&#x1f99f;"},
+ {"", ":microbe:", "&#x1f9a0;"},
+ {"", ":mango:", "&#x1f96d;"},
+ {"", ":coconut:", "&#x1f965;"},
+ {"", ":leafy green:", "&#x1f96c;"},
+ {"", ":broccoli:", "&#x1f966;"},
+ {"", ":pretzel:", "&#x1f968;"},
+ {"", ":bagel:", "&#x1f96f;"},
+ {"", ":cut of meat:", "&#x1f969;"},
+ {"", ":sandwich:", "&#x1f96a;"},
+ {"", ":bowl with spoon:", "&#x1f963;"},
+ {"", ":salt:", "&#x1f9c2;"},
+ {"", ":canned food:", "&#x1f96b;"},
+ {"", ":moon cake:", "&#x1f96e;"},
+ {"", ":dumpling:", "&#x1f95f;"},
+ {"", ":fortune cookie:", "&#x1f960;"},
+ {"", ":takeout box:", "&#x1f961;"},
+ {"", ":lobster:", "&#x1f99e;"},
+ {"", ":cupcake:", "&#x1f9c1;"},
+ {"", ":pie:", "&#x1f967;"},
+ {"", ":cup with straw:", "&#x1f964;"},
+ {"", ":chopsticks:", "&#x1f962;"},
+ {"", ":compass:", "&#x1f9ed;"},
+ {"", ":brick:", "&#x1f9f1;"},
+ {"", ":skateboard:", "&#x1f6f9;"},
+ {"", ":flying saucer:", "&#x1f6f8;"},
+ {"", ":luggage:", "&#x1f9f3;"},
+ {"", ":firecracker:", "&#x1f9e8;"},
+ {"", ":red envelope:", "&#x1f9e7;"},
+ {"", ":softball:", "&#x1f94e;"},
+ {"", ":flying disc:", "&#x1f94f;"},
+ {"", ":lacrosse:", "&#x1f94d;"},
+ {"", ":sled:", "&#x1f6f7;"},
+ {"", ":curling stone:", "&#x1f94c;"},
+ {"", ":nazar amulet:", "&#x1f9ff;"},
+ {"", ":jigsaw:", "&#x1f9e9;"},
+ {"", ":teddy bear:", "&#x1f9f8;"},
+ {"", ":chess pawn:", "&#x265f;"},
+ {"", ":thread:", "&#x1f9f5;"},
+ {"", ":yarn:", "&#x1f9f6;"},
+ {"", ":goggles:", "&#x1f97d;"},
+ {"", ":lab coat:", "&#x1f97c;"},
+ {"", ":scarf:", "&#x1f9e3;"},
+ {"", ":gloves:", "&#x1f9e4;"},
+ {"", ":coat:", "&#x1f9e5;"},
+ {"", ":socks:", "&#x1f9e6;"},
+ {"", ":hiking boot:", "&#x1f97e;"},
+ {"", ":flat shoe:", "&#x1f97f;"},
+ {"", ":billed cap:", "&#x1f9e2;"},
+ {"", ":abacus:", "&#x1f9ee;"},
+ {"", ":receipt:", "&#x1f9fe;"},
+ {"", ":toolbox:", "&#x1f9f0;"},
+ {"", ":magnet:", "&#x1f9f2;"},
+ {"", ":test tube:", "&#x1f9ea;"},
+ {"", ":petri dish:", "&#x1f9eb;"},
+ {"", ":dna:", "&#x1f9ec;"},
+ {"", ":lotion bottle:", "&#x1f9f4;"},
+ {"", ":safety pin:", "&#x1f9f7;"},
+ {"", ":broom:", "&#x1f9f9;"},
+ {"", ":basket:", "&#x1f9fa;"},
+ {"", ":roll of paper:", "&#x1f9fb;"},
+ {"", ":soap:", "&#x1f9fc;"},
+ {"", ":sponge:", "&#x1f9fd;"},
+ {"", ":fire extinguisher:", "&#x1f9ef;"},
+ {"", ":eject button:", "&#x23cf;"},
+ {"", ":medical symbol:", "&#x2695;"},
+ {"", ":infinity:", "&#x267e;"},
+ {"", ":pirate flag:", "&#x1f3f4;&#x200d;&#x2620;&#xfe0f;"},
+ {"", ":flag ascension island:", "&#x1f1e6;&#x1f1e8;"},
+ {"", ":flag bouvet island:", "&#x1f1e7;&#x1f1fb;"},
+ {"", ":flag clipperton island:", "&#x1f1e8;&#x1f1f5;"},
+ {"", ":flag diego garcia:", "&#x1f1e9;&#x1f1ec;"},
+ {"", ":flag ceuta & melilla:", "&#x1f1ea;&#x1f1e6;"},
+ {"", ":flag heard & mcdonald islands:", "&#x1f1ed;&#x1f1f2;"},
+ {"", ":flag st. martin:", "&#x1f1f2;&#x1f1eb;"},
+ {"", ":flag svalbard & jan mayen:", "&#x1f1f8;&#x1f1ef;"},
+ {"", ":flag tristan da cunha:", "&#x1f1f9;&#x1f1e6;"},
+ {"", ":flag u.s. outlying islands:", "&#x1f1fa;&#x1f1f2;"},
+ {"", ":flag united nations:", "&#x1f1fa;&#x1f1f3;"},
+ {"", ":flag england:", "&#x1f3f4;&#xe0067;&#xe0062;&#xe0065;&#xe006e;&#xe0067;&#xe007f;"},
+ {"", ":flag scotland:", "&#x1f3f4;&#xe0067;&#xe0062;&#xe0073;&#xe0063;&#xe0074;&#xe007f;"},
+ {"", ":flag wales:", "&#x1f3f4;&#xe0067;&#xe0062;&#xe0077;&#xe006c;&#xe0073;&#xe007f;"},
+ {"", ":waving hand light skin tone:", "&#x1f44b;&#x1f3fb;"},
+ {"", ":waving hand medium-light skin tone:", "&#x1f44b;&#x1f3fc;"},
+ {"", ":waving hand medium skin tone:", "&#x1f44b;&#x1f3fd;"},
+ {"", ":waving hand medium-dark skin tone:", "&#x1f44b;&#x1f3fe;"},
+ {"", ":waving hand dark skin tone:", "&#x1f44b;&#x1f3ff;"},
+ {"", ":raised back of hand light skin tone:", "&#x1f91a;&#x1f3fb;"},
+ {"", ":raised back of hand medium-light skin tone:", "&#x1f91a;&#x1f3fc;"},
+ {"", ":raised back of hand medium skin tone:", "&#x1f91a;&#x1f3fd;"},
+ {"", ":raised back of hand medium-dark skin tone:", "&#x1f91a;&#x1f3fe;"},
+ {"", ":raised back of hand dark skin tone:", "&#x1f91a;&#x1f3ff;"},
+ {"", ":hand with fingers splayed light skin tone:", "&#x1f590;&#x1f3fb;"},
+ {"", ":hand with fingers splayed medium-light skin tone:", "&#x1f590;&#x1f3fc;"},
+ {"", ":hand with fingers splayed medium skin tone:", "&#x1f590;&#x1f3fd;"},
+ {"", ":hand with fingers splayed medium-dark skin tone:", "&#x1f590;&#x1f3fe;"},
+ {"", ":hand with fingers splayed dark skin tone:", "&#x1f590;&#x1f3ff;"},
+ {"", ":raised hand light skin tone:", "&#x270b;&#x1f3fb;"},
+ {"", ":raised hand medium-light skin tone:", "&#x270b;&#x1f3fc;"},
+ {"", ":raised hand medium skin tone:", "&#x270b;&#x1f3fd;"},
+ {"", ":raised hand medium-dark skin tone:", "&#x270b;&#x1f3fe;"},
+ {"", ":raised hand dark skin tone:", "&#x270b;&#x1f3ff;"},
+ {"", ":vulcan salute light skin tone:", "&#x1f596;&#x1f3fb;"},
+ {"", ":vulcan salute medium-light skin tone:", "&#x1f596;&#x1f3fc;"},
+ {"", ":vulcan salute medium skin tone:", "&#x1f596;&#x1f3fd;"},
+ {"", ":vulcan salute medium-dark skin tone:", "&#x1f596;&#x1f3fe;"},
+ {"", ":vulcan salute dark skin tone:", "&#x1f596;&#x1f3ff;"},
+ {"", ":ok hand light skin tone:", "&#x1f44c;&#x1f3fb;"},
+ {"", ":ok hand medium-light skin tone:", "&#x1f44c;&#x1f3fc;"},
+ {"", ":ok hand medium skin tone:", "&#x1f44c;&#x1f3fd;"},
+ {"", ":ok hand medium-dark skin tone:", "&#x1f44c;&#x1f3fe;"},
+ {"", ":ok hand dark skin tone:", "&#x1f44c;&#x1f3ff;"},
+ {"", ":victory hand light skin tone:", "&#x270c;&#x1f3fb;"},
+ {"", ":victory hand medium-light skin tone:", "&#x270c;&#x1f3fc;"},
+ {"", ":victory hand medium skin tone:", "&#x270c;&#x1f3fd;"},
+ {"", ":victory hand medium-dark skin tone:", "&#x270c;&#x1f3fe;"},
+ {"", ":victory hand dark skin tone:", "&#x270c;&#x1f3ff;"},
+ {"", ":crossed fingers light skin tone:", "&#x1f91e;&#x1f3fb;"},
+ {"", ":crossed fingers medium-light skin tone:", "&#x1f91e;&#x1f3fc;"},
+ {"", ":crossed fingers medium skin tone:", "&#x1f91e;&#x1f3fd;"},
+ {"", ":crossed fingers medium-dark skin tone:", "&#x1f91e;&#x1f3fe;"},
+ {"", ":crossed fingers dark skin tone:", "&#x1f91e;&#x1f3ff;"},
+ {"", ":love-you gesture light skin tone:", "&#x1f91f;&#x1f3fb;"},
+ {"", ":love-you gesture medium-light skin tone:", "&#x1f91f;&#x1f3fc;"},
+ {"", ":love-you gesture medium skin tone:", "&#x1f91f;&#x1f3fd;"},
+ {"", ":love-you gesture medium-dark skin tone:", "&#x1f91f;&#x1f3fe;"},
+ {"", ":love-you gesture dark skin tone:", "&#x1f91f;&#x1f3ff;"},
+ {"", ":sign of the horns light skin tone:", "&#x1f918;&#x1f3fb;"},
+ {"", ":sign of the horns medium-light skin tone:", "&#x1f918;&#x1f3fc;"},
+ {"", ":sign of the horns medium skin tone:", "&#x1f918;&#x1f3fd;"},
+ {"", ":sign of the horns medium-dark skin tone:", "&#x1f918;&#x1f3fe;"},
+ {"", ":sign of the horns dark skin tone:", "&#x1f918;&#x1f3ff;"},
+ {"", ":call me hand light skin tone:", "&#x1f919;&#x1f3fb;"},
+ {"", ":call me hand medium-light skin tone:", "&#x1f919;&#x1f3fc;"},
+ {"", ":call me hand medium skin tone:", "&#x1f919;&#x1f3fd;"},
+ {"", ":call me hand medium-dark skin tone:", "&#x1f919;&#x1f3fe;"},
+ {"", ":call me hand dark skin tone:", "&#x1f919;&#x1f3ff;"},
+ {"", ":backhand index pointing left light skin tone:", "&#x1f448;&#x1f3fb;"},
+ {"", ":backhand index pointing left medium-light skin tone:", "&#x1f448;&#x1f3fc;"},
+ {"", ":backhand index pointing left medium skin tone:", "&#x1f448;&#x1f3fd;"},
+ {"", ":backhand index pointing left medium-dark skin tone:", "&#x1f448;&#x1f3fe;"},
+ {"", ":backhand index pointing left dark skin tone:", "&#x1f448;&#x1f3ff;"},
+ {"", ":backhand index pointing right light skin tone:", "&#x1f449;&#x1f3fb;"},
+ {"", ":backhand index pointing right medium-light skin tone:", "&#x1f449;&#x1f3fc;"},
+ {"", ":backhand index pointing right medium skin tone:", "&#x1f449;&#x1f3fd;"},
+ {"", ":backhand index pointing right medium-dark skin tone:", "&#x1f449;&#x1f3fe;"},
+ {"", ":backhand index pointing right dark skin tone:", "&#x1f449;&#x1f3ff;"},
+ {"", ":backhand index pointing up light skin tone:", "&#x1f446;&#x1f3fb;"},
+ {"", ":backhand index pointing up medium-light skin tone:", "&#x1f446;&#x1f3fc;"},
+ {"", ":backhand index pointing up medium skin tone:", "&#x1f446;&#x1f3fd;"},
+ {"", ":backhand index pointing up medium-dark skin tone:", "&#x1f446;&#x1f3fe;"},
+ {"", ":backhand index pointing up dark skin tone:", "&#x1f446;&#x1f3ff;"},
+ {"", ":middle finger light skin tone:", "&#x1f595;&#x1f3fb;"},
+ {"", ":middle finger medium-light skin tone:", "&#x1f595;&#x1f3fc;"},
+ {"", ":middle finger medium skin tone:", "&#x1f595;&#x1f3fd;"},
+ {"", ":middle finger medium-dark skin tone:", "&#x1f595;&#x1f3fe;"},
+ {"", ":middle finger dark skin tone:", "&#x1f595;&#x1f3ff;"},
+ {"", ":backhand index pointing down light skin tone:", "&#x1f447;&#x1f3fb;"},
+ {"", ":backhand index pointing down medium-light skin tone:", "&#x1f447;&#x1f3fc;"},
+ {"", ":backhand index pointing down medium skin tone:", "&#x1f447;&#x1f3fd;"},
+ {"", ":backhand index pointing down medium-dark skin tone:", "&#x1f447;&#x1f3fe;"},
+ {"", ":backhand index pointing down dark skin tone:", "&#x1f447;&#x1f3ff;"},
+ {"", ":index pointing up light skin tone:", "&#x261d;&#x1f3fb;"},
+ {"", ":index pointing up medium-light skin tone:", "&#x261d;&#x1f3fc;"},
+ {"", ":index pointing up medium skin tone:", "&#x261d;&#x1f3fd;"},
+ {"", ":index pointing up medium-dark skin tone:", "&#x261d;&#x1f3fe;"},
+ {"", ":index pointing up dark skin tone:", "&#x261d;&#x1f3ff;"},
+ {"", ":thumbs up light skin tone:", "&#x1f44d;&#x1f3fb;"},
+ {"", ":thumbs up medium-light skin tone:", "&#x1f44d;&#x1f3fc;"},
+ {"", ":thumbs up medium skin tone:", "&#x1f44d;&#x1f3fd;"},
+ {"", ":thumbs up medium-dark skin tone:", "&#x1f44d;&#x1f3fe;"},
+ {"", ":thumbs up dark skin tone:", "&#x1f44d;&#x1f3ff;"},
+ {"", ":thumbs down light skin tone:", "&#x1f44e;&#x1f3fb;"},
+ {"", ":thumbs down medium-light skin tone:", "&#x1f44e;&#x1f3fc;"},
+ {"", ":thumbs down medium skin tone:", "&#x1f44e;&#x1f3fd;"},
+ {"", ":thumbs down medium-dark skin tone:", "&#x1f44e;&#x1f3fe;"},
+ {"", ":thumbs down dark skin tone:", "&#x1f44e;&#x1f3ff;"},
+ {"", ":raised fist light skin tone:", "&#x270a;&#x1f3fb;"},
+ {"", ":raised fist medium-light skin tone:", "&#x270a;&#x1f3fc;"},
+ {"", ":raised fist medium skin tone:", "&#x270a;&#x1f3fd;"},
+ {"", ":raised fist medium-dark skin tone:", "&#x270a;&#x1f3fe;"},
+ {"", ":raised fist dark skin tone:", "&#x270a;&#x1f3ff;"},
+ {"", ":oncoming fist light skin tone:", "&#x1f44a;&#x1f3fb;"},
+ {"", ":oncoming fist medium-light skin tone:", "&#x1f44a;&#x1f3fc;"},
+ {"", ":oncoming fist medium skin tone:", "&#x1f44a;&#x1f3fd;"},
+ {"", ":oncoming fist medium-dark skin tone:", "&#x1f44a;&#x1f3fe;"},
+ {"", ":oncoming fist dark skin tone:", "&#x1f44a;&#x1f3ff;"},
+ {"", ":left-facing fist light skin tone:", "&#x1f91b;&#x1f3fb;"},
+ {"", ":left-facing fist medium-light skin tone:", "&#x1f91b;&#x1f3fc;"},
+ {"", ":left-facing fist medium skin tone:", "&#x1f91b;&#x1f3fd;"},
+ {"", ":left-facing fist medium-dark skin tone:", "&#x1f91b;&#x1f3fe;"},
+ {"", ":left-facing fist dark skin tone:", "&#x1f91b;&#x1f3ff;"},
+ {"", ":right-facing fist light skin tone:", "&#x1f91c;&#x1f3fb;"},
+ {"", ":right-facing fist medium-light skin tone:", "&#x1f91c;&#x1f3fc;"},
+ {"", ":right-facing fist medium skin tone:", "&#x1f91c;&#x1f3fd;"},
+ {"", ":right-facing fist medium-dark skin tone:", "&#x1f91c;&#x1f3fe;"},
+ {"", ":right-facing fist dark skin tone:", "&#x1f91c;&#x1f3ff;"},
+ {"", ":clapping hands light skin tone:", "&#x1f44f;&#x1f3fb;"},
+ {"", ":clapping hands medium-light skin tone:", "&#x1f44f;&#x1f3fc;"},
+ {"", ":clapping hands medium skin tone:", "&#x1f44f;&#x1f3fd;"},
+ {"", ":clapping hands medium-dark skin tone:", "&#x1f44f;&#x1f3fe;"},
+ {"", ":clapping hands dark skin tone:", "&#x1f44f;&#x1f3ff;"},
+ {"", ":raising hands light skin tone:", "&#x1f64c;&#x1f3fb;"},
+ {"", ":raising hands medium-light skin tone:", "&#x1f64c;&#x1f3fc;"},
+ {"", ":raising hands medium skin tone:", "&#x1f64c;&#x1f3fd;"},
+ {"", ":raising hands medium-dark skin tone:", "&#x1f64c;&#x1f3fe;"},
+ {"", ":raising hands dark skin tone:", "&#x1f64c;&#x1f3ff;"},
+ {"", ":open hands light skin tone:", "&#x1f450;&#x1f3fb;"},
+ {"", ":open hands medium-light skin tone:", "&#x1f450;&#x1f3fc;"},
+ {"", ":open hands medium skin tone:", "&#x1f450;&#x1f3fd;"},
+ {"", ":open hands medium-dark skin tone:", "&#x1f450;&#x1f3fe;"},
+ {"", ":open hands dark skin tone:", "&#x1f450;&#x1f3ff;"},
+ {"", ":palms up together light skin tone:", "&#x1f932;&#x1f3fb;"},
+ {"", ":palms up together medium-light skin tone:", "&#x1f932;&#x1f3fc;"},
+ {"", ":palms up together medium skin tone:", "&#x1f932;&#x1f3fd;"},
+ {"", ":palms up together medium-dark skin tone:", "&#x1f932;&#x1f3fe;"},
+ {"", ":palms up together dark skin tone:", "&#x1f932;&#x1f3ff;"},
+ {"", ":folded hands light skin tone:", "&#x1f64f;&#x1f3fb;"},
+ {"", ":folded hands medium-light skin tone:", "&#x1f64f;&#x1f3fc;"},
+ {"", ":folded hands medium skin tone:", "&#x1f64f;&#x1f3fd;"},
+ {"", ":folded hands medium-dark skin tone:", "&#x1f64f;&#x1f3fe;"},
+ {"", ":folded hands dark skin tone:", "&#x1f64f;&#x1f3ff;"},
+ {"", ":writing hand light skin tone:", "&#x270d;&#x1f3fb;"},
+ {"", ":writing hand medium-light skin tone:", "&#x270d;&#x1f3fc;"},
+ {"", ":writing hand medium skin tone:", "&#x270d;&#x1f3fd;"},
+ {"", ":writing hand medium-dark skin tone:", "&#x270d;&#x1f3fe;"},
+ {"", ":writing hand dark skin tone:", "&#x270d;&#x1f3ff;"},
+ {"", ":nail polish light skin tone:", "&#x1f485;&#x1f3fb;"},
+ {"", ":nail polish medium-light skin tone:", "&#x1f485;&#x1f3fc;"},
+ {"", ":nail polish medium skin tone:", "&#x1f485;&#x1f3fd;"},
+ {"", ":nail polish medium-dark skin tone:", "&#x1f485;&#x1f3fe;"},
+ {"", ":nail polish dark skin tone:", "&#x1f485;&#x1f3ff;"},
+ {"", ":selfie light skin tone:", "&#x1f933;&#x1f3fb;"},
+ {"", ":selfie medium-light skin tone:", "&#x1f933;&#x1f3fc;"},
+ {"", ":selfie medium skin tone:", "&#x1f933;&#x1f3fd;"},
+ {"", ":selfie medium-dark skin tone:", "&#x1f933;&#x1f3fe;"},
+ {"", ":selfie dark skin tone:", "&#x1f933;&#x1f3ff;"},
+ {"", ":flexed biceps light skin tone:", "&#x1f4aa;&#x1f3fb;"},
+ {"", ":flexed biceps medium-light skin tone:", "&#x1f4aa;&#x1f3fc;"},
+ {"", ":flexed biceps medium skin tone:", "&#x1f4aa;&#x1f3fd;"},
+ {"", ":flexed biceps medium-dark skin tone:", "&#x1f4aa;&#x1f3fe;"},
+ {"", ":flexed biceps dark skin tone:", "&#x1f4aa;&#x1f3ff;"},
+ {"", ":leg light skin tone:", "&#x1f9b5;&#x1f3fb;"},
+ {"", ":leg medium-light skin tone:", "&#x1f9b5;&#x1f3fc;"},
+ {"", ":leg medium skin tone:", "&#x1f9b5;&#x1f3fd;"},
+ {"", ":leg medium-dark skin tone:", "&#x1f9b5;&#x1f3fe;"},
+ {"", ":leg dark skin tone:", "&#x1f9b5;&#x1f3ff;"},
+ {"", ":foot light skin tone:", "&#x1f9b6;&#x1f3fb;"},
+ {"", ":foot medium-light skin tone:", "&#x1f9b6;&#x1f3fc;"},
+ {"", ":foot medium skin tone:", "&#x1f9b6;&#x1f3fd;"},
+ {"", ":foot medium-dark skin tone:", "&#x1f9b6;&#x1f3fe;"},
+ {"", ":foot dark skin tone:", "&#x1f9b6;&#x1f3ff;"},
+ {"", ":ear light skin tone:", "&#x1f442;&#x1f3fb;"},
+ {"", ":ear medium-light skin tone:", "&#x1f442;&#x1f3fc;"},
+ {"", ":ear medium skin tone:", "&#x1f442;&#x1f3fd;"},
+ {"", ":ear medium-dark skin tone:", "&#x1f442;&#x1f3fe;"},
+ {"", ":ear dark skin tone:", "&#x1f442;&#x1f3ff;"},
+ {"", ":nose light skin tone:", "&#x1f443;&#x1f3fb;"},
+ {"", ":nose medium-light skin tone:", "&#x1f443;&#x1f3fc;"},
+ {"", ":nose medium skin tone:", "&#x1f443;&#x1f3fd;"},
+ {"", ":nose medium-dark skin tone:", "&#x1f443;&#x1f3fe;"},
+ {"", ":nose dark skin tone:", "&#x1f443;&#x1f3ff;"},
+ {"", ":baby light skin tone:", "&#x1f476;&#x1f3fb;"},
+ {"", ":baby medium-light skin tone:", "&#x1f476;&#x1f3fc;"},
+ {"", ":baby medium skin tone:", "&#x1f476;&#x1f3fd;"},
+ {"", ":baby medium-dark skin tone:", "&#x1f476;&#x1f3fe;"},
+ {"", ":baby dark skin tone:", "&#x1f476;&#x1f3ff;"},
+ {"", ":child light skin tone:", "&#x1f9d2;&#x1f3fb;"},
+ {"", ":child medium-light skin tone:", "&#x1f9d2;&#x1f3fc;"},
+ {"", ":child medium skin tone:", "&#x1f9d2;&#x1f3fd;"},
+ {"", ":child medium-dark skin tone:", "&#x1f9d2;&#x1f3fe;"},
+ {"", ":child dark skin tone:", "&#x1f9d2;&#x1f3ff;"},
+ {"", ":boy light skin tone:", "&#x1f466;&#x1f3fb;"},
+ {"", ":boy medium-light skin tone:", "&#x1f466;&#x1f3fc;"},
+ {"", ":boy medium skin tone:", "&#x1f466;&#x1f3fd;"},
+ {"", ":boy medium-dark skin tone:", "&#x1f466;&#x1f3fe;"},
+ {"", ":boy dark skin tone:", "&#x1f466;&#x1f3ff;"},
+ {"", ":girl light skin tone:", "&#x1f467;&#x1f3fb;"},
+ {"", ":girl medium-light skin tone:", "&#x1f467;&#x1f3fc;"},
+ {"", ":girl medium skin tone:", "&#x1f467;&#x1f3fd;"},
+ {"", ":girl medium-dark skin tone:", "&#x1f467;&#x1f3fe;"},
+ {"", ":girl dark skin tone:", "&#x1f467;&#x1f3ff;"},
+ {"", ":person light skin tone:", "&#x1f9d1;&#x1f3fb;"},
+ {"", ":person medium-light skin tone:", "&#x1f9d1;&#x1f3fc;"},
+ {"", ":person medium skin tone:", "&#x1f9d1;&#x1f3fd;"},
+ {"", ":person medium-dark skin tone:", "&#x1f9d1;&#x1f3fe;"},
+ {"", ":person dark skin tone:", "&#x1f9d1;&#x1f3ff;"},
+ {"", ":person light skin tone, blond hair:", "&#x1f471;&#x1f3fb;"},
+ {"", ":person medium-light skin tone, blond hair:", "&#x1f471;&#x1f3fc;"},
+ {"", ":person medium skin tone, blond hair:", "&#x1f471;&#x1f3fd;"},
+ {"", ":person medium-dark skin tone, blond hair:", "&#x1f471;&#x1f3fe;"},
+ {"", ":person dark skin tone, blond hair:", "&#x1f471;&#x1f3ff;"},
+ {"", ":man light skin tone:", "&#x1f468;&#x1f3fb;"},
+ {"", ":man medium-light skin tone:", "&#x1f468;&#x1f3fc;"},
+ {"", ":man medium skin tone:", "&#x1f468;&#x1f3fd;"},
+ {"", ":man medium-dark skin tone:", "&#x1f468;&#x1f3fe;"},
+ {"", ":man dark skin tone:", "&#x1f468;&#x1f3ff;"},
+ {"", ":man light skin tone, blond hair:", "&#x1f471;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man medium-light skin tone, blond hair:", "&#x1f471;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man medium skin tone, blond hair:", "&#x1f471;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man medium-dark skin tone, blond hair:", "&#x1f471;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man dark skin tone, blond hair:", "&#x1f471;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man light skin tone, red hair:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f9b0;"},
+ {"", ":man medium-light skin tone, red hair:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f9b0;"},
+ {"", ":man medium skin tone, red hair:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f9b0;"},
+ {"", ":man medium-dark skin tone, red hair:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f9b0;"},
+ {"", ":man dark skin tone, red hair:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f9b0;"},
+ {"", ":man light skin tone, curly hair:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f9b1;"},
+ {"", ":man medium-light skin tone, curly hair:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f9b1;"},
+ {"", ":man medium skin tone, curly hair:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f9b1;"},
+ {"", ":man medium-dark skin tone, curly hair:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f9b1;"},
+ {"", ":man dark skin tone, curly hair:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f9b1;"},
+ {"", ":man light skin tone, white hair:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f9b3;"},
+ {"", ":man medium-light skin tone, white hair:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f9b3;"},
+ {"", ":man medium skin tone, white hair:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f9b3;"},
+ {"", ":man medium-dark skin tone, white hair:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f9b3;"},
+ {"", ":man dark skin tone, white hair:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f9b3;"},
+ {"", ":man light skin tone, bald:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f9b2;"},
+ {"", ":man medium-light skin tone, bald:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f9b2;"},
+ {"", ":man medium skin tone, bald:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f9b2;"},
+ {"", ":man medium-dark skin tone, bald:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f9b2;"},
+ {"", ":man dark skin tone, bald:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f9b2;"},
+ {"", ":man light skin tone, beard:", "&#x1f9d4;&#x1f3fb;"},
+ {"", ":man medium-light skin tone, beard:", "&#x1f9d4;&#x1f3fc;"},
+ {"", ":man medium skin tone, beard:", "&#x1f9d4;&#x1f3fd;"},
+ {"", ":man medium-dark skin tone, beard:", "&#x1f9d4;&#x1f3fe;"},
+ {"", ":man dark skin tone, beard:", "&#x1f9d4;&#x1f3ff;"},
+ {"", ":woman light skin tone:", "&#x1f469;&#x1f3fb;"},
+ {"", ":woman medium-light skin tone:", "&#x1f469;&#x1f3fc;"},
+ {"", ":woman medium skin tone:", "&#x1f469;&#x1f3fd;"},
+ {"", ":woman medium-dark skin tone:", "&#x1f469;&#x1f3fe;"},
+ {"", ":woman dark skin tone:", "&#x1f469;&#x1f3ff;"},
+ {"", ":woman light skin tone, blond hair:", "&#x1f471;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman medium-light skin tone, blond hair:", "&#x1f471;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman medium skin tone, blond hair:", "&#x1f471;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman medium-dark skin tone, blond hair:", "&#x1f471;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman dark skin tone, blond hair:", "&#x1f471;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman light skin tone, red hair:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f9b0;"},
+ {"", ":woman medium-light skin tone, red hair:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f9b0;"},
+ {"", ":woman medium skin tone, red hair:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f9b0;"},
+ {"", ":woman medium-dark skin tone, red hair:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f9b0;"},
+ {"", ":woman dark skin tone, red hair:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f9b0;"},
+ {"", ":woman light skin tone, curly hair:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f9b1;"},
+ {"", ":woman medium-light skin tone, curly hair:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f9b1;"},
+ {"", ":woman medium skin tone, curly hair:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f9b1;"},
+ {"", ":woman medium-dark skin tone, curly hair:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f9b1;"},
+ {"", ":woman dark skin tone, curly hair:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f9b1;"},
+ {"", ":woman light skin tone, white hair:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f9b3;"},
+ {"", ":woman medium-light skin tone, white hair:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f9b3;"},
+ {"", ":woman medium skin tone, white hair:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f9b3;"},
+ {"", ":woman medium-dark skin tone, white hair:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f9b3;"},
+ {"", ":woman dark skin tone, white hair:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f9b3;"},
+ {"", ":woman light skin tone, bald:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f9b2;"},
+ {"", ":woman medium-light skin tone, bald:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f9b2;"},
+ {"", ":woman medium skin tone, bald:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f9b2;"},
+ {"", ":woman medium-dark skin tone, bald:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f9b2;"},
+ {"", ":woman dark skin tone, bald:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f9b2;"},
+ {"", ":older person light skin tone:", "&#x1f9d3;&#x1f3fb;"},
+ {"", ":older person medium-light skin tone:", "&#x1f9d3;&#x1f3fc;"},
+ {"", ":older person medium skin tone:", "&#x1f9d3;&#x1f3fd;"},
+ {"", ":older person medium-dark skin tone:", "&#x1f9d3;&#x1f3fe;"},
+ {"", ":older person dark skin tone:", "&#x1f9d3;&#x1f3ff;"},
+ {"", ":old man light skin tone:", "&#x1f474;&#x1f3fb;"},
+ {"", ":old man medium-light skin tone:", "&#x1f474;&#x1f3fc;"},
+ {"", ":old man medium skin tone:", "&#x1f474;&#x1f3fd;"},
+ {"", ":old man medium-dark skin tone:", "&#x1f474;&#x1f3fe;"},
+ {"", ":old man dark skin tone:", "&#x1f474;&#x1f3ff;"},
+ {"", ":old woman light skin tone:", "&#x1f475;&#x1f3fb;"},
+ {"", ":old woman medium-light skin tone:", "&#x1f475;&#x1f3fc;"},
+ {"", ":old woman medium skin tone:", "&#x1f475;&#x1f3fd;"},
+ {"", ":old woman medium-dark skin tone:", "&#x1f475;&#x1f3fe;"},
+ {"", ":old woman dark skin tone:", "&#x1f475;&#x1f3ff;"},
+ {"", ":person frowning light skin tone:", "&#x1f64d;&#x1f3fb;"},
+ {"", ":person frowning medium-light skin tone:", "&#x1f64d;&#x1f3fc;"},
+ {"", ":person frowning medium skin tone:", "&#x1f64d;&#x1f3fd;"},
+ {"", ":person frowning medium-dark skin tone:", "&#x1f64d;&#x1f3fe;"},
+ {"", ":person frowning dark skin tone:", "&#x1f64d;&#x1f3ff;"},
+ {"", ":man frowning light skin tone:", "&#x1f64d;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man frowning medium-light skin tone:", "&#x1f64d;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man frowning medium skin tone:", "&#x1f64d;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man frowning medium-dark skin tone:", "&#x1f64d;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man frowning dark skin tone:", "&#x1f64d;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman frowning light skin tone:", "&#x1f64d;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman frowning medium-light skin tone:", "&#x1f64d;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman frowning medium skin tone:", "&#x1f64d;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman frowning medium-dark skin tone:", "&#x1f64d;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman frowning dark skin tone:", "&#x1f64d;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person pouting light skin tone:", "&#x1f64e;&#x1f3fb;"},
+ {"", ":person pouting medium-light skin tone:", "&#x1f64e;&#x1f3fc;"},
+ {"", ":person pouting medium skin tone:", "&#x1f64e;&#x1f3fd;"},
+ {"", ":person pouting medium-dark skin tone:", "&#x1f64e;&#x1f3fe;"},
+ {"", ":person pouting dark skin tone:", "&#x1f64e;&#x1f3ff;"},
+ {"", ":man pouting light skin tone:", "&#x1f64e;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man pouting medium-light skin tone:", "&#x1f64e;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man pouting medium skin tone:", "&#x1f64e;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man pouting medium-dark skin tone:", "&#x1f64e;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man pouting dark skin tone:", "&#x1f64e;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman pouting light skin tone:", "&#x1f64e;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman pouting medium-light skin tone:", "&#x1f64e;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman pouting medium skin tone:", "&#x1f64e;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman pouting medium-dark skin tone:", "&#x1f64e;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman pouting dark skin tone:", "&#x1f64e;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person gesturing no light skin tone:", "&#x1f645;&#x1f3fb;"},
+ {"", ":person gesturing no medium-light skin tone:", "&#x1f645;&#x1f3fc;"},
+ {"", ":person gesturing no medium skin tone:", "&#x1f645;&#x1f3fd;"},
+ {"", ":person gesturing no medium-dark skin tone:", "&#x1f645;&#x1f3fe;"},
+ {"", ":person gesturing no dark skin tone:", "&#x1f645;&#x1f3ff;"},
+ {"", ":man gesturing no light skin tone:", "&#x1f645;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing no medium-light skin tone:", "&#x1f645;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing no medium skin tone:", "&#x1f645;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing no medium-dark skin tone:", "&#x1f645;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing no dark skin tone:", "&#x1f645;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman gesturing no light skin tone:", "&#x1f645;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing no medium-light skin tone:", "&#x1f645;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing no medium skin tone:", "&#x1f645;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing no medium-dark skin tone:", "&#x1f645;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing no dark skin tone:", "&#x1f645;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person gesturing ok light skin tone:", "&#x1f646;&#x1f3fb;"},
+ {"", ":person gesturing ok medium-light skin tone:", "&#x1f646;&#x1f3fc;"},
+ {"", ":person gesturing ok medium skin tone:", "&#x1f646;&#x1f3fd;"},
+ {"", ":person gesturing ok medium-dark skin tone:", "&#x1f646;&#x1f3fe;"},
+ {"", ":person gesturing ok dark skin tone:", "&#x1f646;&#x1f3ff;"},
+ {"", ":man gesturing ok light skin tone:", "&#x1f646;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing ok medium-light skin tone:", "&#x1f646;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing ok medium skin tone:", "&#x1f646;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing ok medium-dark skin tone:", "&#x1f646;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man gesturing ok dark skin tone:", "&#x1f646;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman gesturing ok light skin tone:", "&#x1f646;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing ok medium-light skin tone:", "&#x1f646;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing ok medium skin tone:", "&#x1f646;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing ok medium-dark skin tone:", "&#x1f646;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman gesturing ok dark skin tone:", "&#x1f646;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person tipping hand light skin tone:", "&#x1f481;&#x1f3fb;"},
+ {"", ":person tipping hand medium-light skin tone:", "&#x1f481;&#x1f3fc;"},
+ {"", ":person tipping hand medium skin tone:", "&#x1f481;&#x1f3fd;"},
+ {"", ":person tipping hand medium-dark skin tone:", "&#x1f481;&#x1f3fe;"},
+ {"", ":person tipping hand dark skin tone:", "&#x1f481;&#x1f3ff;"},
+ {"", ":man tipping hand light skin tone:", "&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man tipping hand medium-light skin tone:", "&#x1f481;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man tipping hand medium skin tone:", "&#x1f481;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man tipping hand medium-dark skin tone:", "&#x1f481;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man tipping hand dark skin tone:", "&#x1f481;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman tipping hand light skin tone:", "&#x1f481;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman tipping hand medium-light skin tone:", "&#x1f481;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman tipping hand medium skin tone:", "&#x1f481;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman tipping hand medium-dark skin tone:", "&#x1f481;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman tipping hand dark skin tone:", "&#x1f481;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person raising hand light skin tone:", "&#x1f64b;&#x1f3fb;"},
+ {"", ":person raising hand medium-light skin tone:", "&#x1f64b;&#x1f3fc;"},
+ {"", ":person raising hand medium skin tone:", "&#x1f64b;&#x1f3fd;"},
+ {"", ":person raising hand medium-dark skin tone:", "&#x1f64b;&#x1f3fe;"},
+ {"", ":person raising hand dark skin tone:", "&#x1f64b;&#x1f3ff;"},
+ {"", ":man raising hand light skin tone:", "&#x1f64b;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man raising hand medium-light skin tone:", "&#x1f64b;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man raising hand medium skin tone:", "&#x1f64b;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man raising hand medium-dark skin tone:", "&#x1f64b;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man raising hand dark skin tone:", "&#x1f64b;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman raising hand light skin tone:", "&#x1f64b;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman raising hand medium-light skin tone:", "&#x1f64b;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman raising hand medium skin tone:", "&#x1f64b;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman raising hand medium-dark skin tone:", "&#x1f64b;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman raising hand dark skin tone:", "&#x1f64b;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person bowing light skin tone:", "&#x1f647;&#x1f3fb;"},
+ {"", ":person bowing medium-light skin tone:", "&#x1f647;&#x1f3fc;"},
+ {"", ":person bowing medium skin tone:", "&#x1f647;&#x1f3fd;"},
+ {"", ":person bowing medium-dark skin tone:", "&#x1f647;&#x1f3fe;"},
+ {"", ":person bowing dark skin tone:", "&#x1f647;&#x1f3ff;"},
+ {"", ":man bowing light skin tone:", "&#x1f647;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bowing medium-light skin tone:", "&#x1f647;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bowing medium skin tone:", "&#x1f647;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bowing medium-dark skin tone:", "&#x1f647;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bowing dark skin tone:", "&#x1f647;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman bowing light skin tone:", "&#x1f647;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bowing medium-light skin tone:", "&#x1f647;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bowing medium skin tone:", "&#x1f647;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bowing medium-dark skin tone:", "&#x1f647;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bowing dark skin tone:", "&#x1f647;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person facepalming light skin tone:", "&#x1f926;&#x1f3fb;"},
+ {"", ":person facepalming medium-light skin tone:", "&#x1f926;&#x1f3fc;"},
+ {"", ":person facepalming medium skin tone:", "&#x1f926;&#x1f3fd;"},
+ {"", ":person facepalming medium-dark skin tone:", "&#x1f926;&#x1f3fe;"},
+ {"", ":person facepalming dark skin tone:", "&#x1f926;&#x1f3ff;"},
+ {"", ":man facepalming light skin tone:", "&#x1f926;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man facepalming medium-light skin tone:", "&#x1f926;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man facepalming medium skin tone:", "&#x1f926;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man facepalming medium-dark skin tone:", "&#x1f926;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man facepalming dark skin tone:", "&#x1f926;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman facepalming light skin tone:", "&#x1f926;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman facepalming medium-light skin tone:", "&#x1f926;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman facepalming medium skin tone:", "&#x1f926;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman facepalming medium-dark skin tone:", "&#x1f926;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman facepalming dark skin tone:", "&#x1f926;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person shrugging light skin tone:", "&#x1f937;&#x1f3fb;"},
+ {"", ":person shrugging medium-light skin tone:", "&#x1f937;&#x1f3fc;"},
+ {"", ":person shrugging medium skin tone:", "&#x1f937;&#x1f3fd;"},
+ {"", ":person shrugging medium-dark skin tone:", "&#x1f937;&#x1f3fe;"},
+ {"", ":person shrugging dark skin tone:", "&#x1f937;&#x1f3ff;"},
+ {"", ":man shrugging light skin tone:", "&#x1f937;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man shrugging medium-light skin tone:", "&#x1f937;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man shrugging medium skin tone:", "&#x1f937;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man shrugging medium-dark skin tone:", "&#x1f937;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man shrugging dark skin tone:", "&#x1f937;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman shrugging light skin tone:", "&#x1f937;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman shrugging medium-light skin tone:", "&#x1f937;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman shrugging medium skin tone:", "&#x1f937;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman shrugging medium-dark skin tone:", "&#x1f937;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman shrugging dark skin tone:", "&#x1f937;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":man health worker light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":man health worker medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":man health worker medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":man health worker medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":man health worker dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":woman health worker light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":woman health worker medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":woman health worker medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":woman health worker medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":woman health worker dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x2695;&#xfe0f;"},
+ {"", ":man student light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f393;"},
+ {"", ":man student medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f393;"},
+ {"", ":man student medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f393;"},
+ {"", ":man student medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f393;"},
+ {"", ":man student dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f393;"},
+ {"", ":woman student light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f393;"},
+ {"", ":woman student medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f393;"},
+ {"", ":woman student medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f393;"},
+ {"", ":woman student medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f393;"},
+ {"", ":woman student dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f393;"},
+ {"", ":man teacher light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f3eb;"},
+ {"", ":man teacher medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f3eb;"},
+ {"", ":man teacher medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f3eb;"},
+ {"", ":man teacher medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f3eb;"},
+ {"", ":man teacher dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f3eb;"},
+ {"", ":woman teacher light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f3eb;"},
+ {"", ":woman teacher medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f3eb;"},
+ {"", ":woman teacher medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f3eb;"},
+ {"", ":woman teacher medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f3eb;"},
+ {"", ":woman teacher dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f3eb;"},
+ {"", ":man judge light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":man judge medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":man judge medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":man judge medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":man judge dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":woman judge light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":woman judge medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":woman judge medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":woman judge medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":woman judge dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x2696;&#xfe0f;"},
+ {"", ":man farmer light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f33e;"},
+ {"", ":man farmer medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f33e;"},
+ {"", ":man farmer medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f33e;"},
+ {"", ":man farmer medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f33e;"},
+ {"", ":man farmer dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f33e;"},
+ {"", ":woman farmer light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f33e;"},
+ {"", ":woman farmer medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f33e;"},
+ {"", ":woman farmer medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f33e;"},
+ {"", ":woman farmer medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f33e;"},
+ {"", ":woman farmer dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f33e;"},
+ {"", ":man cook light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f373;"},
+ {"", ":man cook medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f373;"},
+ {"", ":man cook medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f373;"},
+ {"", ":man cook medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f373;"},
+ {"", ":man cook dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f373;"},
+ {"", ":woman cook light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f373;"},
+ {"", ":woman cook medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f373;"},
+ {"", ":woman cook medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f373;"},
+ {"", ":woman cook medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f373;"},
+ {"", ":woman cook dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f373;"},
+ {"", ":man mechanic light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f527;"},
+ {"", ":man mechanic medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f527;"},
+ {"", ":man mechanic medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f527;"},
+ {"", ":man mechanic medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f527;"},
+ {"", ":man mechanic dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f527;"},
+ {"", ":woman mechanic light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f527;"},
+ {"", ":woman mechanic medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f527;"},
+ {"", ":woman mechanic medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f527;"},
+ {"", ":woman mechanic medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f527;"},
+ {"", ":woman mechanic dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f527;"},
+ {"", ":man factory worker light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f3ed;"},
+ {"", ":man factory worker medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f3ed;"},
+ {"", ":man factory worker medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f3ed;"},
+ {"", ":man factory worker medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f3ed;"},
+ {"", ":man factory worker dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f3ed;"},
+ {"", ":woman factory worker light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f3ed;"},
+ {"", ":woman factory worker medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f3ed;"},
+ {"", ":woman factory worker medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f3ed;"},
+ {"", ":woman factory worker medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f3ed;"},
+ {"", ":woman factory worker dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f3ed;"},
+ {"", ":man office worker light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f4bc;"},
+ {"", ":man office worker medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f4bc;"},
+ {"", ":man office worker medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f4bc;"},
+ {"", ":man office worker medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f4bc;"},
+ {"", ":man office worker dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f4bc;"},
+ {"", ":woman office worker light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f4bc;"},
+ {"", ":woman office worker medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f4bc;"},
+ {"", ":woman office worker medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f4bc;"},
+ {"", ":woman office worker medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f4bc;"},
+ {"", ":woman office worker dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f4bc;"},
+ {"", ":man scientist light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f52c;"},
+ {"", ":man scientist medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f52c;"},
+ {"", ":man scientist medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f52c;"},
+ {"", ":man scientist medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f52c;"},
+ {"", ":man scientist dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f52c;"},
+ {"", ":woman scientist light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f52c;"},
+ {"", ":woman scientist medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f52c;"},
+ {"", ":woman scientist medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f52c;"},
+ {"", ":woman scientist medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f52c;"},
+ {"", ":woman scientist dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f52c;"},
+ {"", ":man technologist light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f4bb;"},
+ {"", ":man technologist medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f4bb;"},
+ {"", ":man technologist medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f4bb;"},
+ {"", ":man technologist medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f4bb;"},
+ {"", ":man technologist dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f4bb;"},
+ {"", ":woman technologist light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f4bb;"},
+ {"", ":woman technologist medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f4bb;"},
+ {"", ":woman technologist medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f4bb;"},
+ {"", ":woman technologist medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f4bb;"},
+ {"", ":woman technologist dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f4bb;"},
+ {"", ":man singer light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f3a4;"},
+ {"", ":man singer medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f3a4;"},
+ {"", ":man singer medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f3a4;"},
+ {"", ":man singer medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f3a4;"},
+ {"", ":man singer dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f3a4;"},
+ {"", ":woman singer light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f3a4;"},
+ {"", ":woman singer medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f3a4;"},
+ {"", ":woman singer medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f3a4;"},
+ {"", ":woman singer medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f3a4;"},
+ {"", ":woman singer dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f3a4;"},
+ {"", ":man artist light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f3a8;"},
+ {"", ":man artist medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f3a8;"},
+ {"", ":man artist medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f3a8;"},
+ {"", ":man artist medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f3a8;"},
+ {"", ":man artist dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f3a8;"},
+ {"", ":woman artist light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f3a8;"},
+ {"", ":woman artist medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f3a8;"},
+ {"", ":woman artist medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f3a8;"},
+ {"", ":woman artist medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f3a8;"},
+ {"", ":woman artist dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f3a8;"},
+ {"", ":man pilot light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":man pilot medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":man pilot medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":man pilot medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":man pilot dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":woman pilot light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":woman pilot medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":woman pilot medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":woman pilot medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":woman pilot dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x2708;&#xfe0f;"},
+ {"", ":man astronaut light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f680;"},
+ {"", ":man astronaut medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f680;"},
+ {"", ":man astronaut medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f680;"},
+ {"", ":man astronaut medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f680;"},
+ {"", ":man astronaut dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f680;"},
+ {"", ":woman astronaut light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f680;"},
+ {"", ":woman astronaut medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f680;"},
+ {"", ":woman astronaut medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f680;"},
+ {"", ":woman astronaut medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f680;"},
+ {"", ":woman astronaut dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f680;"},
+ {"", ":man firefighter light skin tone:", "&#x1f468;&#x1f3fb;&#x200d;&#x1f692;"},
+ {"", ":man firefighter medium-light skin tone:", "&#x1f468;&#x1f3fc;&#x200d;&#x1f692;"},
+ {"", ":man firefighter medium skin tone:", "&#x1f468;&#x1f3fd;&#x200d;&#x1f692;"},
+ {"", ":man firefighter medium-dark skin tone:", "&#x1f468;&#x1f3fe;&#x200d;&#x1f692;"},
+ {"", ":man firefighter dark skin tone:", "&#x1f468;&#x1f3ff;&#x200d;&#x1f692;"},
+ {"", ":woman firefighter light skin tone:", "&#x1f469;&#x1f3fb;&#x200d;&#x1f692;"},
+ {"", ":woman firefighter medium-light skin tone:", "&#x1f469;&#x1f3fc;&#x200d;&#x1f692;"},
+ {"", ":woman firefighter medium skin tone:", "&#x1f469;&#x1f3fd;&#x200d;&#x1f692;"},
+ {"", ":woman firefighter medium-dark skin tone:", "&#x1f469;&#x1f3fe;&#x200d;&#x1f692;"},
+ {"", ":woman firefighter dark skin tone:", "&#x1f469;&#x1f3ff;&#x200d;&#x1f692;"},
+ {"", ":police officer light skin tone:", "&#x1f46e;&#x1f3fb;"},
+ {"", ":police officer medium-light skin tone:", "&#x1f46e;&#x1f3fc;"},
+ {"", ":police officer medium skin tone:", "&#x1f46e;&#x1f3fd;"},
+ {"", ":police officer medium-dark skin tone:", "&#x1f46e;&#x1f3fe;"},
+ {"", ":police officer dark skin tone:", "&#x1f46e;&#x1f3ff;"},
+ {"", ":man police officer light skin tone:", "&#x1f46e;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man police officer medium-light skin tone:", "&#x1f46e;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man police officer medium skin tone:", "&#x1f46e;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man police officer medium-dark skin tone:", "&#x1f46e;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man police officer dark skin tone:", "&#x1f46e;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman police officer light skin tone:", "&#x1f46e;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman police officer medium-light skin tone:", "&#x1f46e;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman police officer medium skin tone:", "&#x1f46e;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman police officer medium-dark skin tone:", "&#x1f46e;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman police officer dark skin tone:", "&#x1f46e;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":detective light skin tone:", "&#x1f575;&#x1f3fb;"},
+ {"", ":detective medium-light skin tone:", "&#x1f575;&#x1f3fc;"},
+ {"", ":detective medium skin tone:", "&#x1f575;&#x1f3fd;"},
+ {"", ":detective medium-dark skin tone:", "&#x1f575;&#x1f3fe;"},
+ {"", ":detective dark skin tone:", "&#x1f575;&#x1f3ff;"},
+ {"", ":man detective light skin tone:", "&#x1f575;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man detective medium-light skin tone:", "&#x1f575;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man detective medium skin tone:", "&#x1f575;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man detective medium-dark skin tone:", "&#x1f575;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man detective dark skin tone:", "&#x1f575;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman detective light skin tone:", "&#x1f575;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman detective medium-light skin tone:", "&#x1f575;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman detective medium skin tone:", "&#x1f575;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman detective medium-dark skin tone:", "&#x1f575;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman detective dark skin tone:", "&#x1f575;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":guard light skin tone:", "&#x1f482;&#x1f3fb;"},
+ {"", ":guard medium-light skin tone:", "&#x1f482;&#x1f3fc;"},
+ {"", ":guard medium skin tone:", "&#x1f482;&#x1f3fd;"},
+ {"", ":guard medium-dark skin tone:", "&#x1f482;&#x1f3fe;"},
+ {"", ":guard dark skin tone:", "&#x1f482;&#x1f3ff;"},
+ {"", ":man guard light skin tone:", "&#x1f482;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man guard medium-light skin tone:", "&#x1f482;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man guard medium skin tone:", "&#x1f482;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man guard medium-dark skin tone:", "&#x1f482;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man guard dark skin tone:", "&#x1f482;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman guard light skin tone:", "&#x1f482;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman guard medium-light skin tone:", "&#x1f482;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman guard medium skin tone:", "&#x1f482;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman guard medium-dark skin tone:", "&#x1f482;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman guard dark skin tone:", "&#x1f482;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":construction worker light skin tone:", "&#x1f477;&#x1f3fb;"},
+ {"", ":construction worker medium-light skin tone:", "&#x1f477;&#x1f3fc;"},
+ {"", ":construction worker medium skin tone:", "&#x1f477;&#x1f3fd;"},
+ {"", ":construction worker medium-dark skin tone:", "&#x1f477;&#x1f3fe;"},
+ {"", ":construction worker dark skin tone:", "&#x1f477;&#x1f3ff;"},
+ {"", ":man construction worker light skin tone:", "&#x1f477;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man construction worker medium-light skin tone:", "&#x1f477;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man construction worker medium skin tone:", "&#x1f477;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man construction worker medium-dark skin tone:", "&#x1f477;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man construction worker dark skin tone:", "&#x1f477;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman construction worker light skin tone:", "&#x1f477;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman construction worker medium-light skin tone:", "&#x1f477;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman construction worker medium skin tone:", "&#x1f477;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman construction worker medium-dark skin tone:", "&#x1f477;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman construction worker dark skin tone:", "&#x1f477;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":prince light skin tone:", "&#x1f934;&#x1f3fb;"},
+ {"", ":prince medium-light skin tone:", "&#x1f934;&#x1f3fc;"},
+ {"", ":prince medium skin tone:", "&#x1f934;&#x1f3fd;"},
+ {"", ":prince medium-dark skin tone:", "&#x1f934;&#x1f3fe;"},
+ {"", ":prince dark skin tone:", "&#x1f934;&#x1f3ff;"},
+ {"", ":princess light skin tone:", "&#x1f478;&#x1f3fb;"},
+ {"", ":princess medium-light skin tone:", "&#x1f478;&#x1f3fc;"},
+ {"", ":princess medium skin tone:", "&#x1f478;&#x1f3fd;"},
+ {"", ":princess medium-dark skin tone:", "&#x1f478;&#x1f3fe;"},
+ {"", ":princess dark skin tone:", "&#x1f478;&#x1f3ff;"},
+ {"", ":person wearing turban light skin tone:", "&#x1f473;&#x1f3fb;"},
+ {"", ":person wearing turban medium-light skin tone:", "&#x1f473;&#x1f3fc;"},
+ {"", ":person wearing turban medium skin tone:", "&#x1f473;&#x1f3fd;"},
+ {"", ":person wearing turban medium-dark skin tone:", "&#x1f473;&#x1f3fe;"},
+ {"", ":person wearing turban dark skin tone:", "&#x1f473;&#x1f3ff;"},
+ {"", ":man wearing turban light skin tone:", "&#x1f473;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man wearing turban medium-light skin tone:", "&#x1f473;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man wearing turban medium skin tone:", "&#x1f473;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man wearing turban medium-dark skin tone:", "&#x1f473;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man wearing turban dark skin tone:", "&#x1f473;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman wearing turban light skin tone:", "&#x1f473;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman wearing turban medium-light skin tone:", "&#x1f473;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman wearing turban medium skin tone:", "&#x1f473;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman wearing turban medium-dark skin tone:", "&#x1f473;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman wearing turban dark skin tone:", "&#x1f473;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":man with chinese cap light skin tone:", "&#x1f472;&#x1f3fb;"},
+ {"", ":man with chinese cap medium-light skin tone:", "&#x1f472;&#x1f3fc;"},
+ {"", ":man with chinese cap medium skin tone:", "&#x1f472;&#x1f3fd;"},
+ {"", ":man with chinese cap medium-dark skin tone:", "&#x1f472;&#x1f3fe;"},
+ {"", ":man with chinese cap dark skin tone:", "&#x1f472;&#x1f3ff;"},
+ {"", ":woman with headscarf light skin tone:", "&#x1f9d5;&#x1f3fb;"},
+ {"", ":woman with headscarf medium-light skin tone:", "&#x1f9d5;&#x1f3fc;"},
+ {"", ":woman with headscarf medium skin tone:", "&#x1f9d5;&#x1f3fd;"},
+ {"", ":woman with headscarf medium-dark skin tone:", "&#x1f9d5;&#x1f3fe;"},
+ {"", ":woman with headscarf dark skin tone:", "&#x1f9d5;&#x1f3ff;"},
+ {"", ":man in tuxedo light skin tone:", "&#x1f935;&#x1f3fb;"},
+ {"", ":man in tuxedo medium-light skin tone:", "&#x1f935;&#x1f3fc;"},
+ {"", ":man in tuxedo medium skin tone:", "&#x1f935;&#x1f3fd;"},
+ {"", ":man in tuxedo medium-dark skin tone:", "&#x1f935;&#x1f3fe;"},
+ {"", ":man in tuxedo dark skin tone:", "&#x1f935;&#x1f3ff;"},
+ {"", ":bride with veil light skin tone:", "&#x1f470;&#x1f3fb;"},
+ {"", ":bride with veil medium-light skin tone:", "&#x1f470;&#x1f3fc;"},
+ {"", ":bride with veil medium skin tone:", "&#x1f470;&#x1f3fd;"},
+ {"", ":bride with veil medium-dark skin tone:", "&#x1f470;&#x1f3fe;"},
+ {"", ":bride with veil dark skin tone:", "&#x1f470;&#x1f3ff;"},
+ {"", ":pregnant woman light skin tone:", "&#x1f930;&#x1f3fb;"},
+ {"", ":pregnant woman medium-light skin tone:", "&#x1f930;&#x1f3fc;"},
+ {"", ":pregnant woman medium skin tone:", "&#x1f930;&#x1f3fd;"},
+ {"", ":pregnant woman medium-dark skin tone:", "&#x1f930;&#x1f3fe;"},
+ {"", ":pregnant woman dark skin tone:", "&#x1f930;&#x1f3ff;"},
+ {"", ":breast-feeding light skin tone:", "&#x1f931;&#x1f3fb;"},
+ {"", ":breast-feeding medium-light skin tone:", "&#x1f931;&#x1f3fc;"},
+ {"", ":breast-feeding medium skin tone:", "&#x1f931;&#x1f3fd;"},
+ {"", ":breast-feeding medium-dark skin tone:", "&#x1f931;&#x1f3fe;"},
+ {"", ":breast-feeding dark skin tone:", "&#x1f931;&#x1f3ff;"},
+ {"", ":baby angel light skin tone:", "&#x1f47c;&#x1f3fb;"},
+ {"", ":baby angel medium-light skin tone:", "&#x1f47c;&#x1f3fc;"},
+ {"", ":baby angel medium skin tone:", "&#x1f47c;&#x1f3fd;"},
+ {"", ":baby angel medium-dark skin tone:", "&#x1f47c;&#x1f3fe;"},
+ {"", ":baby angel dark skin tone:", "&#x1f47c;&#x1f3ff;"},
+ {"", ":santa claus light skin tone:", "&#x1f385;&#x1f3fb;"},
+ {"", ":santa claus medium-light skin tone:", "&#x1f385;&#x1f3fc;"},
+ {"", ":santa claus medium skin tone:", "&#x1f385;&#x1f3fd;"},
+ {"", ":santa claus medium-dark skin tone:", "&#x1f385;&#x1f3fe;"},
+ {"", ":santa claus dark skin tone:", "&#x1f385;&#x1f3ff;"},
+ {"", ":mrs. claus light skin tone:", "&#x1f936;&#x1f3fb;"},
+ {"", ":mrs. claus medium-light skin tone:", "&#x1f936;&#x1f3fc;"},
+ {"", ":mrs. claus medium skin tone:", "&#x1f936;&#x1f3fd;"},
+ {"", ":mrs. claus medium-dark skin tone:", "&#x1f936;&#x1f3fe;"},
+ {"", ":mrs. claus dark skin tone:", "&#x1f936;&#x1f3ff;"},
+ {"", ":superhero light skin tone:", "&#x1f9b8;&#x1f3fb;"},
+ {"", ":superhero medium-light skin tone:", "&#x1f9b8;&#x1f3fc;"},
+ {"", ":superhero medium skin tone:", "&#x1f9b8;&#x1f3fd;"},
+ {"", ":superhero medium-dark skin tone:", "&#x1f9b8;&#x1f3fe;"},
+ {"", ":superhero dark skin tone:", "&#x1f9b8;&#x1f3ff;"},
+ {"", ":man superhero light skin tone:", "&#x1f9b8;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man superhero medium-light skin tone:", "&#x1f9b8;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man superhero medium skin tone:", "&#x1f9b8;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man superhero medium-dark skin tone:", "&#x1f9b8;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man superhero dark skin tone:", "&#x1f9b8;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman superhero light skin tone:", "&#x1f9b8;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman superhero medium-light skin tone:", "&#x1f9b8;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman superhero medium skin tone:", "&#x1f9b8;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman superhero medium-dark skin tone:", "&#x1f9b8;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman superhero dark skin tone:", "&#x1f9b8;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":supervillain light skin tone:", "&#x1f9b9;&#x1f3fb;"},
+ {"", ":supervillain medium-light skin tone:", "&#x1f9b9;&#x1f3fc;"},
+ {"", ":supervillain medium skin tone:", "&#x1f9b9;&#x1f3fd;"},
+ {"", ":supervillain medium-dark skin tone:", "&#x1f9b9;&#x1f3fe;"},
+ {"", ":supervillain dark skin tone:", "&#x1f9b9;&#x1f3ff;"},
+ {"", ":man supervillain light skin tone:", "&#x1f9b9;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man supervillain medium-light skin tone:", "&#x1f9b9;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man supervillain medium skin tone:", "&#x1f9b9;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man supervillain medium-dark skin tone:", "&#x1f9b9;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man supervillain dark skin tone:", "&#x1f9b9;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman supervillain light skin tone:", "&#x1f9b9;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman supervillain medium-light skin tone:", "&#x1f9b9;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman supervillain medium skin tone:", "&#x1f9b9;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman supervillain medium-dark skin tone:", "&#x1f9b9;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman supervillain dark skin tone:", "&#x1f9b9;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":mage light skin tone:", "&#x1f9d9;&#x1f3fb;"},
+ {"", ":mage medium-light skin tone:", "&#x1f9d9;&#x1f3fc;"},
+ {"", ":mage medium skin tone:", "&#x1f9d9;&#x1f3fd;"},
+ {"", ":mage medium-dark skin tone:", "&#x1f9d9;&#x1f3fe;"},
+ {"", ":mage dark skin tone:", "&#x1f9d9;&#x1f3ff;"},
+ {"", ":man mage light skin tone:", "&#x1f9d9;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mage medium-light skin tone:", "&#x1f9d9;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mage medium skin tone:", "&#x1f9d9;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mage medium-dark skin tone:", "&#x1f9d9;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mage dark skin tone:", "&#x1f9d9;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman mage light skin tone:", "&#x1f9d9;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mage medium-light skin tone:", "&#x1f9d9;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mage medium skin tone:", "&#x1f9d9;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mage medium-dark skin tone:", "&#x1f9d9;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mage dark skin tone:", "&#x1f9d9;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":fairy light skin tone:", "&#x1f9da;&#x1f3fb;"},
+ {"", ":fairy medium-light skin tone:", "&#x1f9da;&#x1f3fc;"},
+ {"", ":fairy medium skin tone:", "&#x1f9da;&#x1f3fd;"},
+ {"", ":fairy medium-dark skin tone:", "&#x1f9da;&#x1f3fe;"},
+ {"", ":fairy dark skin tone:", "&#x1f9da;&#x1f3ff;"},
+ {"", ":man fairy light skin tone:", "&#x1f9da;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man fairy medium-light skin tone:", "&#x1f9da;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man fairy medium skin tone:", "&#x1f9da;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man fairy medium-dark skin tone:", "&#x1f9da;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man fairy dark skin tone:", "&#x1f9da;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman fairy light skin tone:", "&#x1f9da;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman fairy medium-light skin tone:", "&#x1f9da;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman fairy medium skin tone:", "&#x1f9da;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman fairy medium-dark skin tone:", "&#x1f9da;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman fairy dark skin tone:", "&#x1f9da;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":vampire light skin tone:", "&#x1f9db;&#x1f3fb;"},
+ {"", ":vampire medium-light skin tone:", "&#x1f9db;&#x1f3fc;"},
+ {"", ":vampire medium skin tone:", "&#x1f9db;&#x1f3fd;"},
+ {"", ":vampire medium-dark skin tone:", "&#x1f9db;&#x1f3fe;"},
+ {"", ":vampire dark skin tone:", "&#x1f9db;&#x1f3ff;"},
+ {"", ":man vampire light skin tone:", "&#x1f9db;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man vampire medium-light skin tone:", "&#x1f9db;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man vampire medium skin tone:", "&#x1f9db;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man vampire medium-dark skin tone:", "&#x1f9db;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man vampire dark skin tone:", "&#x1f9db;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman vampire light skin tone:", "&#x1f9db;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman vampire medium-light skin tone:", "&#x1f9db;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman vampire medium skin tone:", "&#x1f9db;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman vampire medium-dark skin tone:", "&#x1f9db;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman vampire dark skin tone:", "&#x1f9db;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":merperson light skin tone:", "&#x1f9dc;&#x1f3fb;"},
+ {"", ":merperson medium-light skin tone:", "&#x1f9dc;&#x1f3fc;"},
+ {"", ":merperson medium skin tone:", "&#x1f9dc;&#x1f3fd;"},
+ {"", ":merperson medium-dark skin tone:", "&#x1f9dc;&#x1f3fe;"},
+ {"", ":merperson dark skin tone:", "&#x1f9dc;&#x1f3ff;"},
+ {"", ":merman light skin tone:", "&#x1f9dc;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":merman medium-light skin tone:", "&#x1f9dc;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":merman medium skin tone:", "&#x1f9dc;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":merman medium-dark skin tone:", "&#x1f9dc;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":merman dark skin tone:", "&#x1f9dc;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":mermaid light skin tone:", "&#x1f9dc;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":mermaid medium-light skin tone:", "&#x1f9dc;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":mermaid medium skin tone:", "&#x1f9dc;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":mermaid medium-dark skin tone:", "&#x1f9dc;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":mermaid dark skin tone:", "&#x1f9dc;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":elf light skin tone:", "&#x1f9dd;&#x1f3fb;"},
+ {"", ":elf medium-light skin tone:", "&#x1f9dd;&#x1f3fc;"},
+ {"", ":elf medium skin tone:", "&#x1f9dd;&#x1f3fd;"},
+ {"", ":elf medium-dark skin tone:", "&#x1f9dd;&#x1f3fe;"},
+ {"", ":elf dark skin tone:", "&#x1f9dd;&#x1f3ff;"},
+ {"", ":man elf light skin tone:", "&#x1f9dd;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man elf medium-light skin tone:", "&#x1f9dd;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man elf medium skin tone:", "&#x1f9dd;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man elf medium-dark skin tone:", "&#x1f9dd;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man elf dark skin tone:", "&#x1f9dd;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman elf light skin tone:", "&#x1f9dd;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman elf medium-light skin tone:", "&#x1f9dd;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman elf medium skin tone:", "&#x1f9dd;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman elf medium-dark skin tone:", "&#x1f9dd;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman elf dark skin tone:", "&#x1f9dd;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person getting massage light skin tone:", "&#x1f486;&#x1f3fb;"},
+ {"", ":person getting massage medium-light skin tone:", "&#x1f486;&#x1f3fc;"},
+ {"", ":person getting massage medium skin tone:", "&#x1f486;&#x1f3fd;"},
+ {"", ":person getting massage medium-dark skin tone:", "&#x1f486;&#x1f3fe;"},
+ {"", ":person getting massage dark skin tone:", "&#x1f486;&#x1f3ff;"},
+ {"", ":man getting massage light skin tone:", "&#x1f486;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting massage medium-light skin tone:", "&#x1f486;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting massage medium skin tone:", "&#x1f486;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting massage medium-dark skin tone:", "&#x1f486;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting massage dark skin tone:", "&#x1f486;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman getting massage light skin tone:", "&#x1f486;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting massage medium-light skin tone:", "&#x1f486;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting massage medium skin tone:", "&#x1f486;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting massage medium-dark skin tone:", "&#x1f486;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting massage dark skin tone:", "&#x1f486;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person getting haircut light skin tone:", "&#x1f487;&#x1f3fb;"},
+ {"", ":person getting haircut medium-light skin tone:", "&#x1f487;&#x1f3fc;"},
+ {"", ":person getting haircut medium skin tone:", "&#x1f487;&#x1f3fd;"},
+ {"", ":person getting haircut medium-dark skin tone:", "&#x1f487;&#x1f3fe;"},
+ {"", ":person getting haircut dark skin tone:", "&#x1f487;&#x1f3ff;"},
+ {"", ":man getting haircut light skin tone:", "&#x1f487;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting haircut medium-light skin tone:", "&#x1f487;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting haircut medium skin tone:", "&#x1f487;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting haircut medium-dark skin tone:", "&#x1f487;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man getting haircut dark skin tone:", "&#x1f487;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman getting haircut light skin tone:", "&#x1f487;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting haircut medium-light skin tone:", "&#x1f487;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting haircut medium skin tone:", "&#x1f487;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting haircut medium-dark skin tone:", "&#x1f487;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman getting haircut dark skin tone:", "&#x1f487;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person walking light skin tone:", "&#x1f6b6;&#x1f3fb;"},
+ {"", ":person walking medium-light skin tone:", "&#x1f6b6;&#x1f3fc;"},
+ {"", ":person walking medium skin tone:", "&#x1f6b6;&#x1f3fd;"},
+ {"", ":person walking medium-dark skin tone:", "&#x1f6b6;&#x1f3fe;"},
+ {"", ":person walking dark skin tone:", "&#x1f6b6;&#x1f3ff;"},
+ {"", ":man walking light skin tone:", "&#x1f6b6;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man walking medium-light skin tone:", "&#x1f6b6;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man walking medium skin tone:", "&#x1f6b6;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man walking medium-dark skin tone:", "&#x1f6b6;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man walking dark skin tone:", "&#x1f6b6;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman walking light skin tone:", "&#x1f6b6;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman walking medium-light skin tone:", "&#x1f6b6;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman walking medium skin tone:", "&#x1f6b6;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman walking medium-dark skin tone:", "&#x1f6b6;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman walking dark skin tone:", "&#x1f6b6;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person running light skin tone:", "&#x1f3c3;&#x1f3fb;"},
+ {"", ":person running medium-light skin tone:", "&#x1f3c3;&#x1f3fc;"},
+ {"", ":person running medium skin tone:", "&#x1f3c3;&#x1f3fd;"},
+ {"", ":person running medium-dark skin tone:", "&#x1f3c3;&#x1f3fe;"},
+ {"", ":person running dark skin tone:", "&#x1f3c3;&#x1f3ff;"},
+ {"", ":man running light skin tone:", "&#x1f3c3;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man running medium-light skin tone:", "&#x1f3c3;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man running medium skin tone:", "&#x1f3c3;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man running medium-dark skin tone:", "&#x1f3c3;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man running dark skin tone:", "&#x1f3c3;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman running light skin tone:", "&#x1f3c3;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman running medium-light skin tone:", "&#x1f3c3;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman running medium skin tone:", "&#x1f3c3;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman running medium-dark skin tone:", "&#x1f3c3;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman running dark skin tone:", "&#x1f3c3;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman dancing light skin tone:", "&#x1f483;&#x1f3fb;"},
+ {"", ":woman dancing medium-light skin tone:", "&#x1f483;&#x1f3fc;"},
+ {"", ":woman dancing medium skin tone:", "&#x1f483;&#x1f3fd;"},
+ {"", ":woman dancing medium-dark skin tone:", "&#x1f483;&#x1f3fe;"},
+ {"", ":woman dancing dark skin tone:", "&#x1f483;&#x1f3ff;"},
+ {"", ":man dancing light skin tone:", "&#x1f57a;&#x1f3fb;"},
+ {"", ":man dancing medium-light skin tone:", "&#x1f57a;&#x1f3fc;"},
+ {"", ":man dancing medium skin tone:", "&#x1f57a;&#x1f3fd;"},
+ {"", ":man dancing medium-dark skin tone:", "&#x1f57a;&#x1f3fe;"},
+ {"", ":man dancing dark skin tone:", "&#x1f57a;&#x1f3ff;"},
+ {"", ":man in suit levitating light skin tone:", "&#x1f574;&#x1f3fb;"},
+ {"", ":man in suit levitating medium-light skin tone:", "&#x1f574;&#x1f3fc;"},
+ {"", ":man in suit levitating medium skin tone:", "&#x1f574;&#x1f3fd;"},
+ {"", ":man in suit levitating medium-dark skin tone:", "&#x1f574;&#x1f3fe;"},
+ {"", ":man in suit levitating dark skin tone:", "&#x1f574;&#x1f3ff;"},
+ {"", ":person in steamy room light skin tone:", "&#x1f9d6;&#x1f3fb;"},
+ {"", ":person in steamy room medium-light skin tone:", "&#x1f9d6;&#x1f3fc;"},
+ {"", ":person in steamy room medium skin tone:", "&#x1f9d6;&#x1f3fd;"},
+ {"", ":person in steamy room medium-dark skin tone:", "&#x1f9d6;&#x1f3fe;"},
+ {"", ":person in steamy room dark skin tone:", "&#x1f9d6;&#x1f3ff;"},
+ {"", ":man in steamy room light skin tone:", "&#x1f9d6;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in steamy room medium-light skin tone:", "&#x1f9d6;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in steamy room medium skin tone:", "&#x1f9d6;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in steamy room medium-dark skin tone:", "&#x1f9d6;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in steamy room dark skin tone:", "&#x1f9d6;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman in steamy room light skin tone:", "&#x1f9d6;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in steamy room medium-light skin tone:", "&#x1f9d6;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in steamy room medium skin tone:", "&#x1f9d6;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in steamy room medium-dark skin tone:", "&#x1f9d6;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in steamy room dark skin tone:", "&#x1f9d6;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person climbing light skin tone:", "&#x1f9d7;&#x1f3fb;"},
+ {"", ":person climbing medium-light skin tone:", "&#x1f9d7;&#x1f3fc;"},
+ {"", ":person climbing medium skin tone:", "&#x1f9d7;&#x1f3fd;"},
+ {"", ":person climbing medium-dark skin tone:", "&#x1f9d7;&#x1f3fe;"},
+ {"", ":person climbing dark skin tone:", "&#x1f9d7;&#x1f3ff;"},
+ {"", ":man climbing light skin tone:", "&#x1f9d7;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man climbing medium-light skin tone:", "&#x1f9d7;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man climbing medium skin tone:", "&#x1f9d7;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man climbing medium-dark skin tone:", "&#x1f9d7;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man climbing dark skin tone:", "&#x1f9d7;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman climbing light skin tone:", "&#x1f9d7;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman climbing medium-light skin tone:", "&#x1f9d7;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman climbing medium skin tone:", "&#x1f9d7;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman climbing medium-dark skin tone:", "&#x1f9d7;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman climbing dark skin tone:", "&#x1f9d7;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":horse racing light skin tone:", "&#x1f3c7;&#x1f3fb;"},
+ {"", ":horse racing medium-light skin tone:", "&#x1f3c7;&#x1f3fc;"},
+ {"", ":horse racing medium skin tone:", "&#x1f3c7;&#x1f3fd;"},
+ {"", ":horse racing medium-dark skin tone:", "&#x1f3c7;&#x1f3fe;"},
+ {"", ":horse racing dark skin tone:", "&#x1f3c7;&#x1f3ff;"},
+ {"", ":snowboarder light skin tone:", "&#x1f3c2;&#x1f3fb;"},
+ {"", ":snowboarder medium-light skin tone:", "&#x1f3c2;&#x1f3fc;"},
+ {"", ":snowboarder medium skin tone:", "&#x1f3c2;&#x1f3fd;"},
+ {"", ":snowboarder medium-dark skin tone:", "&#x1f3c2;&#x1f3fe;"},
+ {"", ":snowboarder dark skin tone:", "&#x1f3c2;&#x1f3ff;"},
+ {"", ":person golfing light skin tone:", "&#x1f3cc;&#x1f3fb;"},
+ {"", ":person golfing medium-light skin tone:", "&#x1f3cc;&#x1f3fc;"},
+ {"", ":person golfing medium skin tone:", "&#x1f3cc;&#x1f3fd;"},
+ {"", ":person golfing medium-dark skin tone:", "&#x1f3cc;&#x1f3fe;"},
+ {"", ":person golfing dark skin tone:", "&#x1f3cc;&#x1f3ff;"},
+ {"", ":man golfing light skin tone:", "&#x1f3cc;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man golfing medium-light skin tone:", "&#x1f3cc;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man golfing medium skin tone:", "&#x1f3cc;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man golfing medium-dark skin tone:", "&#x1f3cc;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man golfing dark skin tone:", "&#x1f3cc;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman golfing light skin tone:", "&#x1f3cc;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman golfing medium-light skin tone:", "&#x1f3cc;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman golfing medium skin tone:", "&#x1f3cc;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman golfing medium-dark skin tone:", "&#x1f3cc;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman golfing dark skin tone:", "&#x1f3cc;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person surfing light skin tone:", "&#x1f3c4;&#x1f3fb;"},
+ {"", ":person surfing medium-light skin tone:", "&#x1f3c4;&#x1f3fc;"},
+ {"", ":person surfing medium skin tone:", "&#x1f3c4;&#x1f3fd;"},
+ {"", ":person surfing medium-dark skin tone:", "&#x1f3c4;&#x1f3fe;"},
+ {"", ":person surfing dark skin tone:", "&#x1f3c4;&#x1f3ff;"},
+ {"", ":man surfing light skin tone:", "&#x1f3c4;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man surfing medium-light skin tone:", "&#x1f3c4;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man surfing medium skin tone:", "&#x1f3c4;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man surfing medium-dark skin tone:", "&#x1f3c4;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man surfing dark skin tone:", "&#x1f3c4;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman surfing light skin tone:", "&#x1f3c4;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman surfing medium-light skin tone:", "&#x1f3c4;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman surfing medium skin tone:", "&#x1f3c4;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman surfing medium-dark skin tone:", "&#x1f3c4;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman surfing dark skin tone:", "&#x1f3c4;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person rowing boat light skin tone:", "&#x1f6a3;&#x1f3fb;"},
+ {"", ":person rowing boat medium-light skin tone:", "&#x1f6a3;&#x1f3fc;"},
+ {"", ":person rowing boat medium skin tone:", "&#x1f6a3;&#x1f3fd;"},
+ {"", ":person rowing boat medium-dark skin tone:", "&#x1f6a3;&#x1f3fe;"},
+ {"", ":person rowing boat dark skin tone:", "&#x1f6a3;&#x1f3ff;"},
+ {"", ":man rowing boat light skin tone:", "&#x1f6a3;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man rowing boat medium-light skin tone:", "&#x1f6a3;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man rowing boat medium skin tone:", "&#x1f6a3;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man rowing boat medium-dark skin tone:", "&#x1f6a3;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man rowing boat dark skin tone:", "&#x1f6a3;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman rowing boat light skin tone:", "&#x1f6a3;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman rowing boat medium-light skin tone:", "&#x1f6a3;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman rowing boat medium skin tone:", "&#x1f6a3;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman rowing boat medium-dark skin tone:", "&#x1f6a3;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman rowing boat dark skin tone:", "&#x1f6a3;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person swimming light skin tone:", "&#x1f3ca;&#x1f3fb;"},
+ {"", ":person swimming medium-light skin tone:", "&#x1f3ca;&#x1f3fc;"},
+ {"", ":person swimming medium skin tone:", "&#x1f3ca;&#x1f3fd;"},
+ {"", ":person swimming medium-dark skin tone:", "&#x1f3ca;&#x1f3fe;"},
+ {"", ":person swimming dark skin tone:", "&#x1f3ca;&#x1f3ff;"},
+ {"", ":man swimming light skin tone:", "&#x1f3ca;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man swimming medium-light skin tone:", "&#x1f3ca;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man swimming medium skin tone:", "&#x1f3ca;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man swimming medium-dark skin tone:", "&#x1f3ca;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man swimming dark skin tone:", "&#x1f3ca;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman swimming light skin tone:", "&#x1f3ca;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman swimming medium-light skin tone:", "&#x1f3ca;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman swimming medium skin tone:", "&#x1f3ca;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman swimming medium-dark skin tone:", "&#x1f3ca;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman swimming dark skin tone:", "&#x1f3ca;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person bouncing ball light skin tone:", "&#x26f9;&#x1f3fb;"},
+ {"", ":person bouncing ball medium-light skin tone:", "&#x26f9;&#x1f3fc;"},
+ {"", ":person bouncing ball medium skin tone:", "&#x26f9;&#x1f3fd;"},
+ {"", ":person bouncing ball medium-dark skin tone:", "&#x26f9;&#x1f3fe;"},
+ {"", ":person bouncing ball dark skin tone:", "&#x26f9;&#x1f3ff;"},
+ {"", ":man bouncing ball light skin tone:", "&#x26f9;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bouncing ball medium-light skin tone:", "&#x26f9;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bouncing ball medium skin tone:", "&#x26f9;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bouncing ball medium-dark skin tone:", "&#x26f9;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man bouncing ball dark skin tone:", "&#x26f9;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman bouncing ball light skin tone:", "&#x26f9;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bouncing ball medium-light skin tone:", "&#x26f9;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bouncing ball medium skin tone:", "&#x26f9;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bouncing ball medium-dark skin tone:", "&#x26f9;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman bouncing ball dark skin tone:", "&#x26f9;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person lifting weights light skin tone:", "&#x1f3cb;&#x1f3fb;"},
+ {"", ":person lifting weights medium-light skin tone:", "&#x1f3cb;&#x1f3fc;"},
+ {"", ":person lifting weights medium skin tone:", "&#x1f3cb;&#x1f3fd;"},
+ {"", ":person lifting weights medium-dark skin tone:", "&#x1f3cb;&#x1f3fe;"},
+ {"", ":person lifting weights dark skin tone:", "&#x1f3cb;&#x1f3ff;"},
+ {"", ":man lifting weights light skin tone:", "&#x1f3cb;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man lifting weights medium-light skin tone:", "&#x1f3cb;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man lifting weights medium skin tone:", "&#x1f3cb;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man lifting weights medium-dark skin tone:", "&#x1f3cb;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man lifting weights dark skin tone:", "&#x1f3cb;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman lifting weights light skin tone:", "&#x1f3cb;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman lifting weights medium-light skin tone:", "&#x1f3cb;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman lifting weights medium skin tone:", "&#x1f3cb;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman lifting weights medium-dark skin tone:", "&#x1f3cb;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman lifting weights dark skin tone:", "&#x1f3cb;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person biking light skin tone:", "&#x1f6b4;&#x1f3fb;"},
+ {"", ":person biking medium-light skin tone:", "&#x1f6b4;&#x1f3fc;"},
+ {"", ":person biking medium skin tone:", "&#x1f6b4;&#x1f3fd;"},
+ {"", ":person biking medium-dark skin tone:", "&#x1f6b4;&#x1f3fe;"},
+ {"", ":person biking dark skin tone:", "&#x1f6b4;&#x1f3ff;"},
+ {"", ":man biking light skin tone:", "&#x1f6b4;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man biking medium-light skin tone:", "&#x1f6b4;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man biking medium skin tone:", "&#x1f6b4;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man biking medium-dark skin tone:", "&#x1f6b4;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man biking dark skin tone:", "&#x1f6b4;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman biking light skin tone:", "&#x1f6b4;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman biking medium-light skin tone:", "&#x1f6b4;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman biking medium skin tone:", "&#x1f6b4;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman biking medium-dark skin tone:", "&#x1f6b4;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman biking dark skin tone:", "&#x1f6b4;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person mountain biking light skin tone:", "&#x1f6b5;&#x1f3fb;"},
+ {"", ":person mountain biking medium-light skin tone:", "&#x1f6b5;&#x1f3fc;"},
+ {"", ":person mountain biking medium skin tone:", "&#x1f6b5;&#x1f3fd;"},
+ {"", ":person mountain biking medium-dark skin tone:", "&#x1f6b5;&#x1f3fe;"},
+ {"", ":person mountain biking dark skin tone:", "&#x1f6b5;&#x1f3ff;"},
+ {"", ":man mountain biking light skin tone:", "&#x1f6b5;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mountain biking medium-light skin tone:", "&#x1f6b5;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mountain biking medium skin tone:", "&#x1f6b5;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mountain biking medium-dark skin tone:", "&#x1f6b5;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man mountain biking dark skin tone:", "&#x1f6b5;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman mountain biking light skin tone:", "&#x1f6b5;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mountain biking medium-light skin tone:", "&#x1f6b5;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mountain biking medium skin tone:", "&#x1f6b5;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mountain biking medium-dark skin tone:", "&#x1f6b5;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman mountain biking dark skin tone:", "&#x1f6b5;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person cartwheeling light skin tone:", "&#x1f938;&#x1f3fb;"},
+ {"", ":person cartwheeling medium-light skin tone:", "&#x1f938;&#x1f3fc;"},
+ {"", ":person cartwheeling medium skin tone:", "&#x1f938;&#x1f3fd;"},
+ {"", ":person cartwheeling medium-dark skin tone:", "&#x1f938;&#x1f3fe;"},
+ {"", ":person cartwheeling dark skin tone:", "&#x1f938;&#x1f3ff;"},
+ {"", ":man cartwheeling light skin tone:", "&#x1f938;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man cartwheeling medium-light skin tone:", "&#x1f938;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man cartwheeling medium skin tone:", "&#x1f938;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man cartwheeling medium-dark skin tone:", "&#x1f938;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man cartwheeling dark skin tone:", "&#x1f938;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman cartwheeling light skin tone:", "&#x1f938;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman cartwheeling medium-light skin tone:", "&#x1f938;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman cartwheeling medium skin tone:", "&#x1f938;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman cartwheeling medium-dark skin tone:", "&#x1f938;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman cartwheeling dark skin tone:", "&#x1f938;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person playing water polo light skin tone:", "&#x1f93d;&#x1f3fb;"},
+ {"", ":person playing water polo medium-light skin tone:", "&#x1f93d;&#x1f3fc;"},
+ {"", ":person playing water polo medium skin tone:", "&#x1f93d;&#x1f3fd;"},
+ {"", ":person playing water polo medium-dark skin tone:", "&#x1f93d;&#x1f3fe;"},
+ {"", ":person playing water polo dark skin tone:", "&#x1f93d;&#x1f3ff;"},
+ {"", ":man playing water polo light skin tone:", "&#x1f93d;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing water polo medium-light skin tone:", "&#x1f93d;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing water polo medium skin tone:", "&#x1f93d;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing water polo medium-dark skin tone:", "&#x1f93d;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing water polo dark skin tone:", "&#x1f93d;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman playing water polo light skin tone:", "&#x1f93d;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing water polo medium-light skin tone:", "&#x1f93d;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing water polo medium skin tone:", "&#x1f93d;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing water polo medium-dark skin tone:", "&#x1f93d;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing water polo dark skin tone:", "&#x1f93d;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person playing handball light skin tone:", "&#x1f93e;&#x1f3fb;"},
+ {"", ":person playing handball medium-light skin tone:", "&#x1f93e;&#x1f3fc;"},
+ {"", ":person playing handball medium skin tone:", "&#x1f93e;&#x1f3fd;"},
+ {"", ":person playing handball medium-dark skin tone:", "&#x1f93e;&#x1f3fe;"},
+ {"", ":person playing handball dark skin tone:", "&#x1f93e;&#x1f3ff;"},
+ {"", ":man playing handball light skin tone:", "&#x1f93e;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing handball medium-light skin tone:", "&#x1f93e;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing handball medium skin tone:", "&#x1f93e;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing handball medium-dark skin tone:", "&#x1f93e;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man playing handball dark skin tone:", "&#x1f93e;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman playing handball light skin tone:", "&#x1f93e;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing handball medium-light skin tone:", "&#x1f93e;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing handball medium skin tone:", "&#x1f93e;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing handball medium-dark skin tone:", "&#x1f93e;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman playing handball dark skin tone:", "&#x1f93e;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person juggling light skin tone:", "&#x1f939;&#x1f3fb;"},
+ {"", ":person juggling medium-light skin tone:", "&#x1f939;&#x1f3fc;"},
+ {"", ":person juggling medium skin tone:", "&#x1f939;&#x1f3fd;"},
+ {"", ":person juggling medium-dark skin tone:", "&#x1f939;&#x1f3fe;"},
+ {"", ":person juggling dark skin tone:", "&#x1f939;&#x1f3ff;"},
+ {"", ":man juggling light skin tone:", "&#x1f939;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man juggling medium-light skin tone:", "&#x1f939;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man juggling medium skin tone:", "&#x1f939;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man juggling medium-dark skin tone:", "&#x1f939;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man juggling dark skin tone:", "&#x1f939;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman juggling light skin tone:", "&#x1f939;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman juggling medium-light skin tone:", "&#x1f939;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman juggling medium skin tone:", "&#x1f939;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman juggling medium-dark skin tone:", "&#x1f939;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman juggling dark skin tone:", "&#x1f939;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person in lotus position light skin tone:", "&#x1f9d8;&#x1f3fb;"},
+ {"", ":person in lotus position medium-light skin tone:", "&#x1f9d8;&#x1f3fc;"},
+ {"", ":person in lotus position medium skin tone:", "&#x1f9d8;&#x1f3fd;"},
+ {"", ":person in lotus position medium-dark skin tone:", "&#x1f9d8;&#x1f3fe;"},
+ {"", ":person in lotus position dark skin tone:", "&#x1f9d8;&#x1f3ff;"},
+ {"", ":man in lotus position light skin tone:", "&#x1f9d8;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in lotus position medium-light skin tone:", "&#x1f9d8;&#x1f3fc;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in lotus position medium skin tone:", "&#x1f9d8;&#x1f3fd;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in lotus position medium-dark skin tone:", "&#x1f9d8;&#x1f3fe;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":man in lotus position dark skin tone:", "&#x1f9d8;&#x1f3ff;&#x200d;&#x2642;&#xfe0f;"},
+ {"", ":woman in lotus position light skin tone:", "&#x1f9d8;&#x1f3fb;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in lotus position medium-light skin tone:", "&#x1f9d8;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in lotus position medium skin tone:", "&#x1f9d8;&#x1f3fd;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in lotus position medium-dark skin tone:", "&#x1f9d8;&#x1f3fe;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":woman in lotus position dark skin tone:", "&#x1f9d8;&#x1f3ff;&#x200d;&#x2640;&#xfe0f;"},
+ {"", ":person taking bath light skin tone:", "&#x1f6c0;&#x1f3fb;"},
+ {"", ":person taking bath medium-light skin tone:", "&#x1f6c0;&#x1f3fc;"},
+ {"", ":person taking bath medium skin tone:", "&#x1f6c0;&#x1f3fd;"},
+ {"", ":person taking bath medium-dark skin tone:", "&#x1f6c0;&#x1f3fe;"},
+ {"", ":person taking bath dark skin tone:", "&#x1f6c0;&#x1f3ff;"},
+ {"", ":person in bed light skin tone:", "&#x1f6cc;&#x1f3fb;"},
+ {"", ":person in bed medium-light skin tone:", "&#x1f6cc;&#x1f3fc;"},
+ {"", ":person in bed medium skin tone:", "&#x1f6cc;&#x1f3fd;"},
+ {"", ":person in bed medium-dark skin tone:", "&#x1f6cc;&#x1f3fe;"},
+ {"", ":person in bed dark skin tone:", "&#x1f6cc;&#x1f3ff;"},
+ {"", ":light skin tone:", "&#x1f3fb;"},
+ {"", ":medium-light skin tone:", "&#x1f3fc;"},
+ {"", ":medium skin tone:", "&#x1f3fd;"},
+ {"", ":medium-dark skin tone:", "&#x1f3fe;"},
+ {"", ":dark skin tone:", "&#x1f3ff;"},
+}
+;
+
+static const int g_numEmojiEntities = (int)(sizeof(g_emojiEntities)/ sizeof(*g_emojiEntities));
+
+EmojiEntityMapper *EmojiEntityMapper::s_instance = 0;
+
+EmojiEntityMapper::EmojiEntityMapper()
+{
+ m_name2symGh = new QDict<int>(1009);
+ m_name2symUni = new QDict<int>(1009);
+ m_name2symStripUni = new QDict<int>(10);
+ m_name2symGh->setAutoDelete(TRUE);
+ m_name2symUni->setAutoDelete(TRUE);
+ m_name2symStripUni->setAutoDelete(TRUE);
+ // 2 loops to be able to give precedence to the unicodeName (CLDR)
+ for (int i = 0; i < g_numEmojiEntities; i++)
+ {
+ if (strlen(g_emojiEntities[i].githubName)) m_name2symGh->insert(g_emojiEntities[i].githubName, new int(i+1));
+ }
+ for (int i = 0; i < g_numEmojiEntities; i++)
+ {
+ m_name2symUni->insert(g_emojiEntities[i].unicodeName, new int(-(i+1)));
+ QCString strippedUnicodeName = g_emojiEntities[i].unicodeName;
+ // A ring -> a ring
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\x85","\xc3\xa5");
+ if (strippedUnicodeName != g_emojiEntities[i].unicodeName)
+ {
+ m_name2symStripUni->insert(strippedUnicodeName, new int(-(i+1)));
+ }
+ // a ring -> a
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\xa5","a");
+ // c cedille -> c
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\xa7","c");
+ // o circumflex -> o
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\xb4","o");
+ // e acute -> e
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\xa9","e");
+ // a tilde -> a
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\xa3","a");
+ // i acute -> i
+ strippedUnicodeName = substitute(strippedUnicodeName,"\xc3\xad","i");
+ if (strippedUnicodeName != g_emojiEntities[i].unicodeName)
+ {
+ m_name2symStripUni->insert(strippedUnicodeName, new int(-(i+1)));
+ }
+ }
+}
+
+EmojiEntityMapper::~EmojiEntityMapper()
+{
+ delete m_name2symGh;
+ delete m_name2symUni;
+ delete m_name2symStripUni;
+}
+
+/** Returns the one and only instance of the Emoji entity mapper */
+EmojiEntityMapper *EmojiEntityMapper::instance()
+{
+ if (s_instance==0)
+ {
+ s_instance = new EmojiEntityMapper;
+ }
+ return s_instance;
+}
+
+/** Deletes the one and only instance of the Emoji entity mapper */
+void EmojiEntityMapper::deleteInstance()
+{
+ delete s_instance;
+ s_instance=0;
+}
+
+
+/*! @brief Access routine to the UTF8 code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @param useInPrintf If TRUE the result will be escaped such that it can be
+ * used in a printf string pattern
+ * @return the UTF8 code of the Emoji entity,
+ * in case the UTF code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::utf8(int symb) const
+{
+ if (symb > 0) return g_emojiEntities[symb-1].githubName;
+ else if (symb < 0) return g_emojiEntities[abs(symb)-1].unicodeName;
+ else return NULL;
+}
+
+/*! @brief Access routine to the html code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @param useInPrintf If TRUE the result will be escaped such that it can be
+ * used in a printf string pattern
+ * @return the html representation of the Emoji entity,
+ * in case the html code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::html(int symb) const
+{
+ return g_emojiEntities[abs(symb) - 1].code;
+}
+
+/*! @brief Access routine to the XML code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the XML code of the Emoji entity,
+ * in case the XML code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::xml(int symb) const
+{
+ return g_emojiEntities[abs(symb) - 1].code;
+}
+/*! @brief Access routine to the docbook code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the docbook code of the Emoji entity,
+ * in case the docbook code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::docbook(int symb) const
+{
+ return g_emojiEntities[abs(symb) - 1].code;
+}
+
+/*! @brief Access routine to the LaTeX code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the LaTeX code of the Emoji entity,
+ * in case the LaTeX code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::latex(int symb) const
+{
+ if (symb > 0) return g_emojiEntities[symb-1].githubName;
+ else if (symb < 0) return g_emojiEntities[abs(symb)-1].unicodeName;
+ else return NULL;
+}
+
+/*! @brief Access routine to the man code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the man of the Emoji entity,
+ * in case the man code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::man(int symb) const
+{
+ if (symb > 0) return g_emojiEntities[symb-1].githubName;
+ else if (symb < 0) return g_emojiEntities[abs(symb)-1].unicodeName;
+ else return NULL;
+}
+
+/*! @brief Access routine to the RTF code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the RTF of the Emoji entity,
+ * in case the RTF code is unknown \c NULL is returned.
+ */
+const char *EmojiEntityMapper::rtf(int symb) const
+{
+ return g_emojiEntities[abs(symb) - 1].code;
+}
+
+/*! @brief Access routine to the perl struct with the perl code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the pointer to perl struct with the perl code of the Emoji entity,
+ * in case the perl code does not exists the NULL pointer is entered in the
+ * \c symb field and in the `DocSymbol::Perl_unknown` in the \c type field.
+ */
+const char *EmojiEntityMapper::perl(int symb) const
+{
+ if (symb > 0) return g_emojiEntities[symb-1].githubName;
+ else if (symb < 0) return g_emojiEntities[abs(symb)-1].unicodeName;
+ else return NULL;
+}
+
+/*!
+ * @brief Give code of the requested Emoji entity name
+ * @param symName Emoji entity name
+ * @return the code for the requested Emoji entity name,
+ * in case the requested Emoji item does not exist `0` is returned.
+ */
+int EmojiEntityMapper::name2sym(const QCString &symName) const
+{
+ QCString locSymName = symName.lower();
+ int *pSymb = m_name2symUni->find(locSymName);
+ if (!pSymb) pSymb = m_name2symStripUni->find(locSymName);
+ if (!pSymb) pSymb = m_name2symGh->find(locSymName);
+ return pSymb ? (*pSymb) : 0;
+}
+void EmojiEntityMapper::writeEmojiFile(QFile &file)
+{
+ FTextStream t(&file);
+
+ for (int i = 0; i < g_numEmojiEntities; i++)
+ {
+ t << g_emojiEntities[i].unicodeName << endl;
+ }
+ for (int i = 0; i < g_numEmojiEntities; i++)
+ {
+ if (strlen(g_emojiEntities[i].githubName)) t << g_emojiEntities[i].githubName << endl;
+ }
+}
+/*! @brief Access routine to the code of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the code of the Emoji entity,
+ */
+const char *EmojiEntityMapper::code(int symb) const
+{
+ return g_emojiEntities[abs(symb) - 1].code;
+}
+
+/*! @brief Access routine to the text of the Emoji entity
+ *
+ * @param symb Code of the requested Emoji entity
+ * @return the text of the Emoji entity,
+ */
+const char *EmojiEntityMapper::text(int symb) const
+{
+ if (symb > 0) return g_emojiEntities[symb-1].githubName;
+ else if (symb < 0) return g_emojiEntities[abs(symb)-1].unicodeName;
+ else return NULL;
+}
+/// \file
+/// to generate the content of the table with the emoji definitions and code the following procedure has been used:
+///
+/// <pre>
+/// wget https://api.github.com/emojis
+/// wget https://www.unicode.org/emoji/charts/full-emoji-list.html
+/// wget http://www.unicode.org/emoji/charts/full-emoji-modifiers.html
+///
+/// grep -v "[{}]" emojis | sed -e "s/https:.*\///" | sed -e "s%.png.*%%" | sed -e "s/ //" | sed -e "s/://" | tr ' ' '\n' | tr '\042' ' ' | sed -e "s/ //g" > emojis.res
+///
+/// grep -A 14 "<tr><td class='rchars'>[0-9]" full-emoji-list.html | grep -v "class='andr" | grep -v "class='[r]*chars'" | sed -e "s/<[^>]*>//g" | sed -e "s/://" | tr [A-Z] [a-z] | sed -e "s/^[^a-z][^a-z][^a-z] //" | grep -v "\-\-" | sed -e "s/&amp;/\&/" | sed -e "s/ u+/;\&#x/g" | sed -e "s/^u+\(.*\)/\&#x\1;/" > full.res
+/// grep -A 14 "<tr><td class='rchars'>[0-9]" full-emoji-modifiers.html | grep -v "class='andr" | grep -v "class='[r]*chars'" | sed -e "s/<[^>]*>//g" | sed -e "s/://" | tr [A-Z] [a-z] | sed -e "s/^[^a-z][^a-z][^a-z] //" | grep -v "\-\-" | sed -e "s/&amp;/\&/" | sed -e "s/ u+/;\&#x/g" | sed -e "s/^u+\(.*\)/\&#x\1;/" >> full.res
+///
+///
+/// python transform.py full.res emojis.res > transform.res
+/// </pre>
+/// where the contents of `transform.py` is:
+/// \code{.py}
+///import sys
+///
+///# read first file (unicode names)
+///# read second files (github names)
+///
+///uniFile = open(sys.argv[1])
+///emoFile = open(sys.argv[2])
+///
+///uniLines = uniFile.readlines()
+///emoLines = emoFile.readlines()
+///
+///uniFile.close()
+///emoFile.close()
+///
+///uniMaxLen = 0
+///emoMaxLen = 0
+///
+///for i in range(0, len(uniLines), 2):
+/// if (len(uniLines[i]) > uniMaxLen):
+/// uniMaxLen = len(uniLines[i])
+///
+///for i in range(0, len(emoLines), 2):
+/// if (len(emoLines[i]) > emoMaxLen):
+/// emoMaxLen = len(emoLines[i])
+///
+///uniProcessed = [False]*(len(uniLines) / 2)
+///
+///# replace "strange" single and double quotes.
+///for i in range(0, len(uniLines), 2):
+/// uniLines[i+1] = uniLines[i+1].replace("\342\200\234",'\\"').replace("\342\200\235",'\\"')
+/// uniLines[i+1] = uniLines[i+1].replace("\342\200\231","'").replace("\342\200\231","'")
+///
+///for i in range(0, len(emoLines), 2):
+/// emoCode = emoLines[i+1].split('-')
+/// found = False
+/// emoCode = [e.replace('\n', '') for e in emoCode]
+/// for u in range(0, len(uniLines), 2):
+/// cnt = 0
+/// beg = 0
+/// for j in emoCode:
+/// pos = uniLines[u].find(j, beg)
+/// if pos != -1:
+/// # in case of 'u+': 2, '&#x': 3
+/// if (beg == 0 and j == emoCode[0] and pos != 3):
+/// break
+/// cnt += 1
+/// beg = pos + 1
+/// if (cnt == len(emoCode)):
+/// uniProcessed[u/2] = True
+/// found = True
+/// print ' {":'+emoLines[i].replace('\n','')+':",'+(emoMaxLen-len(emoLines[i].replace('\n',''))+1)*' '+'":'+uniLines[u+1].replace('\n','')+':",'+(uniMaxLen-len(uniLines[u+1].replace('\n',''))+1)*' '+'"'+uniLines[u].replace('\n','')+'"},'
+/// break
+/// if not found:
+/// # github name but no unicode version
+/// # print ' ONLY_GITHUB_NAME "'+emoLines[i].replace('\n','')+'" "'+emoLines[i+1].replace('\n','')+'"'
+/// pass
+///
+///for u in range(0, len(uniProcessed)):
+/// if not uniProcessed[u]:
+/// print ' {"",'+(emoMaxLen+1)*' '+'":'+uniLines[u*2+1].replace('\n','')+':",'+(uniMaxLen-len(uniLines[u*2+1].replace('\n',''))+1)*' '+'"'+uniLines[u*2].replace('\n','')+'"},'
+///
+/// \endcode
diff --git a/src/emoji.h b/src/emoji.h
new file mode 100644
index 0000000..b8db6f1
--- /dev/null
+++ b/src/emoji.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2018 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 EMOJIENTITY_H
+#define EMOJIENTITY_H
+
+#include <qdict.h>
+#include <qfile.h>
+
+class FTextStream;
+
+/** @brief Singleton helper class to map emoji entities to other formats */
+class EmojiEntityMapper
+{
+ public:
+ static EmojiEntityMapper *instance();
+ static void deleteInstance();
+ int name2sym(const QCString &symName) const;
+ const char *utf8(int symb) const;
+ const char *html(int symb) const;
+ const char *xml(int symb) const;
+ const char *docbook(int symb) const;
+ const char *latex(int symb) const;
+ const char *man(int symb) const;
+ const char *rtf(int symb) const;
+ const char *perl(int symb) const;
+ const char *code(int symb) const;
+ const char *text(int symb) const;
+ void writeEmojiFile(QFile &file);
+ private:
+ EmojiEntityMapper();
+ ~EmojiEntityMapper();
+ static EmojiEntityMapper *s_instance;
+ QDict<int> *m_name2symGh;
+ QDict<int> *m_name2symUni;
+ QDict<int> *m_name2symStripUni;
+};
+
+#endif
diff --git a/src/entry.cpp b/src/entry.cpp
index a0460da..4332186 100644
--- a/src/entry.cpp
+++ b/src/entry.cpp
@@ -79,6 +79,8 @@ Entry::Entry(const Entry &e)
subGrouping = e.subGrouping;
callGraph = e.callGraph;
callerGraph = e.callerGraph;
+ referencedByRelation = e.referencedByRelation;
+ referencesRelation = e.referencesRelation;
virt = e.virt;
args = e.args;
bitfields = e.bitfields;
@@ -219,6 +221,8 @@ void Entry::reset()
{
static bool entryCallGraph = Config_getBool(CALL_GRAPH);
static bool entryCallerGraph = Config_getBool(CALLER_GRAPH);
+ static bool entryReferencedByRelation = Config_getBool(REFERENCED_BY_RELATION);
+ static bool entryReferencesRelation = Config_getBool(REFERENCES_RELATION);
//printf("Entry::reset()\n");
name.resize(0);
type.resize(0);
@@ -250,6 +254,8 @@ void Entry::reset()
mGrpId = -1;
callGraph = entryCallGraph;
callerGraph = entryCallerGraph;
+ referencedByRelation = entryReferencedByRelation;
+ referencesRelation = entryReferencesRelation;
section = EMPTY_SEC;
mtype = Method;
virt = Normal;
diff --git a/src/entry.h b/src/entry.h
index fac3831..8187e03 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -91,14 +91,14 @@ class Entry
ENUMDOC_SEC = 0x01000000,
ENUM_SEC = 0x02000000,
- EMPTY_SEC = 0x03000000,
- PAGEDOC_SEC = 0x04000000,
+ EMPTY_SEC = 0x03000000,
+ PAGEDOC_SEC = 0x04000000,
VARIABLE_SEC = 0x05000000,
FUNCTION_SEC = 0x06000000,
TYPEDEF_SEC = 0x07000000,
- MEMBERDOC_SEC = 0x08000000,
+ MEMBERDOC_SEC = 0x08000000,
OVERLOADDOC_SEC = 0x09000000,
- EXAMPLE_SEC = 0x0a000000,
+ EXAMPLE_SEC = 0x0a000000,
VARIABLEDOC_SEC = 0x0b000000,
FILEDOC_SEC = 0x0c000000,
DEFINEDOC_SEC = 0x0d000000,
@@ -112,9 +112,10 @@ class Entry
PACKAGE_SEC = 0x15000000,
PACKAGEDOC_SEC = 0x16000000,
OBJCIMPL_SEC = 0x17000000,
- DIRDOC_SEC = 0x18000000
- ,EXPORTED_INTERFACE_SEC = 0x19000000
- ,INCLUDED_SERVICE_SEC = 0x1A000000
+ DIRDOC_SEC = 0x18000000,
+ EXPORTED_INTERFACE_SEC = 0x19000000,
+ INCLUDED_SERVICE_SEC = 0x1A000000,
+ EXAMPLE_LINENO_SEC = 0x1B000000,
};
// class specifiers (add new items to the end)
@@ -248,6 +249,8 @@ class Entry
bool subGrouping; //!< automatically group class members?
bool callGraph; //!< do we need to draw the call graph?
bool callerGraph; //!< do we need to draw the caller graph?
+ bool referencedByRelation;//!< do we need to show the referenced by relation?
+ bool referencesRelation; //!< do we need to show the references relation?
Specifier virt; //!< virtualness of the entry
QCString args; //!< member argument string
QCString bitfields; //!< member's bit fields
diff --git a/src/filedef.cpp b/src/filedef.cpp
index e2df9be..d9eaa4b 100644
--- a/src/filedef.cpp
+++ b/src/filedef.cpp
@@ -348,6 +348,10 @@ void FileDef::writeDetailedDescription(OutputList &ol,const QCString &title)
{
ol.disable(OutputGenerator::Latex);
}
+ if (ol.isEnabled(OutputGenerator::Docbook) && !Config_getBool(DOCBOOK_PROGRAMLISTING))
+ {
+ ol.disable(OutputGenerator::Docbook);
+ }
if (ol.isEnabled(OutputGenerator::RTF) && !Config_getBool(RTF_SOURCE_CODE))
{
ol.disable(OutputGenerator::RTF);
@@ -937,6 +941,7 @@ void FileDef::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu)
static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES);
static bool latexSourceCode = Config_getBool(LATEX_SOURCE_CODE);
+ static bool docbookSourceCode = Config_getBool(DOCBOOK_PROGRAMLISTING);
static bool rtfSourceCode = Config_getBool(RTF_SOURCE_CODE);
DevNullCodeDocInterface devNullIntf;
QCString title = m_docname;
@@ -947,6 +952,7 @@ void FileDef::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu)
QCString pageTitle = theTranslator->trSourceFile(title);
ol.disable(OutputGenerator::Man);
if (!latexSourceCode) ol.disable(OutputGenerator::Latex);
+ if (!docbookSourceCode) ol.disable(OutputGenerator::Docbook);
if (!rtfSourceCode) ol.disable(OutputGenerator::RTF);
bool isDocFile = isDocumentationFile();
@@ -978,13 +984,14 @@ void FileDef::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu)
if (isLinkable())
{
+ ol.pushGeneratorState();
if (latexSourceCode) ol.disable(OutputGenerator::Latex);
if (rtfSourceCode) ol.disable(OutputGenerator::RTF);
+ if (docbookSourceCode) ol.disable(OutputGenerator::Docbook);
ol.startTextLink(getOutputFileBase(),0);
ol.parseText(theTranslator->trGotoDocumentation());
ol.endTextLink();
- if (latexSourceCode) ol.enable(OutputGenerator::Latex);
- if (rtfSourceCode) ol.enable(OutputGenerator::RTF);
+ ol.popGeneratorState();
}
(void)sameTu;
diff --git a/src/fortrancode.l b/src/fortrancode.l
index 3c1829d..0e610fd 100644
--- a/src/fortrancode.l
+++ b/src/fortrancode.l
@@ -37,7 +37,7 @@
#include <ctype.h>
#include <qregexp.h>
#include <qdir.h>
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include "entry.h"
#include "doxygen.h"
#include "message.h"
@@ -86,7 +86,7 @@ class UseEntry
{
public:
QCString module; // just for debug
- QStringList onlyNames; /* entries of the ONLY-part */
+ QCStringList onlyNames; /* entries of the ONLY-part */
};
/**
@@ -105,10 +105,11 @@ class UseSDict : public SDict<UseEntry>
class Scope
{
public:
- QStringList useNames; //!< contains names of used modules
+ QCStringList useNames; //!< contains names of used modules
QDict<void> localVars; //!< contains names of local variables
+ QDict<void> externalVars; //!< contains names of external entities
- Scope() : localVars(7, FALSE /*caseSensitive*/) {}
+ Scope() : localVars(7, FALSE /*caseSensitive*/), externalVars(7, FALSE /*caseSensitive*/) {}
};
/*===================================================================*/
@@ -122,7 +123,8 @@ static QCString currentClass=0; //!< name of the current enclosing
static UseSDict *useMembers= new UseSDict; //!< info about used modules
static UseEntry *useEntry = 0; //!< current use statement info
static QList<Scope> scopeStack;
-// static QStringList *currentUseNames= new QStringList; //! contains names of used modules of current program unit
+static bool g_isExternal = false;
+// static QCStringList *currentUseNames= new QCStringList; //! contains names of used modules of current program unit
static QCString str=""; //!> contents of fortran string
static CodeOutputInterface * g_code;
@@ -434,7 +436,7 @@ static bool getFortranDefs(const QCString &memberName, const QCString &moduleNam
Scope *scope;
for (it.toLast();(scope=it.current());--it)
{
- if (scope->localVars.find(memberName))
+ if (scope->localVars.find(memberName) && (!scope->externalVars.find(memberName)))
return FALSE;
}
@@ -478,7 +480,7 @@ static bool getFortranDefs(const QCString &memberName, const QCString &moduleNam
if (ue)
{
// check if only-list exists and if current entry exists is this list
- QStringList &only= ue->onlyNames;
+ QCStringList &only= ue->onlyNames;
if (only.isEmpty())
{
//cout << " found in module " << moduleName << " entry " << memberName << endl;
@@ -486,10 +488,10 @@ static bool getFortranDefs(const QCString &memberName, const QCString &moduleNam
}
else
{
- for ( QStringList::Iterator it = only.begin(); it != only.end(); ++it)
+ for ( QCStringList::Iterator it = only.begin(); it != only.end(); ++it)
{
//cout << " search in only: " << moduleName << ":: " << memberName << "==" << (*it)<< endl;
- if (memberName == (*it).utf8())
+ if (memberName == *it)
{
return TRUE; // found in ONLY-part of use list
}
@@ -632,9 +634,9 @@ static void endScope()
Scope *scope = scopeStack.getLast();
scopeStack.removeLast();
- for ( QStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it)
+ for ( QCStringList::Iterator it = scope->useNames.begin(); it != scope->useNames.end(); ++it)
{
- useMembers->remove((*it).utf8());
+ useMembers->remove(*it);
}
delete scope;
}
@@ -648,7 +650,10 @@ static void addUse(const QCString &moduleName)
static void addLocalVar(const QCString &varName)
{
if (!scopeStack.isEmpty())
+ {
scopeStack.getLast()->localVars.insert(varName, (void*)1);
+ if (g_isExternal) scopeStack.getLast()->externalVars.insert(varName, (void*)1);
+ }
}
//----------------------------------------------------------------------------
@@ -969,11 +974,18 @@ LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")
endFontClass();
}
<Start>{ATTR_SPEC} {
+ if (QCString(yytext) == "external")
+ {
+ yy_push_state(YY_START);
+ BEGIN(Declaration);
+ g_isExternal = true;
+ }
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
}
<Declaration>({TYPE_SPEC}|{ATTR_SPEC})/[,:( ] { //| variable declaration
+ if (QCString(yytext) == "external") g_isExternal = true;
startFontClass("keywordtype");
g_code->codify(yytext);
endFontClass();
@@ -1046,6 +1058,7 @@ LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")
g_contLineNr++;
if (!(g_hasContLine && g_hasContLine[g_contLineNr - 1]))
{
+ g_isExternal = false;
yy_pop_state();
}
YY_FTN_RESET
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 884c86e..5f10669 100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
@@ -231,6 +231,8 @@ static void updateVariablePrepassComment(int from, int to);
static void newLine();
static void initEntry();
+static const char *stateToString(int state);
+
//-----------------------------------------------------------------------------
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
@@ -1638,7 +1640,7 @@ const char* prepassFixedForm(const char* contents, int *hasContLine)
}
// fallthrough
default:
- if ((column < 6) && ((c - '0') >= 0) && ((c - '0') <= 9)) { // remove numbers, i.e. labels from first 5 positions.
+ if (!commented && (column < 6) && ((c - '0') >= 0) && ((c - '0') <= 9)) { // remove numbers, i.e. labels from first 5 positions.
newContents[j]=' ';
}
else if(column==6 && emptyLabel) { // continuation
@@ -2759,7 +2761,7 @@ void FortranLanguageScanner::parsePrototype(const char *text)
static void scanner_abort()
{
fprintf(stderr,"********************************************************************\n");
- fprintf(stderr,"Error in file %s line: %d, state: %d\n",yyFileName.data(),yyLineNr,YY_START);
+ fprintf(stderr,"Error in file %s line: %d, state: %d(%s)\n",yyFileName.data(),yyLineNr,YY_START,stateToString(YY_START));
fprintf(stderr,"********************************************************************\n");
EntryListIterator eli(*global_root->children());
@@ -2788,3 +2790,47 @@ extern "C" { // some bogus code to keep the compiler happy
}
#endif
+#define scanStateToString(x) case x: resultString = #x; break;
+static const char *stateToString(int state)
+{
+ const char *resultString;
+ switch(state)
+ {
+ scanStateToString(INITIAL)
+ scanStateToString(Subprog)
+ scanStateToString(SubprogPrefix)
+ scanStateToString(Parameterlist)
+ scanStateToString(SubprogBody)
+ scanStateToString(SubprogBodyContains)
+ scanStateToString(Start)
+ scanStateToString(Comment)
+ scanStateToString(Module)
+ scanStateToString(Program)
+ scanStateToString(ModuleBody)
+ scanStateToString(ModuleBodyContains)
+ scanStateToString(AttributeList)
+ scanStateToString(Variable)
+ scanStateToString(Initialization)
+ scanStateToString(ArrayInitializer)
+ scanStateToString(Enum)
+ scanStateToString(Typedef)
+ scanStateToString(TypedefBody)
+ scanStateToString(TypedefBodyContains)
+ scanStateToString(InterfaceBody)
+ scanStateToString(StrIgnore)
+ scanStateToString(String)
+ scanStateToString(Use)
+ scanStateToString(UseOnly)
+ scanStateToString(ModuleProcedure)
+ scanStateToString(Prepass)
+ scanStateToString(DocBlock)
+ scanStateToString(DocBackLine)
+ scanStateToString(EndDoc)
+ scanStateToString(BlockData)
+ scanStateToString(Prototype)
+ scanStateToString(PrototypeSubprog)
+ scanStateToString(PrototypeArgs)
+ default: resultString = "Unknown"; break;
+ }
+ return resultString;
+}
diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp
index cee39f2..8c46fd5 100644
--- a/src/ftvhelp.cpp
+++ b/src/ftvhelp.cpp
@@ -171,11 +171,10 @@ void FTVHelp::decContentsDepth()
/*! Add a list item to the contents file.
* \param isDir TRUE if the item is a directory, FALSE if it is a text
- * \param name The name of the item.
+ * \param name the name of the item.
* \param ref the URL of to the item.
* \param file the file containing the definition of the item
* \param anchor the anchor within the file.
- * \param name the name of the item.
* \param separateIndex put the entries in a separate index file
* \param addToNavIndex add this entry to the quick navigation index
* \param def Definition corresponding to this entry
diff --git a/src/htmldocvisitor.cpp b/src/htmldocvisitor.cpp
index 6bd5347..ba10ca1 100644
--- a/src/htmldocvisitor.cpp
+++ b/src/htmldocvisitor.cpp
@@ -34,10 +34,36 @@
#include "filedef.h"
#include "memberdef.h"
#include "htmlentity.h"
+#include "emoji.h"
#include "plantuml.h"
static const int NUM_HTML_LIST_TYPES = 4;
static const char types[][NUM_HTML_LIST_TYPES] = {"1", "a", "i", "A"};
+enum contexts_t
+{
+ NONE, // 0
+ STARTLI, // 1
+ STARTDD, // 2
+ ENDLI, // 3
+ ENDDD, // 4
+ STARTTD, // 5
+ ENDTD, // 6
+ INTERLI, // 7
+ INTERDD, // 8
+ INTERTD // 9
+};
+static const char *contexts[10] =
+{ "", // 0
+ "startli", // 1
+ "startdd", // 2
+ "endli", // 3
+ "enddd", // 4
+ "starttd", // 5
+ "endtd", // 6
+ "interli", // 7
+ "interdd", // 8
+ "intertd" // 9
+};
static QCString convertIndexWordToAnchor(const QString &word)
{
@@ -126,7 +152,7 @@ static bool mustBeOutsideParagraph(DocNode *n)
return FALSE;
}
-static QString htmlAttribsToString(const HtmlAttribList &attribs, const bool img_tag = FALSE)
+static QString htmlAttribsToString(const HtmlAttribList &attribs, bool img_tag = FALSE)
{
QString result;
HtmlAttribListIterator li(attribs);
@@ -209,6 +235,20 @@ void HtmlDocVisitor::visit(DocSymbol *s)
}
}
+void HtmlDocVisitor::visit(DocEmoji *s)
+{
+ if (m_hide) return;
+ const char *res = EmojiEntityMapper::instance()->html(s->emoji());
+ if (res)
+ {
+ m_t << res;
+ }
+ else
+ {
+ err("HTML: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+}
+
void HtmlDocVisitor::writeObfuscatedMailAddress(const QCString &url)
{
m_t << "<a href=\"#\" onclick=\"location.href='mai'+'lto:'";
@@ -271,6 +311,12 @@ void HtmlDocVisitor::visit(DocStyleChange *s)
case DocStyleChange::Bold:
if (s->enable()) m_t << "<b" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</b>";
break;
+ case DocStyleChange::Strike:
+ if (s->enable()) m_t << "<strike" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</strike>";
+ break;
+ case DocStyleChange::Underline:
+ if (s->enable()) m_t << "<u" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</u>";
+ break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "<em" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</em>";
break;
@@ -887,24 +933,24 @@ static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
}
isFirst=isFirstChildNode((DocParBlock*)p->parent(),p);
isLast =isLastChildNode ((DocParBlock*)p->parent(),p);
- t=0;
+ t=NONE;
if (isFirst)
{
if (kind==DocNode::Kind_HtmlListItem ||
kind==DocNode::Kind_SecRefItem)
{
- t=1;
+ t=STARTLI;
}
else if (kind==DocNode::Kind_HtmlDescData ||
kind==DocNode::Kind_XRefItem ||
kind==DocNode::Kind_SimpleSect)
{
- t=2;
+ t=STARTDD;
}
else if (kind==DocNode::Kind_HtmlCell ||
kind==DocNode::Kind_ParamList)
{
- t=5;
+ t=STARTTD;
}
}
if (isLast)
@@ -912,18 +958,37 @@ static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
if (kind==DocNode::Kind_HtmlListItem ||
kind==DocNode::Kind_SecRefItem)
{
- t=3;
+ t=ENDLI;
+ }
+ else if (kind==DocNode::Kind_HtmlDescData ||
+ kind==DocNode::Kind_XRefItem ||
+ kind==DocNode::Kind_SimpleSect)
+ {
+ t=ENDDD;
+ }
+ else if (kind==DocNode::Kind_HtmlCell ||
+ kind==DocNode::Kind_ParamList)
+ {
+ t=ENDTD;
+ }
+ }
+ if (!isFirst && !isLast)
+ {
+ if (kind==DocNode::Kind_HtmlListItem ||
+ kind==DocNode::Kind_SecRefItem)
+ {
+ t=INTERLI;
}
else if (kind==DocNode::Kind_HtmlDescData ||
kind==DocNode::Kind_XRefItem ||
kind==DocNode::Kind_SimpleSect)
{
- t=4;
+ t=INTERDD;
}
else if (kind==DocNode::Kind_HtmlCell ||
kind==DocNode::Kind_ParamList)
{
- t=6;
+ t=INTERTD;
}
}
break;
@@ -931,47 +996,51 @@ static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
case DocNode::Kind_AutoListItem:
isFirst=isFirstChildNode((DocAutoListItem*)p->parent(),p);
isLast =isLastChildNode ((DocAutoListItem*)p->parent(),p);
- t=1; // not used
+ t=STARTLI; // not used
break;
case DocNode::Kind_SimpleListItem:
isFirst=TRUE;
isLast =TRUE;
- t=1; // not used
+ t=STARTLI; // not used
break;
case DocNode::Kind_ParamList:
isFirst=TRUE;
isLast =TRUE;
- t=1; // not used
+ t=STARTLI; // not used
break;
case DocNode::Kind_HtmlListItem:
isFirst=isFirstChildNode((DocHtmlListItem*)p->parent(),p);
isLast =isLastChildNode ((DocHtmlListItem*)p->parent(),p);
- if (isFirst) t=1;
- if (isLast) t=3;
+ if (isFirst) t=STARTLI;
+ if (isLast) t=ENDLI;
+ if (!isFirst && !isLast) t = INTERLI;
break;
case DocNode::Kind_SecRefItem:
isFirst=isFirstChildNode((DocSecRefItem*)p->parent(),p);
isLast =isLastChildNode ((DocSecRefItem*)p->parent(),p);
- if (isFirst) t=1;
- if (isLast) t=3;
+ if (isFirst) t=STARTLI;
+ if (isLast) t=ENDLI;
+ if (!isFirst && !isLast) t = INTERLI;
break;
case DocNode::Kind_HtmlDescData:
isFirst=isFirstChildNode((DocHtmlDescData*)p->parent(),p);
isLast =isLastChildNode ((DocHtmlDescData*)p->parent(),p);
- if (isFirst) t=2;
- if (isLast) t=4;
+ if (isFirst) t=STARTDD;
+ if (isLast) t=ENDDD;
+ if (!isFirst && !isLast) t = INTERDD;
break;
case DocNode::Kind_XRefItem:
isFirst=isFirstChildNode((DocXRefItem*)p->parent(),p);
isLast =isLastChildNode ((DocXRefItem*)p->parent(),p);
- if (isFirst) t=2;
- if (isLast) t=4;
+ if (isFirst) t=STARTDD;
+ if (isLast) t=ENDDD;
+ if (!isFirst && !isLast) t = INTERDD;
break;
case DocNode::Kind_SimpleSect:
isFirst=isFirstChildNode((DocSimpleSect*)p->parent(),p);
isLast =isLastChildNode ((DocSimpleSect*)p->parent(),p);
- if (isFirst) t=2;
- if (isLast) t=4;
+ if (isFirst) t=STARTDD;
+ if (isLast) t=ENDDD;
if (isSeparatedParagraph((DocSimpleSect*)p->parent(),p))
// if the paragraph is enclosed with separators it will
// be included in <dd>..</dd> so avoid addition paragraph
@@ -979,12 +1048,14 @@ static int getParagraphContext(DocPara *p,bool &isFirst,bool &isLast)
{
isFirst=isLast=TRUE;
}
+ if (!isFirst && !isLast) t = INTERDD;
break;
case DocNode::Kind_HtmlCell:
isFirst=isFirstChildNode((DocHtmlCell*)p->parent(),p);
isLast =isLastChildNode ((DocHtmlCell*)p->parent(),p);
- if (isFirst) t=5;
- if (isLast) t=6;
+ if (isFirst) t=STARTTD;
+ if (isLast) t=ENDTD;
+ if (!isFirst && !isLast) t = INTERTD;
break;
default:
break;
@@ -1052,19 +1123,10 @@ void HtmlDocVisitor::visitPre(DocPara *p)
}
}
- // check if this paragraph is the first or last child of a <li> or <dd>.
+ // check if this paragraph is the first or last or intermediate child of a <li> or <dd>.
// this allows us to mark the tag with a special class so we can
// fix the otherwise ugly spacing.
int t;
- static const char *contexts[7] =
- { "", // 0
- "startli", // 1
- "startdd", // 2
- "endli", // 3
- "enddd", // 4
- "starttd", // 5
- "endtd" // 6
- };
bool isFirst;
bool isLast;
t = getParagraphContext(p,isFirst,isLast);
diff --git a/src/htmldocvisitor.h b/src/htmldocvisitor.h
index 2ff9f75..7184f0f 100644
--- a/src/htmldocvisitor.h
+++ b/src/htmldocvisitor.h
@@ -43,6 +43,7 @@ class HtmlDocVisitor : public DocVisitor
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
diff --git a/src/htmlentity.cpp b/src/htmlentity.cpp
index 3d95705..e95b817 100644
--- a/src/htmlentity.cpp
+++ b/src/htmlentity.cpp
@@ -314,7 +314,8 @@ static struct htmlEntityInfo
{ SYM(Quot), "\"", "\"", "\"", "&quot;", "\"", "\"", "\"", { "\"", DocSymbol::Perl_char }},
{ SYM(Minus), "-", "-", "-", "-", "-\\/", "-", "-", { "-", DocSymbol::Perl_char }},
{ SYM(Plus), "+", "+", "+", "+", "+", "+", "+", { "+", DocSymbol::Perl_char }},
- { SYM(Dot), ".", ".", ".", ".", ".", ".", ".", { ".", DocSymbol::Perl_char }}
+ { SYM(Dot), ".", ".", ".", ".", ".", ".", ".", { ".", DocSymbol::Perl_char }},
+ { SYM(Colon), ":", ":", ":", ":", ":", ":", ":", { ":", DocSymbol::Perl_char }}
};
static const int g_numHtmlEntities = (int)(sizeof(g_htmlEntities)/ sizeof(*g_htmlEntities));
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 87bc10a..f0f627c 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -17,6 +17,7 @@
#include <stdlib.h>
+#include <assert.h>
#include <qdir.h>
#include <qregexp.h>
#include "message.h"
@@ -690,6 +691,7 @@ HtmlGenerator::HtmlGenerator() : OutputGenerator()
{
dir=Config_getString(HTML_OUTPUT);
m_emptySection=FALSE;
+ m_sectionCount=0;
}
HtmlGenerator::~HtmlGenerator()
@@ -1943,25 +1945,16 @@ void HtmlGenerator::endDescTableData()
t << "</td>";
}
-void HtmlGenerator::startSimpleSect(SectionTypes,
- const char *filename,const char *anchor,
- const char *title)
+void HtmlGenerator::startExamples()
{
- t << "<dl><dt><b>";
- if (filename)
- {
- writeObjectLink(0,filename,anchor,title);
- }
- else
- {
- docify(title);
- }
- t << "</b></dt>";
+ t << "<dl class=\"section examples\"><dt>";
+ docify(theTranslator->trExamples());
+ t << "</dt>";
}
-void HtmlGenerator::endSimpleSect()
+void HtmlGenerator::endExamples()
{
- t << "</dl>";
+ t << "</dl>" << endl;
}
void HtmlGenerator::startParamList(ParamListTypes,
@@ -2064,6 +2057,9 @@ static bool quickLinkVisible(LayoutNavEntry::Kind kind)
case LayoutNavEntry::FileGlobals: return documentedFileMembers[FMHL_All]>0;
//case LayoutNavEntry::Dirs: return documentedDirs>0;
case LayoutNavEntry::Examples: return Doxygen::exampleSDict->count()>0;
+ case LayoutNavEntry::None: // should never happen, means not properly initialized
+ assert(kind != LayoutNavEntry::None);
+ return FALSE;
}
return FALSE;
}
diff --git a/src/htmlgen.h b/src/htmlgen.h
index 2d8d6e0..221269f 100644
--- a/src/htmlgen.h
+++ b/src/htmlgen.h
@@ -246,13 +246,10 @@ class HtmlGenerator : public OutputGenerator
void endCenter() { t << "</center>" << endl; }
void startSmall() { t << "<small>" << endl; }
void endSmall() { t << "</small>" << endl; }
- //void startDescList(SectionTypes) { t << "<dl compact><dt><b>" << endl; }
- //void endDescList() { t << "</dl>"; }
- void startSimpleSect(SectionTypes,const char *,const char *,const char *);
- void endSimpleSect();
+ void startExamples();
+ void endExamples();
void startParamList(ParamListTypes,const char *);
void endParamList();
- //void writeDescItem() { t << "<dd>" << endl; }
void startSection(const char *,const char *,SectionInfo::SectionType);
void endSection(const char *,SectionInfo::SectionType);
void addIndexItem(const char *,const char *);
diff --git a/src/index.cpp b/src/index.cpp
index 8e5f266..8be6b24 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
+#include <assert.h>
#include <qtextstream.h>
#include <qdatetime.h>
#include <qdir.h>
@@ -94,9 +95,12 @@ static void startIndexHierarchy(OutputList &ol,int level)
ol.disable(OutputGenerator::Man);
ol.disable(OutputGenerator::Html);
if (level<6) ol.startIndexList();
- ol.enableAll();
+ ol.popGeneratorState();
+
+ ol.pushGeneratorState();
ol.disable(OutputGenerator::Latex);
ol.disable(OutputGenerator::RTF);
+ ol.disable(OutputGenerator::Docbook);
ol.startItemList();
ol.popGeneratorState();
}
@@ -107,8 +111,11 @@ static void endIndexHierarchy(OutputList &ol,int level)
ol.disable(OutputGenerator::Man);
ol.disable(OutputGenerator::Html);
if (level<6) ol.endIndexList();
- ol.enableAll();
+ ol.popGeneratorState();
+
+ ol.pushGeneratorState();
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
ol.disable(OutputGenerator::RTF);
ol.endItemList();
ol.popGeneratorState();
@@ -959,6 +966,7 @@ static void writeHierarchicalIndex(OutputList &ol)
ol.pushGeneratorState();
//1.{
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassHierarchy);
QCString title = lne ? lne->title() : theTranslator->trClassHierarchy();
@@ -973,15 +981,16 @@ static void writeHierarchicalIndex(OutputList &ol)
if (Config_getBool(HAVE_DOT) && Config_getBool(GRAPHICAL_HIERARCHY))
{
+ ol.pushGeneratorState();
ol.disable(OutputGenerator::Latex);
ol.disable(OutputGenerator::RTF);
+ ol.disable(OutputGenerator::Docbook);
ol.startParagraph();
ol.startTextLink("inherits",0);
ol.parseText(theTranslator->trGotoGraphicalHierarchy());
ol.endTextLink();
ol.endParagraph();
- ol.enable(OutputGenerator::Latex);
- ol.enable(OutputGenerator::RTF);
+ ol.popGeneratorState();
}
ol.parseText(lne ? lne->intro() : theTranslator->trClassHierarchyDescription());
ol.endTextBlock();
@@ -1170,6 +1179,7 @@ static void writeFileIndex(OutputList &ol)
ol.pushGeneratorState();
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
if (documentedFiles==0) ol.disableAllBut(OutputGenerator::Html);
LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileList);
@@ -1450,6 +1460,7 @@ static void writeNamespaceIndex(OutputList &ol)
if (documentedNamespaces==0) return;
ol.pushGeneratorState();
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceList);
if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Namespaces); // fall back
QCString title = lne ? lne->title() : theTranslator->trNamespaceList();
@@ -1603,6 +1614,7 @@ static void writeAnnotatedClassList(OutputList &ol)
if (cd->isEmbeddedInOuterScope())
{
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
ol.disable(OutputGenerator::RTF);
}
if (cd->isLinkableInProject() && cd->templateMaster()==0)
@@ -2021,6 +2033,7 @@ static void writeAlphabeticalIndex(OutputList &ol)
if (annotatedClasses==0) return;
ol.pushGeneratorState();
ol.disableAllBut(OutputGenerator::Html);
+ ol.disable(OutputGenerator::Docbook);
LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassIndex);
QCString title = lne ? lne->title() : theTranslator->trCompoundIndex();
bool addToIndex = lne==0 || lne->visible();
@@ -2053,6 +2066,7 @@ static void writeAnnotatedIndex(OutputList &ol)
ol.pushGeneratorState();
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
if (annotatedClassesPrinted==0)
{
ol.disable(OutputGenerator::Latex);
@@ -3022,6 +3036,7 @@ static void writeExampleIndex(OutputList &ol)
if (Doxygen::exampleSDict->count()==0) return;
ol.pushGeneratorState();
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Examples);
QCString title = lne ? lne->title() : theTranslator->trExamples();
bool addToIndex = lne==0 || lne->visible();
@@ -3621,6 +3636,7 @@ static void writeGroupIndex(OutputList &ol)
ol.pushGeneratorState();
// 1.{
ol.disable(OutputGenerator::Man);
+ ol.disable(OutputGenerator::Docbook);
LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Modules);
QCString title = lne ? lne->title() : theTranslator->trModules();
bool addToIndex = lne==0 || lne->visible();
@@ -3910,6 +3926,7 @@ static void writeIndex(OutputList &ol)
// write LaTeX/RTF index
//--------------------------------------------------------------------
ol.enable(OutputGenerator::Latex);
+ ol.enable(OutputGenerator::Docbook);
ol.enable(OutputGenerator::RTF);
ol.startFile("refman",0,0);
@@ -3918,6 +3935,7 @@ static void writeIndex(OutputList &ol)
{
ol.disable(OutputGenerator::Latex);
}
+ ol.disable(OutputGenerator::Docbook);
if (projPrefix.isEmpty())
{
@@ -3939,6 +3957,7 @@ static void writeIndex(OutputList &ol)
ol.parseText(theTranslator->trGeneratedBy());
ol.endIndexSection(isTitlePageAuthor);
ol.enable(OutputGenerator::Latex);
+ ol.enable(OutputGenerator::Docbook);
ol.lastIndexPage();
if (Doxygen::mainPage)
@@ -3978,9 +3997,11 @@ static void writeIndex(OutputList &ol)
QCString title = pd->title();
if (title.isEmpty()) title=pd->name();
+ ol.disable(OutputGenerator::Docbook);
ol.startIndexSection(isPageDocumentation);
ol.parseText(title);
ol.endIndexSection(isPageDocumentation);
+ ol.enable(OutputGenerator::Docbook);
ol.pushGeneratorState(); // write TOC title (RTF only)
ol.disableAllBut(OutputGenerator::RTF);
@@ -4002,6 +4023,7 @@ static void writeIndex(OutputList &ol)
}
}
+ ol.disable(OutputGenerator::Docbook);
if (!Config_getBool(LATEX_HIDE_INDICES))
{
//if (indexedPages>0)
@@ -4049,6 +4071,8 @@ static void writeIndex(OutputList &ol)
ol.endIndexSection(isFileIndex);
}
}
+ ol.enable(OutputGenerator::Docbook);
+
if (documentedGroups>0)
{
ol.startIndexSection(isModuleDocumentation);
@@ -4285,6 +4309,9 @@ static void writeIndexHierarchyEntries(OutputList &ol,const QList<LayoutNavEntry
}
writeUserGroupStubPage(ol,lne);
break;
+ case LayoutNavEntry::None:
+ assert(kind != LayoutNavEntry::None); // should never happen, means not properly initialized
+ break;
}
if (kind!=LayoutNavEntry::User && kind!=LayoutNavEntry::UserGroup) // User entry may appear multiple times
{
@@ -4334,6 +4361,9 @@ static bool quickLinkVisible(LayoutNavEntry::Kind kind)
case LayoutNavEntry::FileGlobals: return documentedFileMembers[FMHL_All]>0;
//case LayoutNavEntry::Dirs: return documentedDirs>0;
case LayoutNavEntry::Examples: return Doxygen::exampleSDict->count()>0;
+ case LayoutNavEntry::None: // should never happen, means not properly initialized
+ assert(kind != LayoutNavEntry::None);
+ return FALSE;
}
return FALSE;
}
diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp
index 03f9872..7663572 100644
--- a/src/latexdocvisitor.cpp
+++ b/src/latexdocvisitor.cpp
@@ -33,6 +33,7 @@
#include "filedef.h"
#include "config.h"
#include "htmlentity.h"
+#include "emoji.h"
#include "plantuml.h"
const int maxLevels=5;
@@ -48,7 +49,7 @@ static const char *getSectionName(int level)
return secLabels[QMIN(maxLevels-1,l)];
}
-static void visitPreStart(FTextStream &t, const bool hasCaption, QCString name, QCString width, QCString height, const bool inlineImage = FALSE)
+static void visitPreStart(FTextStream &t, bool hasCaption, QCString name, QCString width, QCString height, bool inlineImage = FALSE)
{
if (inlineImage)
{
@@ -118,7 +119,7 @@ static void visitPreStart(FTextStream &t, const bool hasCaption, QCString name,
-static void visitPostEnd(FTextStream &t, const bool hasCaption, const bool inlineImage = FALSE)
+static void visitPostEnd(FTextStream &t, bool hasCaption, bool inlineImage = FALSE)
{
if (inlineImage)
{
@@ -239,18 +240,68 @@ void LatexDocVisitor::visit(DocSymbol *s)
}
}
+void LatexDocVisitor::visit(DocEmoji *s)
+{
+ if (m_hide) return;
+ const char *res_text = EmojiEntityMapper::instance()->text(s->emoji());
+ if (res_text)
+ {
+ const char *res_code = EmojiEntityMapper::instance()->code(s->emoji());
+ m_t << "\\doxygenemoji{";
+ filter(res_text);
+ m_t << "}{";
+ m_t << res_code;
+ m_t << "}{";
+ const char *p = res_code;
+ char res[10];
+ int i = 0;
+ bool first = TRUE;
+ while (*p)
+ {
+ switch(*p)
+ {
+ case '&': case '#': case 'x':
+ break;
+ case ';':
+ res[i] = '\0';
+ if (!first) m_t << "-";
+ m_t << res;
+ first = FALSE;
+ i = 0;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ res[i] = *p;
+ i++;
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ res[i] = *p -'a' + 'A'; // so it is uppercase
+ i++;
+ break;
+ }
+ p++;
+ }
+ m_t << "}";
+ }
+ else
+ {
+ err("LaTeX: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+}
+
void LatexDocVisitor::visit(DocURL *u)
{
if (m_hide) return;
if (Config_getBool(PDF_HYPERLINKS))
{
+ m_t << endl << "%% AME " << u->url() <<endl;
m_t << "\\href{";
if (u->isEmail()) m_t << "mailto:";
- m_t << u->url() << "}";
+ m_t << latexFilterURL(u->url()) << "}";
}
- m_t << "\\texttt{ ";
+ m_t << "{\\texttt{ ";
filter(u->url());
- m_t << "}";
+ m_t << "}}";
}
void LatexDocVisitor::visit(DocLineBreak *)
@@ -271,7 +322,13 @@ void LatexDocVisitor::visit(DocStyleChange *s)
switch (s->style())
{
case DocStyleChange::Bold:
- if (s->enable()) m_t << "{\\bfseries "; else m_t << "}";
+ if (s->enable()) m_t << "{\\bfseries{"; else m_t << "}}";
+ break;
+ case DocStyleChange::Strike:
+ if (s->enable()) m_t << "\\sout{"; else m_t << "}";
+ break;
+ case DocStyleChange::Underline:
+ if (s->enable()) m_t << "\\uline{"; else m_t << "}";
break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "{\\itshape "; else m_t << "}";
@@ -587,9 +644,9 @@ void LatexDocVisitor::visit(DocIndexEntry *i)
{
if (m_hide) return;
m_t << "\\index{";
- m_t << latexEscapeLabelName(i->entry(),false);
+ m_t << latexEscapeLabelName(i->entry());
m_t << "@{";
- m_t << latexEscapeIndexChars(i->entry(),false);
+ m_t << latexEscapeIndexChars(i->entry());
m_t << "}}";
}
@@ -1200,8 +1257,8 @@ void LatexDocVisitor::visitPre(DocHtmlCell *c)
m_t << "r|}{";
break;
case DocHtmlCell::Center:
- break;
m_t << "c|}{";
+ break;
default:
m_t << "l|}{";
break;
@@ -1274,17 +1331,18 @@ void LatexDocVisitor::visitPre(DocHRef *href)
if (m_hide) return;
if (Config_getBool(PDF_HYPERLINKS))
{
+ m_t << endl << "%% AME " << href->url() <<endl;
m_t << "\\href{";
- m_t << href->url();
+ m_t << latexFilterURL(href->url());
m_t << "}";
}
- m_t << "\\texttt{ ";
+ m_t << "{\\texttt{ ";
}
void LatexDocVisitor::visitPost(DocHRef *)
{
if (m_hide) return;
- m_t << "}";
+ m_t << "}}";
}
void LatexDocVisitor::visitPre(DocHtmlHeader *header)
diff --git a/src/latexdocvisitor.h b/src/latexdocvisitor.h
index 881863a..7ea8ae1 100644
--- a/src/latexdocvisitor.h
+++ b/src/latexdocvisitor.h
@@ -42,6 +42,7 @@ class LatexDocVisitor : public DocVisitor
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index 474d368..45b06bf 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -485,6 +485,10 @@ static void writeDefaultHeaderPart1(FTextStream &t)
if (Config_getBool(LATEX_BATCHMODE))
t << "\\batchmode\n";
+ // to overcome problems wit too many open files
+ t << "\\let\\mypdfximage\\pdfximage"
+ "\\def\\pdfximage{\\immediate\\mypdfximage}";
+
// Set document class depending on configuration
QCString documentClass;
if (Config_getBool(COMPACT_LATEX))
@@ -564,6 +568,18 @@ static void writeDefaultHeaderPart1(FTextStream &t)
"\\newcommand{\\+}{\\discretionary{\\mbox{\\scriptsize$\\hookleftarrow$}}{}{}}\n"
"\n";
+ QCString emojiDir=Config_getString(LATEX_EMOJI_DIRECTORY);
+ if (emojiDir.isEmpty()) emojiDir = ".";
+ emojiDir = substitute(emojiDir,"\\","/");
+ t << "% Arguments of doxygenemoji:\n"
+ "% 1) ':<text>:' form of the emoji, already \"LaTeX\"-escaped\n"
+ "% 2) unicode of the emoji inlorm like: 'U+1F603' or 'U+0031U+FE0FU+20E3' depending on the emoji\n"
+ "% 3) file name in form like: '1F603' or '0031-FE0F-20E3' depending on the emoji\n"
+ "% in case image exist use this otherwise use the ':<text>:' form\n";
+ t << "\\newcommand{\\doxygenemoji}[3]{%\n"
+ " \\IfFileExists{" << emojiDir << "/#3.png}{\\raisebox{-0.1em}{\\includegraphics[height=0.9em]{" << emojiDir << "/#3.png}}}{#1}%\n"
+ "}\n";
+
// Define page & text layout
QCString paperName=Config_getEnum(PAPER_TYPE);
// "a4wide" package is obsolete (see bug 563698)
@@ -1369,12 +1385,12 @@ void LatexGenerator::startHtmlLink(const char *url)
t << url;
t << "}";
}
- t << "\\texttt{ ";
+ t << "{\\texttt{ ";
}
void LatexGenerator::endHtmlLink()
{
- t << "}";
+ t << "}}";
}
//void LatexGenerator::writeMailLink(const char *url)
@@ -1519,9 +1535,9 @@ void LatexGenerator::endTitleHead(const char *fileName,const char *name)
if (name)
{
t << "\\label{" << stripPath(fileName) << "}\\index{";
- t << latexEscapeLabelName(name,insideTabbing);
+ t << latexEscapeLabelName(name);
t << "@{";
- t << latexEscapeIndexChars(name,insideTabbing);
+ t << latexEscapeIndexChars(name);
t << "}}" << endl;
}
}
@@ -1602,27 +1618,27 @@ void LatexGenerator::startMemberDoc(const char *clname,
t << "\\index{";
if (clname)
{
- t << latexEscapeLabelName(clname,insideTabbing);
+ t << latexEscapeLabelName(clname);
t << "@{";
- t << latexEscapeIndexChars(clname,insideTabbing);
+ t << latexEscapeIndexChars(clname);
t << "}!";
}
- t << latexEscapeLabelName(memname,insideTabbing);
+ t << latexEscapeLabelName(memname);
t << "@{";
- t << latexEscapeIndexChars(memname,insideTabbing);
+ t << latexEscapeIndexChars(memname);
t << "}}" << endl;
t << "\\index{";
- t << latexEscapeLabelName(memname,insideTabbing);
+ t << latexEscapeLabelName(memname);
t << "@{";
- t << latexEscapeIndexChars(memname,insideTabbing);
+ t << latexEscapeIndexChars(memname);
t << "}";
if (clname)
{
t << "!";
- t << latexEscapeLabelName(clname,insideTabbing);
+ t << latexEscapeLabelName(clname);
t << "@{";
- t << latexEscapeIndexChars(clname,insideTabbing);
+ t << latexEscapeIndexChars(clname);
t << "}";
}
t << "}" << endl;
@@ -1640,7 +1656,7 @@ void LatexGenerator::startMemberDoc(const char *clname,
{
t << "\\texorpdfstring{";
}
- t << latexEscapeIndexChars(title,insideTabbing);
+ t << latexEscapeIndexChars(title);
if (pdfHyperlinks)
{
t << "}{" << latexEscapePDFString(title) << "}";
@@ -1715,16 +1731,16 @@ void LatexGenerator::addIndexItem(const char *s1,const char *s2)
if (s1)
{
t << "\\index{";
- t << latexEscapeLabelName(s1,insideTabbing);
+ t << latexEscapeLabelName(s1);
t << "@{";
- t << latexEscapeIndexChars(s1,insideTabbing);
+ t << latexEscapeIndexChars(s1);
t << "}";
if (s2)
{
t << "!";
- t << latexEscapeLabelName(s2,insideTabbing);
+ t << latexEscapeLabelName(s2);
t << "@{";
- t << latexEscapeIndexChars(s2,insideTabbing);
+ t << latexEscapeIndexChars(s2);
t << "}";
}
t << "}";
@@ -2095,22 +2111,14 @@ void LatexGenerator::endDescItem()
}
}
-void LatexGenerator::startSimpleSect(SectionTypes,const char *file,
- const char *anchor,const char *title)
+void LatexGenerator::startExamples()
{
t << "\\begin{Desc}\n\\item[";
- if (file)
- {
- writeObjectLink(0,file,anchor,title);
- }
- else
- {
- docify(title);
- }
+ docify(theTranslator->trExamples());
t << "]";
}
-void LatexGenerator::endSimpleSect()
+void LatexGenerator::endExamples()
{
t << "\\end{Desc}" << endl;
}
@@ -2167,7 +2175,7 @@ void LatexGenerator::endParameterName(bool last,bool /*emptyList*/,bool closeBra
void LatexGenerator::exceptionEntry(const char* prefix,bool closeBracket)
{
if (prefix)
- t << " " << prefix;
+ t << " " << prefix << "(";
else if (closeBracket)
t << ")";
t << " ";
@@ -2230,11 +2238,9 @@ void LatexGenerator::startCodeFragment()
void LatexGenerator::endCodeFragment()
{
- //if (DoxyCodeOpen)
- //{
- // t << "}\n";
- // DoxyCodeOpen = FALSE;
- //}
+ //endCodeLine checks is there is still an open code line, if so closes it.
+ endCodeLine();
+
t << "\\end{DoxyCode}\n";
DoxyCodeOpen = FALSE;
}
diff --git a/src/latexgen.h b/src/latexgen.h
index 07c4080..1460000 100644
--- a/src/latexgen.h
+++ b/src/latexgen.h
@@ -235,8 +235,8 @@ class LatexGenerator : public OutputGenerator
const char *,const char *,const char *) {}
void startDescList(SectionTypes) { t << "\\begin{Desc}\n\\item["; }
void endDescList() { t << "\\end{Desc}" << endl; }
- void startSimpleSect(SectionTypes,const char *,const char *,const char *);
- void endSimpleSect();
+ void startExamples();
+ void endExamples();
void startParamList(ParamListTypes,const char *title);
void endParamList();
void startDescForItem() { t << "\\par" << endl; }
diff --git a/src/layout.cpp b/src/layout.cpp
index 1d9a5ed..a3849b5 100644
--- a/src/layout.cpp
+++ b/src/layout.cpp
@@ -1268,7 +1268,7 @@ class LayoutParser : public QXmlDefaultHandler
}
private:
- LayoutParser() : m_sHandler(163), m_eHandler(17), m_invalidEntry(FALSE) { }
+ LayoutParser() : m_sHandler(163), m_eHandler(17), m_invalidEntry(FALSE), m_part(0), m_rootNav(NULL) { }
~LayoutParser() { delete m_rootNav; }
QDict<StartElementHandler> m_sHandler;
diff --git a/src/layout.h b/src/layout.h
index 0b9ad9e..1906a3d 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -119,6 +119,7 @@ struct LayoutNavEntry
{
public:
enum Kind {
+ None = -1,
MainPage,
Pages,
Modules,
@@ -158,7 +159,7 @@ struct LayoutNavEntry
LayoutNavEntry *find(LayoutNavEntry::Kind k,const char *file=0) const;
private:
- LayoutNavEntry() : m_parent(0) {}
+ LayoutNavEntry() : m_parent(0), m_kind(None), m_visible(FALSE) {}
LayoutNavEntry *m_parent;
Kind m_kind;
bool m_visible;
diff --git a/src/mandocvisitor.cpp b/src/mandocvisitor.cpp
index 2233cc6..8a9e6c1 100644
--- a/src/mandocvisitor.cpp
+++ b/src/mandocvisitor.cpp
@@ -30,6 +30,7 @@
#include "parserintf.h"
#include "filedef.h"
#include "htmlentity.h"
+#include "emoji.h"
ManDocVisitor::ManDocVisitor(FTextStream &t,CodeOutputInterface &ci,
const char *langExt)
@@ -89,6 +90,22 @@ void ManDocVisitor::visit(DocSymbol *s)
m_firstCol=FALSE;
}
+void ManDocVisitor::visit(DocEmoji *s)
+{
+ if (m_hide) return;
+ const char *res = EmojiEntityMapper::instance()->man(s->emoji());
+ if (res)
+ {
+ m_t << res;
+ }
+ else
+ {
+ // no error or warning to be supplied
+ // err("man: non supported HTML-entity found: &%s;\n",get_symbol_item(s->emoji()));
+ }
+ m_firstCol=FALSE;
+}
+
void ManDocVisitor::visit(DocURL *u)
{
if (m_hide) return;
@@ -120,6 +137,13 @@ void ManDocVisitor::visit(DocStyleChange *s)
if (s->enable()) m_t << "\\fB"; else m_t << "\\fP";
m_firstCol=FALSE;
break;
+ case DocStyleChange::Strike:
+ /* not supported */
+ break;
+ case DocStyleChange::Underline: //underline is shown as emphasis
+ if (s->enable()) m_t << "\\fI"; else m_t << "\\fP";
+ m_firstCol=FALSE;
+ break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "\\fI"; else m_t << "\\fP";
m_firstCol=FALSE;
diff --git a/src/mandocvisitor.h b/src/mandocvisitor.h
index d248c87..8efc223 100644
--- a/src/mandocvisitor.h
+++ b/src/mandocvisitor.h
@@ -40,6 +40,7 @@ class ManDocVisitor : public DocVisitor
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
diff --git a/src/mangen.cpp b/src/mangen.cpp
index d23b2fe..b3ae732 100644
--- a/src/mangen.cpp
+++ b/src/mangen.cpp
@@ -34,7 +34,7 @@
static QCString getExtension()
{
/*
- * [.][nuber][rest]
+ * [.][number][rest]
* in case of . missing, just ignore it
* in case number missing, just place a 3 in front of it
*/
@@ -650,8 +650,25 @@ void ManGenerator::endSection(const char *,SectionInfo::SectionType type)
}
}
-void ManGenerator::startSimpleSect(SectionTypes,const char *,
- const char *,const char *title)
+void ManGenerator::startExamples()
+{
+ if (!firstCol)
+ { t << endl << ".PP" << endl;
+ firstCol=TRUE; paragraph=TRUE;
+ col=0;
+ }
+ paragraph=FALSE;
+ startBold();
+ docify(theTranslator->trExamples());
+ endBold();
+ paragraph=TRUE;
+}
+
+void ManGenerator::endExamples()
+{
+}
+
+void ManGenerator::startDescTable(const char *title)
{
if (!firstCol)
{ t << endl << ".PP" << endl;
@@ -663,10 +680,12 @@ void ManGenerator::startSimpleSect(SectionTypes,const char *,
docify(title);
endBold();
paragraph=TRUE;
+ startDescForItem();
}
-void ManGenerator::endSimpleSect()
+void ManGenerator::endDescTable()
{
+ endDescForItem();
}
void ManGenerator::startParamList(ParamListTypes,const char *title)
diff --git a/src/mangen.h b/src/mangen.h
index 0413ffd..e109355 100644
--- a/src/mangen.h
+++ b/src/mangen.h
@@ -169,8 +169,8 @@ class ManGenerator : public OutputGenerator
const char *,const char *,const char *) {}
void startDescList(SectionTypes);
void endDescList() {}
- void startSimpleSect(SectionTypes,const char *,const char *,const char *);
- void endSimpleSect();
+ void startExamples();
+ void endExamples();
void startParamList(ParamListTypes,const char *title);
void endParamList();
//void writeDescItem();
@@ -197,9 +197,8 @@ class ManGenerator : public OutputGenerator
void endContents() {}
void writeNonBreakableSpace(int n) { int i; for (i=0;i<n;i++) t << " "; }
- void startDescTable(const char *t)
- { startSimpleSect(EnumValues,0,0,t); startDescForItem(); }
- void endDescTable() { endDescForItem(); endSimpleSect(); }
+ void startDescTable(const char *t);
+ void endDescTable();
void startDescTableRow() {}
void endDescTableRow() {}
void startDescTableTitle() { startItemListItem(); startBold(); startEmphasis(); endItemListItem(); }
diff --git a/src/markdown.cpp b/src/markdown.cpp
index 0ca95a4..36b9734 100644
--- a/src/markdown.cpp
+++ b/src/markdown.cpp
@@ -76,7 +76,7 @@
// so for example *bla (*.txt) is cool*
#define ignoreCloseEmphChar(i) \
(data[i]=='(' || data[i]=='{' || data[i]=='[' || data[i]=='<' || \
- data[i]=='=' || data[i]=='+' || data[i]=='-' || data[i]=='\\' || \
+ data[i]=='\\' || \
data[i]=='@')
//----------
@@ -396,9 +396,11 @@ static int processEmphasis2(GrowBuf &out, const char *data, int size, char c)
data[i-1]!='\n'
)
{
- out.addStr("<strong>");
+ if (c == '~') out.addStr("<strike>");
+ else out.addStr("<strong>");
processInline(out,data,i);
- out.addStr("</strong>");
+ if (c == '~') out.addStr("</strike>");
+ else out.addStr("</strong>");
return i + 2;
}
i++;
@@ -406,7 +408,7 @@ static int processEmphasis2(GrowBuf &out, const char *data, int size, char c)
return 0;
}
-/** Parsing tripple emphasis.
+/** Parsing triple emphasis.
* Finds the first closing tag, and delegates to the other emph
*/
static int processEmphasis3(GrowBuf &out, const char *data, int size, char c)
@@ -616,7 +618,7 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size)
char c = data[0];
int ret;
- if (size>2 && data[1]!=c) // _bla or *bla
+ if (size>2 && c!='~' && data[1]!=c) // _bla or *bla
{
// whitespace cannot follow an opening emphasis
if (data[1]==' ' || data[1]=='\n' ||
@@ -635,7 +637,7 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size)
}
return ret+2;
}
- if (size>4 && data[1]==c && data[2]==c && data[3]!=c) // ___bla or ***bla
+ if (size>4 && c!='~' && data[1]==c && data[2]==c && data[3]!=c) // ___bla or ***bla
{
if (data[3]==' ' || data[3]=='\n' ||
(ret = processEmphasis3(out, data+3, size-3, c)) == 0)
@@ -647,6 +649,27 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size)
return 0;
}
+static void writeMarkdownImage(GrowBuf &out, const char *fmt, bool explicitTitle, QCString title, QCString content, QCString link, FileDef *fd)
+{
+ out.addStr("@image ");
+ out.addStr(fmt);
+ out.addStr(" ");
+ out.addStr(link.mid(fd ? 0 : 5));
+ if (!explicitTitle && !content.isEmpty())
+ {
+ out.addStr(" \"");
+ out.addStr(content);
+ out.addStr("\"");
+ }
+ else if ((content.isEmpty() || explicitTitle) && !title.isEmpty())
+ {
+ out.addStr(" \"");
+ out.addStr(title);
+ out.addStr("\"");
+ }
+ out.addStr("\n");
+}
+
static int processLink(GrowBuf &out,const char *data,int,int size)
{
QCString content;
@@ -854,20 +877,10 @@ static int processLink(GrowBuf &out,const char *data,int,int size)
(fd=findFileDef(Doxygen::imageNameDict,link,ambig)))
// assume doxygen symbol link or local image link
{
- out.addStr("@image html ");
- out.addStr(link.mid(fd ? 0 : 5));
- if (!explicitTitle && !content.isEmpty())
- {
- out.addStr(" \"");
- out.addStr(content);
- out.addStr("\"");
- }
- else if ((content.isEmpty() || explicitTitle) && !title.isEmpty())
- {
- out.addStr(" \"");
- out.addStr(title);
- out.addStr("\"");
- }
+ writeMarkdownImage(out, "html", explicitTitle, title, content, link, fd);
+ writeMarkdownImage(out, "latex", explicitTitle, title, content, link, fd);
+ writeMarkdownImage(out, "rtf", explicitTitle, title, content, link, fd);
+ writeMarkdownImage(out, "docbook", explicitTitle, title, content, link, fd);
}
else
{
@@ -1780,22 +1793,20 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size)
QCString cellTag("th"), cellClass("class=\"markdownTableHead");
for (unsigned row = 0; row < tableContents.size(); row++)
{
- out.addStr(" <tr class=\"markdownTable");
if (row)
{
- out.addStr("Body\"");
if (row % 2)
{
- out.addStr(" class=\"markdownTableRowOdd\">\n");
+ out.addStr("<tr class=\"markdownTableRowOdd\">\n");
}
else
{
- out.addStr(" class=\"markdownTableRowEven\">\n");
+ out.addStr("<tr class=\"markdownTableRowEven\">\n");
}
}
else
{
- out.addStr("Head\">\n");
+ out.addStr(" <tr class=\"markdownTableHead\">\n");
}
for (int c = 0; c < columns; c++)
{
@@ -1949,7 +1960,7 @@ void writeOneLineHeaderOrRuler(GrowBuf &out,const char *data,int size)
out.addStr(data,size);
if (hasLineBreak(data,size))
{
- out.addStr("<br>");
+ out.addStr("\n");
}
}
}
@@ -2515,6 +2526,7 @@ QCString processMarkdown(const QCString &fileName,const int lineNr,Entry *e,cons
// setup callback table for special characters
g_actions[(unsigned int)'_']=processEmphasis;
g_actions[(unsigned int)'*']=processEmphasis;
+ g_actions[(unsigned int)'~']=processEmphasis;
g_actions[(unsigned int)'`']=processCodeSpan;
g_actions[(unsigned int)'\\']=processSpecialCommand;
g_actions[(unsigned int)'@']=processSpecialCommand;
diff --git a/src/marshal.cpp b/src/marshal.cpp
index fa29aed..25a9a89 100644
--- a/src/marshal.cpp
+++ b/src/marshal.cpp
@@ -350,6 +350,7 @@ void marshalLocalToc(StorageIntf *s,const LocalToc &lt)
marshalInt(s,lt.htmlLevel());
marshalInt(s,lt.latexLevel());
marshalInt(s,lt.xmlLevel());
+ marshalInt(s,lt.docbookLevel());
}
void marshalEntry(StorageIntf *s,Entry *e)
@@ -369,6 +370,8 @@ void marshalEntry(StorageIntf *s,Entry *e)
marshalBool(s,e->subGrouping);
marshalBool(s,e->callGraph);
marshalBool(s,e->callerGraph);
+ marshalBool(s,e->referencedByRelation);
+ marshalBool(s,e->referencesRelation);
marshalInt(s,(int)e->virt);
marshalQCString(s,e->args);
marshalQCString(s,e->bitfields);
@@ -740,6 +743,7 @@ LocalToc unmarshalLocalToc(StorageIntf *s)
int htmlLevel = unmarshalInt(s);
int latexLevel = unmarshalInt(s);
int xmlLevel = unmarshalInt(s);
+ int docbookLevel = unmarshalInt(s);
if ((mask & (1<<LocalToc::Html))!=0)
{
result.enableHtml(htmlLevel);
@@ -752,6 +756,10 @@ LocalToc unmarshalLocalToc(StorageIntf *s)
{
result.enableXml(xmlLevel);
}
+ if ((mask & (1<<LocalToc::Docbook))!=0)
+ {
+ result.enableDocbook(docbookLevel);
+ }
return result;
}
@@ -774,6 +782,8 @@ Entry * unmarshalEntry(StorageIntf *s)
e->subGrouping = unmarshalBool(s);
e->callGraph = unmarshalBool(s);
e->callerGraph = unmarshalBool(s);
+ e->referencedByRelation = unmarshalBool(s);
+ e->referencesRelation = unmarshalBool(s);
e->virt = (Specifier)unmarshalInt(s);
e->args = unmarshalQCString(s);
e->bitfields = unmarshalQCString(s);
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index 819904f..8f57802 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -161,10 +161,12 @@ static bool writeDefArgumentList(OutputList &ol,Definition *scope,MemberDef *md)
//ol.disableAllBut(OutputGenerator::Html);
bool htmlOn = ol.isEnabled(OutputGenerator::Html);
bool latexOn = ol.isEnabled(OutputGenerator::Latex);
+ bool docbookOn = ol.isEnabled(OutputGenerator::Docbook);
{
// html and latex
if (htmlOn) ol.enable(OutputGenerator::Html);
if (latexOn) ol.enable(OutputGenerator::Latex);
+ if (docbookOn) ol.enable(OutputGenerator::Docbook);
ol.endMemberDocName();
ol.startParameterList(!md->isObjCMethod());
@@ -172,6 +174,7 @@ static bool writeDefArgumentList(OutputList &ol,Definition *scope,MemberDef *md)
ol.enableAll();
ol.disable(OutputGenerator::Html);
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
{
// other formats
if (!md->isObjCMethod()) ol.docify("("); // start argument list
@@ -270,6 +273,7 @@ static bool writeDefArgumentList(OutputList &ol,Definition *scope,MemberDef *md)
// ol.docify(" ");
//}
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
ol.disable(OutputGenerator::Html);
ol.docify(" "); /* man page */
if (htmlOn) ol.enable(OutputGenerator::Html);
@@ -277,12 +281,15 @@ static bool writeDefArgumentList(OutputList &ol,Definition *scope,MemberDef *md)
ol.startEmphasis();
ol.enable(OutputGenerator::Man);
if (latexOn) ol.enable(OutputGenerator::Latex);
+ if (docbookOn) ol.enable(OutputGenerator::Docbook);
if (a->name.isEmpty()) ol.docify(a->type); else ol.docify(a->name);
ol.disable(OutputGenerator::Man);
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
ol.endEmphasis();
ol.enable(OutputGenerator::Man);
if (latexOn) ol.enable(OutputGenerator::Latex);
+ if (docbookOn) ol.enable(OutputGenerator::Docbook);
}
if (!a->array.isEmpty())
{
@@ -338,10 +345,12 @@ static bool writeDefArgumentList(OutputList &ol,Definition *scope,MemberDef *md)
ol.pushGeneratorState();
ol.disable(OutputGenerator::Html);
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
if (!md->isObjCMethod()) ol.docify(")"); // end argument list
ol.enableAll();
if (htmlOn) ol.enable(OutputGenerator::Html);
if (latexOn) ol.enable(OutputGenerator::Latex);
+ if (docbookOn) ol.enable(OutputGenerator::Docbook);
if (first) ol.startParameterName(defArgList->count()<2);
ol.endParameterName(TRUE,defArgList->count()<2,!md->isObjCMethod());
ol.popGeneratorState();
@@ -575,6 +584,8 @@ class MemberDefImpl
bool annUsed;
bool hasCallGraph;
bool hasCallerGraph;
+ bool hasReferencedByRelation;
+ bool hasReferencesRelation;
bool explExt; // member was explicitly declared external
bool tspec; // member is a template specialization
bool groupHasDocs; // true if the entry that caused the grouping was documented
@@ -638,6 +649,8 @@ void MemberDefImpl::init(Definition *def,
defTmpArgLists=0;
hasCallGraph = FALSE;
hasCallerGraph = FALSE;
+ hasReferencedByRelation = FALSE;
+ hasReferencesRelation = FALSE;
initLines=0;
type=t;
if (mt==MemberType_Typedef) type.stripPrefix("typedef ");
@@ -1478,6 +1491,7 @@ void MemberDef::writeDeclaration(OutputList &ol,
ol.pushGeneratorState();
ol.disable(OutputGenerator::Man);
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
ol.docify("\n");
ol.popGeneratorState();
}
@@ -2309,11 +2323,11 @@ void MemberDef::_writeExamples(OutputList &ol)
// write the list of examples that use this member
if (hasExamples())
{
- ol.startSimpleSect(BaseOutputDocInterface::Examples,0,0,theTranslator->trExamples()+": ");
+ ol.startExamples();
ol.startDescForItem();
writeExample(ol,m_impl->exampleSDict);
ol.endDescForItem();
- ol.endSimpleSect();
+ ol.endExamples();
}
}
@@ -2346,8 +2360,6 @@ void MemberDef::_writeEnumValues(OutputList &ol,Definition *container,
{
if (first)
{
- //ol.startSimpleSect(BaseOutputDocInterface::EnumValues,0,0,theTranslator->trEnumerationValues()+": ");
- //ol.startDescForItem();
ol.startDescTable(theTranslator->trEnumerationValues());
}
@@ -2355,28 +2367,17 @@ void MemberDef::_writeEnumValues(OutputList &ol,Definition *container,
ol.addIndexItem(fmd->name(),ciname);
ol.addIndexItem(ciname,fmd->name());
- //Doxygen::indexList->addIndexItem(
- // ciname, // level1
- // fmd->name(), // level2
- // separateMemPages ? cfname : cfiname, // contRef
- // cfname, // memRef
- // fmd->anchor(), // anchor
- // fmd); // memberdef
Doxygen::indexList->addIndexItem(container,fmd);
- //ol.writeListItem();
ol.startDescTableTitle();
ol.startDoxyAnchor(cfname,cname,fmd->anchor(),fmd->name(),fmd->argsString());
first=FALSE;
- //ol.startEmphasis();
ol.docify(fmd->name());
- //ol.endEmphasis();
ol.disableAllBut(OutputGenerator::Man);
ol.writeString(" ");
ol.enableAll();
ol.endDoxyAnchor(cfname,fmd->anchor());
ol.endDescTableTitle();
- //ol.newParagraph();
ol.startDescTableData();
bool hasBrief = !fmd->briefDescription().isEmpty();
@@ -2407,11 +2408,7 @@ void MemberDef::_writeEnumValues(OutputList &ol,Definition *container,
}
if (!first)
{
- //ol.endItemList();
ol.endDescTable();
- //ol.endDescForItem();
- //ol.endSimpleSect();
- //ol.writeChar('\n');
}
}
}
@@ -2567,7 +2564,7 @@ void MemberDef::writeDocumentation(MemberList *ml,
QCString scopeName = scName;
QCString memAnchor = anchor();
- QCString ciname = container->name();
+ QCString ciname = container->displayName();
Definition *scopedContainer = container; // see bug 753608
if (container->definitionType()==TypeGroup)
{
@@ -2991,9 +2988,9 @@ void MemberDef::writeDocumentation(MemberList *ml,
_writeExamples(ol);
_writeTypeConstraints(ol);
writeSourceDef(ol,cname);
- writeSourceRefs(ol,cname);
- writeSourceReffedBy(ol,cname);
writeInlineCode(ol,cname);
+ if (hasReferencesRelation()) writeSourceRefs(ol,cname);
+ if (hasReferencedByRelation()) writeSourceReffedBy(ol,cname);
_writeCallGraph(ol);
_writeCallerGraph(ol);
@@ -3853,8 +3850,10 @@ void MemberDef::writeEnumDeclaration(OutputList &typeDecl,
typeDecl.pushGeneratorState();
typeDecl.disableAllBut(OutputGenerator::Html);
typeDecl.enable(OutputGenerator::Latex);
+ typeDecl.enable(OutputGenerator::Docbook);
typeDecl.lineBreak();
typeDecl.disable(OutputGenerator::Latex);
+ typeDecl.disable(OutputGenerator::Docbook);
typeDecl.writeString("&#160;&#160;");
typeDecl.popGeneratorState();
}
@@ -3965,6 +3964,18 @@ void MemberDef::enableCallerGraph(bool e)
if (e) Doxygen::parseSourcesNeeded = TRUE;
}
+void MemberDef::enableReferencedByRelation(bool e)
+{
+ m_impl->hasReferencedByRelation=e;
+ if (e) Doxygen::parseSourcesNeeded = TRUE;
+}
+
+void MemberDef::enableReferencesRelation(bool e)
+{
+ m_impl->hasReferencesRelation=e;
+ if (e) Doxygen::parseSourcesNeeded = TRUE;
+}
+
#if 0
bool MemberDef::protectionVisible() const
{
@@ -4597,6 +4608,16 @@ bool MemberDef::hasCallerGraph() const
return m_impl->hasCallerGraph;
}
+bool MemberDef::hasReferencedByRelation() const
+{
+ return m_impl->hasReferencedByRelation;
+}
+
+bool MemberDef::hasReferencesRelation() const
+{
+ return m_impl->hasReferencesRelation;
+}
+
MemberDef *MemberDef::templateMaster() const
{
return m_impl->templateMaster;
@@ -5109,6 +5130,11 @@ void combineDeclarationAndDefinition(MemberDef *mdec,MemberDef *mdef)
mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
+
+ mdef->enableReferencedByRelation(mdec->hasReferencedByRelation() || mdef->hasReferencedByRelation());
+ mdef->enableCallerGraph(mdec->hasReferencesRelation() || mdef->hasReferencesRelation());
+ mdec->enableReferencedByRelation(mdec->hasReferencedByRelation() || mdef->hasReferencedByRelation());
+ mdec->enableCallerGraph(mdec->hasReferencesRelation() || mdef->hasReferencesRelation());
}
}
}
diff --git a/src/memberdef.h b/src/memberdef.h
index bf7ea9a..e9524c6 100644
--- a/src/memberdef.h
+++ b/src/memberdef.h
@@ -237,6 +237,9 @@ class MemberDef : public Definition
bool hasCallGraph() const;
bool hasCallerGraph() const;
bool visibleMemberGroup(bool hideNoHeader);
+ // refrenced related members
+ bool hasReferencesRelation() const;
+ bool hasReferencedByRelation() const;
MemberDef *templateMaster() const;
QCString getScopeString() const;
@@ -349,6 +352,9 @@ class MemberDef : public Definition
void enableCallGraph(bool e);
void enableCallerGraph(bool e);
+ void enableReferencedByRelation(bool e);
+ void enableReferencesRelation(bool e);
+
void setTemplateMaster(MemberDef *mt);
void addListReference(Definition *d);
void setDocsForDefinition(bool b);
diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp
index d3eb0df..8e6c881 100644
--- a/src/namespacedef.cpp
+++ b/src/namespacedef.cpp
@@ -326,6 +326,7 @@ void NamespaceDef::writeTagFile(FTextStream &tagFile)
}
}
}
+ break;
case LayoutDocEntry::MemberDecl:
{
LayoutDocEntryMemberDecl *lmd = (LayoutDocEntryMemberDecl*)lde;
diff --git a/src/outputgen.h b/src/outputgen.h
index 44d34b8..a99cff3 100644
--- a/src/outputgen.h
+++ b/src/outputgen.h
@@ -145,7 +145,8 @@ class BaseOutputDocInterface : public CodeOutputInterface
Since, Date, Bug, Note,
Warning, Par, Deprecated, Pre,
Post, Invar, Remark, Attention,
- Todo, Test, RCS, */ EnumValues,
+ Todo, Test, RCS, */
+ EnumValues,
Examples
};
@@ -279,9 +280,8 @@ class BaseOutputDocInterface : public CodeOutputInterface
virtual void startSmall() = 0;
virtual void endSmall() = 0;
- virtual void startSimpleSect(SectionTypes t,const char *file,
- const char *anchor,const char *title) = 0;
- virtual void endSimpleSect() = 0;
+ virtual void startExamples() = 0;
+ virtual void endExamples() = 0;
virtual void startParamList(ParamListTypes t,const char *title) = 0;
virtual void endParamList() = 0;
@@ -322,7 +322,7 @@ class BaseOutputDocInterface : public CodeOutputInterface
class OutputGenerator : public BaseOutputDocInterface
{
public:
- enum OutputType { Html, Latex, Man, RTF, XML, DEF, Perl };
+ enum OutputType { Html, Latex, Man, RTF, XML, DEF, Perl , Docbook};
OutputGenerator();
virtual ~OutputGenerator();
diff --git a/src/outputlist.h b/src/outputlist.h
index 2e89101..5fd8017 100644
--- a/src/outputlist.h
+++ b/src/outputlist.h
@@ -321,11 +321,10 @@ class OutputList : public OutputDocInterface
const char *title,const char *name)
{ forall(&OutputGenerator::writeInheritedSectionTitle,id,ref,
file,anchor,title,name); }
- void startSimpleSect(SectionTypes t,const char *file,const char *anchor,
- const char *title)
- { forall(&OutputGenerator::startSimpleSect,t,file,anchor,title); }
- void endSimpleSect()
- { forall(&OutputGenerator::endSimpleSect); }
+ void startExamples()
+ { forall(&OutputGenerator::startExamples); }
+ void endExamples()
+ { forall(&OutputGenerator::endExamples); }
void startParamList(ParamListTypes t,const char *title)
{ forall(&OutputGenerator::startParamList,t,title); }
void endParamList()
diff --git a/src/pagedef.cpp b/src/pagedef.cpp
index 4721306..79a78d3 100644
--- a/src/pagedef.cpp
+++ b/src/pagedef.cpp
@@ -35,6 +35,7 @@ PageDef::PageDef(const char *f,int l,const char *n,
m_pageScope = 0;
m_nestingLevel = 0;
m_fileName = ::convertNameToFile(n,FALSE,TRUE);
+ m_showLineNo = FALSE;
}
PageDef::~PageDef()
@@ -186,6 +187,7 @@ void PageDef::writeDocumentation(OutputList &ol)
ol.pushGeneratorState();
//2.{
ol.disable(OutputGenerator::Latex);
+ ol.disable(OutputGenerator::Docbook);
ol.disable(OutputGenerator::RTF);
ol.disable(OutputGenerator::Man);
if (!title().isEmpty() && !name().isEmpty() && si!=0)
@@ -206,7 +208,7 @@ void PageDef::writeDocumentation(OutputList &ol)
ol.popGeneratorState();
//2.}
- if ((m_localToc.isHtmlEnabled() || m_localToc.isLatexEnabled()) && hasSections())
+ if ((m_localToc.isHtmlEnabled() || m_localToc.isLatexEnabled() || m_localToc.isDocbookEnabled()) && hasSections())
{
writeToc(ol, m_localToc);
}
@@ -268,6 +270,7 @@ void PageDef::writePageDocumentation(OutputList &ol)
ol.pushGeneratorState();
ol.disableAll();
ol.enable(OutputGenerator::Latex);
+ ol.enable(OutputGenerator::Docbook);
ol.enable(OutputGenerator::RTF);
PageSDict::Iterator pdi(*m_subPageDict);
@@ -329,3 +332,13 @@ void PageDef::setLocalToc(const LocalToc &lt)
{
m_localToc = lt;
}
+
+void PageDef::setShowLineNo(bool b)
+{
+ m_showLineNo = b;
+}
+
+bool PageDef::showLineNo() const
+{
+ return m_showLineNo;
+}
diff --git a/src/pagedef.h b/src/pagedef.h
index 27316cb..a0c3acb 100644
--- a/src/pagedef.h
+++ b/src/pagedef.h
@@ -35,6 +35,7 @@ class PageDef : public Definition
// setters
void setFileName(const char *name);
void setLocalToc(const LocalToc &tl);
+ void setShowLineNo(bool);
// getters
DefType definitionType() const { return TypePage; }
@@ -63,6 +64,7 @@ class PageDef : public Definition
void setPageScope(Definition *d){ m_pageScope = d; }
Definition *getPageScope() const { return m_pageScope; }
QCString displayName(bool=TRUE) const { return !m_title.isEmpty() ? m_title : Definition::name(); }
+ bool showLineNo() const;
void writeDocumentation(OutputList &ol);
void writeTagFile(FTextStream &);
@@ -76,6 +78,7 @@ class PageDef : public Definition
Definition *m_pageScope;
int m_nestingLevel;
LocalToc m_localToc;
+ bool m_showLineNo;
};
class PageSDict : public SDict<PageDef>
diff --git a/src/perlmodgen.cpp b/src/perlmodgen.cpp
index ef5cbc2..bd52810 100644
--- a/src/perlmodgen.cpp
+++ b/src/perlmodgen.cpp
@@ -43,6 +43,7 @@
#include "section.h"
#include "util.h"
#include "htmlentity.h"
+#include "emoji.h"
#define PERLOUTPUT_MAX_INDENTATION 40
@@ -299,6 +300,7 @@ public:
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
@@ -428,7 +430,7 @@ private:
};
PerlModDocVisitor::PerlModDocVisitor(PerlModOutput &output)
- : DocVisitor(DocVisitor_Other), m_output(output), m_textmode(false)
+ : DocVisitor(DocVisitor_Other), m_output(output), m_textmode(false), m_textblockstart(FALSE)
{
m_output.openList("doc");
}
@@ -609,6 +611,11 @@ void PerlModDocVisitor::visit(DocSymbol *sy)
err("perl: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(sy->symbol(),TRUE));
}
}
+void PerlModDocVisitor::visit(DocEmoji *sy)
+{
+ enterText();
+ m_output.add(EmojiEntityMapper::instance()->perl(sy->emoji()));
+}
void PerlModDocVisitor::visit(DocURL *u)
{
@@ -626,6 +633,8 @@ void PerlModDocVisitor::visit(DocStyleChange *s)
switch (s->style())
{
case DocStyleChange::Bold: style = "bold"; break;
+ case DocStyleChange::Strike: style = "strike"; break;
+ case DocStyleChange::Underline: style = "underline"; break;
case DocStyleChange::Italic: style = "italic"; break;
case DocStyleChange::Code: style = "code"; break;
case DocStyleChange::Subscript: style = "subscript"; break;
@@ -1254,6 +1263,7 @@ void PerlModDocVisitor::visitPre(DocParamSect *s)
err("unknown parameter section found\n");
break;
}
+ m_output.openHash();
openOther();
openSubBlock(type);
}
@@ -1262,6 +1272,7 @@ void PerlModDocVisitor::visitPost(DocParamSect *)
{
closeSubBlock();
closeOther();
+ m_output.closeHash();
}
void PerlModDocVisitor::visitPre(DocParamList *pl)
@@ -1605,7 +1616,7 @@ void PerlModGenerator::generatePerlModForMember(MemberDef *md,Definition *)
m_output.openList("parameters");
ArgumentList *declAl = md->declArgumentList();
ArgumentList *defAl = md->argumentList();
- if (declAl && declAl->count()>0)
+ if (declAl && defAl && declAl->count()>0)
{
ArgumentListIterator declAli(*declAl);
ArgumentListIterator defAli(*defAl);
diff --git a/src/plantuml.cpp b/src/plantuml.cpp
index 89e6e9e..ada035b 100644
--- a/src/plantuml.cpp
+++ b/src/plantuml.cpp
@@ -47,7 +47,7 @@ QCString writePlantUMLSource(const QCString &outDir,const QCString &fileName,con
}
QCString text = "@startuml\n";
text+=content;
- text+="@enduml\n";
+ text+="\n@enduml\n";
file.writeBlock( text, text.length() );
file.close();
return baseName;
diff --git a/src/printdocvisitor.h b/src/printdocvisitor.h
index 4d1d765..17d938e 100644
--- a/src/printdocvisitor.h
+++ b/src/printdocvisitor.h
@@ -22,6 +22,7 @@
#include <qglobal.h>
#include "docvisitor.h"
#include "htmlentity.h"
+#include "emoji.h"
#include "message.h"
/*! Concrete visitor implementation for pretty printing */
@@ -68,6 +69,19 @@ class PrintDocVisitor : public DocVisitor
printf("print: non supported HTML-entity found: %s\n",HtmlEntityMapper::instance()->html(s->symbol(),TRUE));
}
}
+ void visit(DocEmoji *s)
+ {
+ indent_leaf();
+ const char *res = EmojiEntityMapper::instance()->utf8(s->emoji());
+ if (res)
+ {
+ printf("%s",res);
+ }
+ else
+ {
+ printf("print: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+ }
void visit(DocURL *u)
{
indent_leaf();
@@ -91,6 +105,12 @@ class PrintDocVisitor : public DocVisitor
case DocStyleChange::Bold:
if (s->enable()) printf("<bold>"); else printf("</bold>");
break;
+ case DocStyleChange::Strike:
+ if (s->enable()) printf("<strike>"); else printf("</strike>");
+ break;
+ case DocStyleChange::Underline:
+ if (s->enable()) printf("<underline>"); else printf("</underline>");
+ break;
case DocStyleChange::Italic:
if (s->enable()) printf("<italic>"); else printf("</italic>");
break;
@@ -634,13 +654,13 @@ class PrintDocVisitor : public DocVisitor
void visitPre(DocXRefItem *x)
{
indent_pre();
- printf("<xrefitem file=\"%s\" anchor=\"%s\" title=\"%s\"/>\n",
+ printf("<xrefitem file=\"%s\" anchor=\"%s\" title=\"%s\">\n",
x->file().data(),x->anchor().data(),x->title().data());
}
void visitPost(DocXRefItem *)
{
indent_post();
- printf("<xrefitem/>\n");
+ printf("</xrefitem>\n");
}
void visitPre(DocInternalRef *r)
{
diff --git a/src/pycode.l b/src/pycode.l
index 1b176d6..dfa383f 100644
--- a/src/pycode.l
+++ b/src/pycode.l
@@ -1311,7 +1311,7 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUT
\\. { // espaced char
codify(yytext);
}
- {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // tripple double quotes
+ {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // triple double quotes
codify(yytext);
}
"'" { // end of the string
@@ -1334,7 +1334,7 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUT
\\. { // espaced char
codify(yytext);
}
- {STRINGPREFIX}?{TRISINGLEQUOTE} { // tripple single quotes
+ {STRINGPREFIX}?{TRISINGLEQUOTE} { // triple single quotes
codify(yytext);
}
"\"" { // end of the string
diff --git a/src/pyscanner.l b/src/pyscanner.l
index 4718e3b..aed1ede 100644
--- a/src/pyscanner.l
+++ b/src/pyscanner.l
@@ -118,6 +118,8 @@ static bool g_packageCommentAllowed;
static bool g_start_init = FALSE;
static int g_search_count = 0;
+static QCString g_argType = "";
+static bool g_funcParamsEnd;
//-----------------------------------------------------------------------------
@@ -513,6 +515,8 @@ STARTDOCSYMS "##"
%x FunctionDec
%x FunctionParams
%x FunctionBody
+%x FunctionAnnotation
+%x FunctionTypeAnnotation
%x FunctionParamDefVal
/* Class states */
@@ -932,7 +936,6 @@ STARTDOCSYMS "##"
}
<FunctionDec>{
-
{IDENTIFIER} {
//found function name
if (current->type.isEmpty())
@@ -943,47 +946,59 @@ STARTDOCSYMS "##"
current->name = current->name.stripWhiteSpace();
newFunction();
}
- {B}":" { // function without arguments
+ {B}":"{B} { // function without arguments
g_specialBlock = TRUE; // expecting a docstring
bodyEntry = current;
current->bodyLine = yyLineNr;
- BEGIN( FunctionBody );
+ BEGIN(FunctionBody);
}
+ "->" {
+ g_defVal.resize(0);
+ g_braceCount = 0;
+ BEGIN(FunctionTypeAnnotation);
+ }
{B}"(" {
- BEGIN( FunctionParams );
+ g_funcParamsEnd = FALSE;
+ BEGIN(FunctionParams);
}
+ ")" { // end of parameter list
+ current->args = argListToString(current->argList);
+ g_funcParamsEnd = TRUE;
+ }
}
<FunctionParams>{
({BB}|",") {
}
+ [\*]+ {
+ g_argType = yytext;
+ }
{IDENTIFIER} { // Name of parameter
lineCount();
Argument *a = new Argument;
current->argList->append(a);
current->argList->getLast()->name = QCString(yytext).stripWhiteSpace();
- current->argList->getLast()->type = "";
+ current->argList->getLast()->type = g_argType;
+ g_argType = "";
}
"=" { // default value
// TODO: this rule is too simple, need to be able to
// match things like =")" as well!
g_defVal.resize(0);
- g_braceCount=0;
+ g_braceCount = 0;
BEGIN(FunctionParamDefVal);
}
-
- ")" { // end of parameter list
- current->args = argListToString(current->argList);
+ ")" {
+ unput(*yytext);
+ BEGIN(FunctionDec);
}
-
":"{B} {
- g_specialBlock = TRUE; // expecting a docstring
- bodyEntry = current;
- current->bodyLine = yyLineNr;
- BEGIN( FunctionBody );
- }
+ g_defVal.resize(0);
+ g_braceCount = 0;
+ BEGIN(FunctionAnnotation);
+ }
{POUNDCOMMENT} { // a comment
}
{PARAMNONEMPTY} { // Default rule inside arguments.
@@ -991,31 +1006,131 @@ STARTDOCSYMS "##"
}
+<FunctionTypeAnnotation>{
+ "{" |
+ "[" |
+ "(" {
+ ++g_braceCount;
+ g_defVal+=*yytext;
+ }
+ "}" |
+ "]" |
+ ")" {
+ --g_braceCount;
+ g_defVal+=*yytext;
+ }
+ ":" {
+ if (g_braceCount == 0)
+ {
+ current->type = g_defVal.data();
+ unput(*yytext);
+ BEGIN(FunctionDec);
+ }
+ else
+ g_defVal+=*yytext;
+ }
+ "'" {
+ g_defVal+=*yytext;
+ g_copyString=&g_defVal;
+ g_stringContext=FunctionTypeAnnotation;
+ BEGIN(SingleQuoteString);
+ }
+ "\"" {
+ g_defVal+=*yytext;
+ g_copyString=&g_defVal;
+ g_stringContext=FunctionTypeAnnotation;
+ BEGIN(DoubleQuoteString);
+ }
+ \n {
+ g_defVal+=*yytext;
+ incLineNr();
+ }
+ . {
+ g_defVal+=*yytext;
+ }
+}
+
+<FunctionAnnotation>{
+ "{" |
+ "[" |
+ "(" {
+ ++g_braceCount;
+ g_defVal+=*yytext;
+ }
+ "}" |
+ "]" {
+ --g_braceCount;
+ g_defVal+=*yytext;
+ }
+ ")" |
+ "=" |
+ "," {
+ if (g_braceCount == 0)
+ {
+ if (current->argList->getLast())
+ current->argList->getLast()->type += g_defVal.data();
+ if (*yytext != ',')
+ unput(*yytext);
+ BEGIN(FunctionParams);
+ }
+ else
+ {
+ if (*yytext == ')')
+ --g_braceCount;
+ g_defVal += *yytext;
+ }
+ }
+ "'" {
+ g_defVal+=*yytext;
+ g_copyString=&g_defVal;
+ g_stringContext=FunctionAnnotation;
+ BEGIN(SingleQuoteString);
+ }
+ "\"" {
+ g_defVal+=*yytext;
+ g_copyString=&g_defVal;
+ g_stringContext=FunctionAnnotation;
+ BEGIN(DoubleQuoteString);
+ }
+ \n {
+ g_defVal+=*yytext;
+ incLineNr();
+ }
+ . {
+ g_defVal+=*yytext;
+ }
+}
+
<FunctionParamDefVal>{
+ "{" |
"[" |
"(" { // internal opening brace, assumption is that we have correct code so braces do match
- g_braceCount++;
+ ++g_braceCount;
g_defVal+=*yytext;
}
- "," |
- "]" |
- ")" {
- if (g_braceCount==0) // end of default argument
+ "}" |
+ "]" {
+ --g_braceCount;
+ g_defVal+=*yytext;
+ }
+ ")" |
+ "," {
+ if (g_braceCount == 0)
{
if (current->argList->getLast())
- {
current->argList->getLast()->defval=QCString(g_defVal.data()).stripWhiteSpace();
- }
- if (*yytext != ',')
- current->args = argListToString(current->argList);
+ if (*yytext == ')')
+ unput(*yytext);
BEGIN(FunctionParams);
}
- else // continue
- {
- if (*yytext != ',')g_braceCount--;
- g_defVal+=*yytext;
- }
+ else
+ {
+ if (*yytext == ')')
+ --g_braceCount;
+ g_defVal += *yytext;
+ }
}
+
"'" {
g_defVal+=*yytext;
g_copyString=&g_defVal;
@@ -1396,7 +1511,6 @@ STARTDOCSYMS "##"
BEGIN(Search);
}
<<EOF>> { yyterminate();
- newEntry();
}
}
@@ -1425,7 +1539,7 @@ STARTDOCSYMS "##"
actualDoc.prepend("\\verbatim ");
actualDoc.append("\\endverbatim ");
}
- actualDoc.prepend("\\namespace "+g_moduleScope+"\\_linebr ");
+ actualDoc.prepend("\\namespace "+g_moduleScope+" ");
handleCommentBlock(actualDoc, FALSE);
}
if ((docBlockContext==ClassBody /*&& !g_hideClassDocs*/) ||
@@ -1508,7 +1622,7 @@ STARTDOCSYMS "##"
\\. { // espaced char
addToString(yytext);
}
- "\"\"\"" { // tripple double quotes
+ "\"\"\"" { // triple double quotes
addToString(yytext);
}
"'" { // end of the string
@@ -1531,7 +1645,7 @@ STARTDOCSYMS "##"
\\. { // espaced char
addToString(yytext);
}
- "'''" { // tripple single quotes
+ "'''" { // triple single quotes
addToString(yytext);
}
"\"" { // end of the string
diff --git a/src/qhp.cpp b/src/qhp.cpp
index e7c8d10..6ce6b06 100644
--- a/src/qhp.cpp
+++ b/src/qhp.cpp
@@ -23,7 +23,7 @@
#include "doxygen.h"
#include "filedef.h"
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include <string.h>
#include <qfile.h>
@@ -101,10 +101,10 @@ void Qhp::initialize()
{ "name", filterName, 0 };
m_doc.open("customFilter", tagAttributes);
- QStringList customFilterAttributes = QStringList::split(QChar(' '), Config_getString(QHP_CUST_FILTER_ATTRS));
+ QCStringList customFilterAttributes = QCStringList::split(' ', Config_getString(QHP_CUST_FILTER_ATTRS));
for (int i = 0; i < (int)customFilterAttributes.count(); i++)
{
- m_doc.openCloseContent("filterAttribute", customFilterAttributes[i].utf8());
+ m_doc.openCloseContent("filterAttribute", customFilterAttributes[i]);
}
m_doc.close("customFilter");
}
@@ -112,15 +112,15 @@ void Qhp::initialize()
m_doc.open("filterSection");
// Add section attributes
- QStringList sectionFilterAttributes = QStringList::split(QChar(' '),
+ QCStringList sectionFilterAttributes = QCStringList::split(' ',
Config_getString(QHP_SECT_FILTER_ATTRS));
- if (!sectionFilterAttributes.contains(QString("doxygen")))
+ if (!sectionFilterAttributes.contains("doxygen"))
{
sectionFilterAttributes << "doxygen";
}
for (int i = 0; i < (int)sectionFilterAttributes.count(); i++)
{
- m_doc.openCloseContent("filterAttribute", sectionFilterAttributes[i].utf8());
+ m_doc.openCloseContent("filterAttribute", sectionFilterAttributes[i]);
}
m_toc.open("toc");
diff --git a/src/reflist.cpp b/src/reflist.cpp
index 1da603e..7ae4c80 100644
--- a/src/reflist.cpp
+++ b/src/reflist.cpp
@@ -131,7 +131,15 @@ void RefList::insertIntoList(const char *key,RefItem *item)
{
if (ri!=item)
{
- ri->extraItems.append(item);
+ // We also have to check if the item is not already in the "extra" list
+ QListIterator<RefItem> li(ri->extraItems);
+ RefItem *extraItem;
+ bool doubleItem = false;
+ for (li.toFirst();(extraItem=li.current());++li)
+ {
+ if (item == extraItem) doubleItem = true;
+ }
+ if (!doubleItem) ri->extraItems.append(item);
}
}
}
@@ -148,8 +156,6 @@ void RefList::generatePage()
for (it.toFirst();(item=it.current());++it)
{
doc += " <dt>";
- doc += "\\anchor ";
- doc += item->listAnchor;
doc += "\n";
if (item->scope)
{
@@ -171,15 +177,21 @@ void RefList::generatePage()
if (!item->args.isEmpty())
{
// escape @'s in argument list, needed for Java annotations (see issue #6208)
- doc += substitute(item->args,"@","@@");
+ // escape \'s in argument list (see issue #6533)
+ doc += substitute(substitute(item->args,"@","@@"),"\\","\\\\");
}
- doc += "</dt><dd> ";
+ doc += "</dt><dd> \\anchor ";
+ doc += item->listAnchor;
+ doc += " ";
doc += item->text;
QListIterator<RefItem> li(item->extraItems);
RefItem *extraItem;
for (li.toFirst();(extraItem=li.current());++li)
{
- doc += "<p>" + extraItem->text;
+ doc += "<p> \\anchor ";
+ doc += extraItem->listAnchor;
+ doc += " ";
+ doc += extraItem->text;
}
doc += "</dd>";
}
diff --git a/src/res2cc_cmd.py b/src/res2cc_cmd.py
index 7e0322d..86d999d 100755
--- a/src/res2cc_cmd.py
+++ b/src/res2cc_cmd.py
@@ -98,10 +98,11 @@ def main():
directory = sys.argv[1]
files = []
for dirName, subdirList, fileList in walk(directory):
- for fname in sorted(fileList):
+ for fname in fileList:
subdir = dirName[len(directory)+1:] if dirName.startswith(directory) else dirName
if subdir:
files.append(File.factory(directory,subdir,fname))
+ files.sort(key=lambda f: f.subdir + "/" + f.fileName)
outputFile = open(sys.argv[2],"w")
print("#include \"resourcemgr.h\"\n",file=outputFile)
for f in files:
diff --git a/src/rtfdocvisitor.cpp b/src/rtfdocvisitor.cpp
index fa7fb64..658950a 100644
--- a/src/rtfdocvisitor.cpp
+++ b/src/rtfdocvisitor.cpp
@@ -34,6 +34,7 @@
#include "filedef.h"
#include "config.h"
#include "htmlentity.h"
+#include "emoji.h"
#include "plantuml.h"
//#define DBG_RTF(x) m_t << x
@@ -136,6 +137,48 @@ void RTFDocVisitor::visit(DocSymbol *s)
m_lastIsPara=FALSE;
}
+void RTFDocVisitor::visit(DocEmoji *s)
+{
+ if (m_hide) return;
+ DBG_RTF("{\\comment RTFDocVisitor::visit(DocEmoji)}\n");
+ const char *res = EmojiEntityMapper::instance()->rtf(s->emoji());
+ if (res)
+ {
+ const char *p = res;
+ int val = 0;
+ int val1 = 0;
+ while (*p)
+ {
+ switch(*p)
+ {
+ case '&': case '#': case 'x':
+ break;
+ case ';':
+ val1 = val;
+ val = 0xd800 + ( ( val1 - 0x10000 ) & 0xffc00 ) / 0x400 - 0x10000;
+ m_t << "\\u" << val << "?";
+ val = 0xdC00 + ( ( val1 - 0x10000 ) & 0x3ff ) - 0x10000 ;
+ m_t << "\\u" << val << "?";
+ val = 0;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ val = val * 16 + *p - '0';
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ val = val * 16 + *p - 'a' + 10;
+ break;
+ }
+ p++;
+ }
+ }
+ else
+ {
+ err("RTF: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+ m_lastIsPara=FALSE;
+}
+
void RTFDocVisitor::visit(DocURL *u)
{
if (m_hide) return;
@@ -192,6 +235,12 @@ void RTFDocVisitor::visit(DocStyleChange *s)
case DocStyleChange::Bold:
if (s->enable()) m_t << "{\\b "; else m_t << "} ";
break;
+ case DocStyleChange::Strike:
+ if (s->enable()) m_t << "{\\strike "; else m_t << "} ";
+ break;
+ case DocStyleChange::Underline:
+ if (s->enable()) m_t << "{\\ul "; else m_t << "} ";
+ break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "{\\i "; else m_t << "} ";
break;
@@ -1066,7 +1115,7 @@ void RTFDocVisitor::visitPre(DocHtmlHeader *header)
m_t << "{" // start section
<< rtf_Style_Reset;
QCString heading;
- int level = QMIN(header->level()+2,4);
+ int level = QMIN(header->level(),5);
heading.sprintf("Heading%d",level);
// set style
m_t << rtf_Style[heading]->reference;
@@ -1090,7 +1139,7 @@ void RTFDocVisitor::visitPre(DocImage *img)
DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocImage)}\n");
includePicturePreRTF(img->name(), img->type()==DocImage::Rtf, img->hasCaption(), img->isInlineImage());
}
-void RTFDocVisitor::includePicturePreRTF(const QCString name, const bool isTypeRTF, const bool hasCaption, const bool inlineImage)
+void RTFDocVisitor::includePicturePreRTF(const QCString name, bool isTypeRTF, bool hasCaption, bool inlineImage)
{
if (isTypeRTF)
{
@@ -1133,7 +1182,7 @@ void RTFDocVisitor::visitPost(DocImage *img)
includePicturePostRTF(img->type()==DocImage::Rtf, img->hasCaption(), img->isInlineImage());
}
-void RTFDocVisitor::includePicturePostRTF(const bool isTypeRTF, const bool hasCaption, const bool inlineImage)
+void RTFDocVisitor::includePicturePostRTF(bool isTypeRTF, bool hasCaption, bool inlineImage)
{
if (isTypeRTF)
{
@@ -1768,7 +1817,7 @@ void RTFDocVisitor::writeDotFile(DocDotFile *df)
{
writeDotFile(df->file(), df->hasCaption());
}
-void RTFDocVisitor::writeDotFile(const QCString &filename, const bool hasCaption)
+void RTFDocVisitor::writeDotFile(const QCString &filename, bool hasCaption)
{
QCString baseName=filename;
int i;
@@ -1786,7 +1835,7 @@ void RTFDocVisitor::writeMscFile(DocMscFile *df)
{
writeMscFile(df->file(), df->hasCaption());
}
-void RTFDocVisitor::writeMscFile(const QCString &fileName, const bool hasCaption)
+void RTFDocVisitor::writeMscFile(const QCString &fileName, bool hasCaption)
{
QCString baseName=fileName;
int i;
@@ -1812,7 +1861,7 @@ void RTFDocVisitor::writeDiaFile(DocDiaFile *df)
includePicturePreRTF(baseName + ".png", true, df->hasCaption());
}
-void RTFDocVisitor::writePlantUMLFile(const QCString &fileName, const bool hasCaption)
+void RTFDocVisitor::writePlantUMLFile(const QCString &fileName, bool hasCaption)
{
QCString baseName=fileName;
int i;
diff --git a/src/rtfdocvisitor.h b/src/rtfdocvisitor.h
index ad82067..b7cc3ea 100644
--- a/src/rtfdocvisitor.h
+++ b/src/rtfdocvisitor.h
@@ -40,6 +40,7 @@ class RTFDocVisitor : public DocVisitor
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
@@ -152,14 +153,14 @@ class RTFDocVisitor : public DocVisitor
void pushEnabled();
void popEnabled();
- void includePicturePreRTF(const QCString name, const bool isTypeRTF, const bool hasCaption, const bool inlineImage = FALSE);
- void includePicturePostRTF(const bool isTypeRTF, const bool hasCaption, const bool inlineImage = FALSE);
- void writeDotFile(const QCString &fileName, const bool hasCaption);
+ void includePicturePreRTF(const QCString name, bool isTypeRTF, bool hasCaption, bool inlineImage = FALSE);
+ void includePicturePostRTF(bool isTypeRTF, bool hasCaption, bool inlineImage = FALSE);
+ void writeDotFile(const QCString &fileName, bool hasCaption);
void writeDotFile(DocDotFile *);
- void writeMscFile(const QCString &fileName, const bool hasCaption);
+ void writeMscFile(const QCString &fileName, bool hasCaption);
void writeMscFile(DocMscFile *);
void writeDiaFile(DocDiaFile *);
- void writePlantUMLFile(const QCString &fileName, const bool hasCaption);
+ void writePlantUMLFile(const QCString &fileName, bool hasCaption);
//--------------------------------------
// state variables
diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp
index 64da929..34af705 100644
--- a/src/rtfgen.cpp
+++ b/src/rtfgen.cpp
@@ -2180,11 +2180,12 @@ void RTFGenerator::newParagraph()
m_omitParagraph = FALSE;
}
-void RTFGenerator::startParagraph(const char *)
+void RTFGenerator::startParagraph(const char *txt)
{
DBG_RTF(t << "{\\comment startParagraph}" << endl)
newParagraph();
t << "{" << endl;
+ if (QCString(txt) == "reference") t << "\\ql" << endl;
}
void RTFGenerator::endParagraph()
@@ -2632,7 +2633,7 @@ void testRTFOutput(const char *name)
err:
err("RTF integrity test failed at line %d of %s due to a bracket mismatch.\n"
" Please try to create a small code example that produces this error \n"
- " and send that to dimitri@stack.nl.\n",line,name);
+ " and send that to doxygen@gmail.com.\n",line,name);
}
/**
@@ -2727,21 +2728,14 @@ void RTFGenerator::endMemberGroup(bool hasHeader)
t << "}";
}
-void RTFGenerator::startSimpleSect(SectionTypes,const char *file,const char *anchor,const char *title)
+void RTFGenerator::startExamples()
{
- DBG_RTF(t << "{\\comment (startSimpleSect)}" << endl)
+ DBG_RTF(t << "{\\comment (startExamples)}" << endl)
t << "{"; // ends at endDescList
t << "{"; // ends at endDescTitle
startBold();
newParagraph();
- if (file)
- {
- writeObjectLink(0,file,anchor,title);
- }
- else
- {
- docify(title);
- }
+ docify(theTranslator->trExamples());
endBold();
t << "}";
newParagraph();
@@ -2749,9 +2743,9 @@ void RTFGenerator::startSimpleSect(SectionTypes,const char *file,const char *anc
t << rtf_Style_Reset << rtf_DList_DepthStyle();
}
-void RTFGenerator::endSimpleSect()
+void RTFGenerator::endExamples()
{
- DBG_RTF(t << "{\\comment (endSimpleSect)}" << endl)
+ DBG_RTF(t << "{\\comment (endExamples)}" << endl)
m_omitParagraph = FALSE;
newParagraph();
decrementIndentLevel();
@@ -2802,7 +2796,7 @@ void RTFGenerator::exceptionEntry(const char* prefix,bool closeBracket)
{
DBG_RTF(t << "{\\comment (exceptionEntry)}" << endl)
if (prefix)
- t << " " << prefix;
+ t << " " << prefix << "(";
else if (closeBracket)
t << ")";
t << " ";
diff --git a/src/rtfgen.h b/src/rtfgen.h
index bb3146a..b6b32c7 100644
--- a/src/rtfgen.h
+++ b/src/rtfgen.h
@@ -164,8 +164,8 @@ class RTFGenerator : public OutputGenerator
void writeInheritedSectionTitle(const char *,const char *,const char *,
const char *,const char *,const char *) {}
void startDescList(SectionTypes);
- void startSimpleSect(SectionTypes,const char *,const char *,const char *);
- void endSimpleSect();
+ void startExamples();
+ void endExamples();
void startParamList(ParamListTypes,const char *);
void endParamList();
//void writeDescItem();
diff --git a/src/scanner.l b/src/scanner.l
index 4846132..e9fca43 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -597,15 +597,11 @@ static int yyread(char *buf,int max_size)
/* start command character */
CMD ("\\"|"@")
-SECTIONCMD {CMD}("image"|"author"|"internal"|"version"|"date"|"deprecated"|"param"|"exception"|"return"[s]?|"retval"|"bug"|"warning"|"par"|"sa"|"see"|"pre"|"post"|"invariant"|"note"|"remark"[s]?|"todo"|"test"|"xrefitem"|"ingroup"|"callgraph"|"callergraph"|"latexonly"|"htmlonly"|"xmlonly"|"docbookonly"|"manonly"|"{"|"verbatim"|"dotfile"|"dot"|"defgroup"|"addtogroup"|"weakgroup"|"class"|"namespace"|"union"|"struct"|"fn"|"var"|"details"|"typedef"|"def"|"overload")|("<"{PRE}">")
BN [ \t\n\r]
BL [ \t\r]*"\n"
B [ \t]
-BS ^(({B}*"//")?)(({B}*"*"+)?){B}*
ID "$"?[a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*
-SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?)
SCOPENAME "$"?(({ID}?{BN}*"::"{BN}*)*)(((~|!){BN}*)?{ID})
-PHPSCOPENAME ({ID}"\\")+{ID}
TSCOPE {ID}("<"[a-z_A-Z0-9 \t\*\&,:]*">")?
CSSCOPENAME (({ID}?{BN}*"."{BN}*)*)((~{BN}*)?{ID})
PRE [pP][rR][eE]
@@ -3079,6 +3075,10 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
*pCopyQuotedGString+=*yytext;
BEGIN( lastStringContext );
}
+<CopyGString,CopyPHPGString>"<?php" { // we had an odd number of quotes.
+ *pCopyQuotedGString += yytext;
+ BEGIN( lastStringContext );
+ }
<CopyGString,CopyPHPGString>"/*"|"*/"|"//" {
*pCopyQuotedGString+=yytext;
}
@@ -3840,6 +3840,28 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
else
{
current->endBodyLine = yyLineNr;
+ if (current->section == Entry::NAMESPACE_SEC && current->type == "namespace")
+ {
+ int split_point;
+ while ((split_point = current->name.find("::")) != -1)
+ {
+ Entry *new_current = new Entry(*current);
+ current->program = "";
+ new_current->doc = "";
+ new_current->docLine = 0;
+ new_current->docFile = "";
+ new_current->brief = "";
+ new_current->briefLine = 0;
+ new_current->briefFile = "";
+ new_current->name = current->name.mid(split_point + 2);
+ current->name = current->name.left(split_point);
+ if (!current_root->name.isEmpty()) current->name.prepend(current_root->name+"::");
+
+ current_root->addSubEntry(current);
+ current_root = current;
+ current = new_current;
+ }
+ }
QCString &cn = current->name;
QCString rn = current_root->name.copy();
//printf("cn=`%s' rn=`%s' isTypedef=%d\n",cn.data(),rn.data(),isTypedef);
diff --git a/src/sqlite3gen.cpp b/src/sqlite3gen.cpp
index 6cd9581..a7b8dbb 100644
--- a/src/sqlite3gen.cpp
+++ b/src/sqlite3gen.cpp
@@ -23,11 +23,15 @@
#include "qtbc.h"
#include "sqlite3gen.h"
#include "doxygen.h"
+#include "xmlgen.h"
+#include "xmldocvisitor.h"
#include "config.h"
#include "util.h"
+#include "outputlist.h"
#include "docparser.h"
#include "language.h"
+#include "version.h"
#include "dot.h"
#include "arguments.h"
#include "classlist.h"
@@ -35,65 +39,129 @@
#include "namespacedef.h"
#include "filename.h"
#include "groupdef.h"
+#include "membername.h"
+#include "memberdef.h"
#include "pagedef.h"
#include "dirdef.h"
+#include "section.h"
+#include <sys/stat.h>
#include <qdir.h>
#include <string.h>
#include <sqlite3.h>
-//#define DBG_CTX(x) printf x
-#define DBG_CTX(x) do { } while(0)
+// enable to show general debug messages
+// #define SQLITE3_DEBUG
-const char * schema_queries[][2] = {
+// enable to print all executed SQL statements.
+// I recommend using the smallest possible input list.
+// #define SQLITE3_DEBUG_SQL
+
+# ifdef SQLITE3_DEBUG
+# define DBG_CTX(x) printf x
+# else // SQLITE3_DEBUG
+# define DBG_CTX(x) do { } while(0)
+# endif
+
+# ifdef SQLITE3_DEBUG_SQL
+// used by sqlite3_trace in generateSqlite3()
+static void sqlLog(void *dbName, const char *sql){
+ msg("SQL: '%s'\n", sql);
+}
+# endif
+
+const char * table_schema[][2] = {
+ /* TABLES */
+ { "meta",
+ "CREATE TABLE IF NOT EXISTS meta (\n"
+ "\t-- Information about this db and how it was generated.\n"
+ "\t-- Doxygen info\n"
+ "\tdoxygen_version TEXT PRIMARY KEY NOT NULL,\n"
+ /*
+ Doxygen's version is likely to rollover much faster than the schema, and
+ at least until it becomes a core output format, we might want to make
+ fairly large schema changes even on minor iterations for Doxygen itself.
+ If these tools just track a predefined semver schema version that can
+ iterate independently, it *might* not be as hard to keep them in sync?
+ */
+ "\tschema_version TEXT NOT NULL, -- Schema-specific semver\n"
+ "\t-- run info\n"
+ "\tgenerated_at TEXT NOT NULL,\n"
+ "\tgenerated_on TEXT NOT NULL,\n"
+ "\t-- project info\n"
+ "\tproject_name TEXT NOT NULL,\n"
+ "\tproject_number TEXT,\n"
+ "\tproject_brief TEXT\n"
+ ");"
+ },
{ "includes",
"CREATE TABLE IF NOT EXISTS includes (\n"
"\t-- #include relations.\n"
"\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
"\tlocal INTEGER NOT NULL,\n"
- "\tid_src INTEGER NOT NULL, -- File id of the includer.\n"
- "\tid_dst INTEGER NOT NULL -- File id of the includee.\n"
- ");\n"
- "CREATE UNIQUE INDEX idx_includes ON includes\n"
- "\t(local, id_src, id_dst);"
+ "\tsrc_id INTEGER NOT NULL REFERENCES path, -- File id of the includer.\n"
+ "\tdst_id INTEGER NOT NULL REFERENCES path, -- File id of the includee.\n"
+ /*
+ In theory we could include name here to be informationally equivalent
+ with the XML, but I don't see an obvious use for it.
+ */
+ "\tUNIQUE(local, src_id, dst_id) ON CONFLICT IGNORE\n"
+ ");"
},
- { "innerclass",
- "CREATE TABLE IF NOT EXISTS innerclass (\n"
+ { "contains",
+ "CREATE TABLE IF NOT EXISTS contains (\n"
+ "\t-- inner/outer relations (file, namespace, dir, class, group, page)\n"
"\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\trefid INTEGER NOT NULL,\n"
- "\tprot INTEGER NOT NULL,\n"
- "\tname TEXT NOT NULL\n"
- ");"
+ "\tinner_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
+ "\touter_rowid INTEGER NOT NULL REFERENCES compounddef\n"
+ ");"
},
- { "files",
- "CREATE TABLE IF NOT EXISTS files (\n"
- "\t-- Names of source files and includes.\n"
- "\tname TEXT PRIMARY KEY NOT NULL\n"
- ");"
+ /* TODO: Path can also share rowids with refid/compounddef/def. (It could
+ * even collapse into that table...)
+ *
+ * I took a first swing at this by changing insertPath() to:
+ * - accept a FileDef
+ * - make its own call to insertRefid
+ * - return a refid struct.
+ *
+ * I rolled this back when I had trouble getting a FileDef for all types
+ * (PageDef in particular).
+ *
+ * Note: all colums referencing path would need an update.
+ */
+ { "path",
+ "CREATE TABLE IF NOT EXISTS path (\n"
+ "\t-- Paths of source files and includes.\n"
+ "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
+ "\ttype INTEGER NOT NULL, -- 1:file 2:dir\n"
+ "\tlocal INTEGER NOT NULL,\n"
+ "\tfound INTEGER NOT NULL,\n"
+ "\tname TEXT NOT NULL\n"
+ ");"
},
- { "refids",
- "CREATE TABLE IF NOT EXISTS refids (\n"
- "\trefid TEXT PRIMARY KEY NOT NULL\n"
- ");"
+ { "refid",
+ "CREATE TABLE IF NOT EXISTS refid (\n"
+ "\t-- Distinct refid for all documented entities.\n"
+ "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
+ "\trefid TEXT NOT NULL UNIQUE\n"
+ ");"
},
{ "xrefs",
"CREATE TABLE IF NOT EXISTS xrefs (\n"
- "\t-- Cross reference relation.\n"
+ "\t-- Cross-reference relation\n"
+ "\t-- (combines xml <referencedby> and <references> nodes).\n"
"\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\trefid_src INTEGER NOT NULL, -- referrer id.\n"
- "\trefid_dst INTEGER NOT NULL, -- referee id.\n"
- "\tid_file INTEGER NOT NULL, -- file where the reference is happening.\n"
- "\tline INTEGER NOT NULL, -- line where the reference is happening.\n"
- "\tcolumn INTEGER NOT NULL -- column where the reference is happening.\n"
- ");\n"
- "CREATE UNIQUE INDEX idx_xrefs ON xrefs\n"
- "\t(refid_src, refid_dst, id_file, line, column);"
+ "\tsrc_rowid INTEGER NOT NULL REFERENCES refid, -- referrer id.\n"
+ "\tdst_rowid INTEGER NOT NULL REFERENCES refid, -- referee id.\n"
+ "\tcontext TEXT NOT NULL, -- inline, argument, initializer\n"
+ "\t-- Just need to know they link; ignore duplicates.\n"
+ "\tUNIQUE(src_rowid, dst_rowid, context) ON CONFLICT IGNORE\n"
+ ");\n"
},
{ "memberdef",
"CREATE TABLE IF NOT EXISTS memberdef (\n"
"\t-- All processed identifiers.\n"
- "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\trefid INTEGER NOT NULL, -- see the refids table\n"
+ "\trowid INTEGER PRIMARY KEY NOT NULL,\n"
"\tname TEXT NOT NULL,\n"
"\tdefinition TEXT,\n"
"\ttype TEXT,\n"
@@ -107,7 +175,7 @@ const char * schema_queries[][2] = {
"\tstatic INTEGER DEFAULT 0, -- 0:no 1:yes\n"
"\tconst INTEGER DEFAULT 0, -- 0:no 1:yes\n"
"\texplicit INTEGER DEFAULT 0, -- 0:no 1:yes\n"
- "\tinline INTEGER DEFAULT 0, -- 0:no 1:yes\n"
+ "\tinline INTEGER DEFAULT 0, -- 0:no 1:yes 2:both (set after encountering inline and not-inline)\n"
"\tfinal INTEGER DEFAULT 0, -- 0:no 1:yes\n"
"\tsealed INTEGER DEFAULT 0, -- 0:no 1:yes\n"
"\tnew INTEGER DEFAULT 0, -- 0:no 1:yes\n"
@@ -138,55 +206,71 @@ const char * schema_queries[][2] = {
"\taddable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
"\tremovable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
"\traisable INTEGER DEFAULT 0, -- 0:no 1:yes\n"
- /// @todo make a `kind' table
- "\tkind INTEGER DEFAULT 0, -- 0:define 1:function 2:variable 3:typedef 4:enum 5:enumvalue 6:signal 7:slot 8:friend 9:DCOP 10:property 11:event\n"
+ "\tkind TEXT NOT NULL, -- 'macro definition' 'function' 'variable' 'typedef' 'enumeration' 'enumvalue' 'signal' 'slot' 'friend' 'dcop' 'property' 'event' 'interface' 'service'\n"
"\tbodystart INTEGER DEFAULT 0, -- starting line of definition\n"
"\tbodyend INTEGER DEFAULT 0, -- ending line of definition\n"
- "\tid_bodyfile INTEGER DEFAULT 0, -- file of definition\n"
- "\tid_file INTEGER NOT NULL, -- file where this identifier is located\n"
+ "\tbodyfile_id INTEGER REFERENCES path, -- file of definition\n"
+ "\tfile_id INTEGER NOT NULL REFERENCES path, -- file where this identifier is located\n"
"\tline INTEGER NOT NULL, -- line where this identifier is located\n"
"\tcolumn INTEGER NOT NULL, -- column where this identifier is located\n"
- /// @todo make a `detaileddescription' table
"\tdetaileddescription TEXT,\n"
"\tbriefdescription TEXT,\n"
- "\tinbodydescription TEXT\n"
- ");"
+ "\tinbodydescription TEXT,\n"
+ "\tFOREIGN KEY (rowid) REFERENCES refid (rowid)\n"
+ ");"
+ },
+ { "member",
+ "CREATE TABLE IF NOT EXISTS member (\n"
+ "\t-- Memberdef <-> containing compound relation.\n"
+ "\t-- Similar to XML listofallmembers.\n"
+ "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
+ "\tscope_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
+ "\tmemberdef_rowid INTEGER NOT NULL REFERENCES memberdef,\n"
+ "\tprot INTEGER NOT NULL,\n"
+ "\tvirt INTEGER NOT NULL,\n"
+ "\tUNIQUE(scope_rowid, memberdef_rowid)\n"
+ ");"
+ },
+ { "reimplements",
+ "CREATE TABLE IF NOT EXISTS reimplements (\n"
+ "\t-- Inherited member reimplmentation relations.\n"
+ "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
+ "\tmemberdef_rowid INTEGER NOT NULL REFERENCES memberdef, -- reimplementing memberdef id.\n"
+ "\treimplemented_rowid INTEGER NOT NULL REFERENCES memberdef, -- reimplemented memberdef id.\n"
+ "\tUNIQUE(memberdef_rowid, reimplemented_rowid) ON CONFLICT IGNORE\n"
+ ");\n"
},
{ "compounddef",
"CREATE TABLE IF NOT EXISTS compounddef (\n"
- "\t-- class/struct definitions.\n"
- "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\tname TEXT NOT NULL,\n"
- "\tkind TEXT NOT NULL,\n"
- "\trefid INTEGER NOT NULL,\n"
- "\tprot INTEGER NOT NULL,\n"
- "\tid_file INTEGER NOT NULL,\n"
- "\tline INTEGER NOT NULL,\n"
- "\tcolumn INTEGER NOT NULL\n"
- ");"
- },
- { "basecompoundref",
- "CREATE TABLE IF NOT EXISTS basecompoundref (\n"
- "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\tbase TEXT NOT NULL,\n"
- "\tderived TEXT NOT NULL,\n"
- "\trefid INTEGER NOT NULL,\n"
- "\tprot INTEGER NOT NULL,\n"
- "\tvirt INTEGER NOT NULL\n"
- ");"
+ "\t-- Class/struct definitions.\n"
+ "\trowid INTEGER PRIMARY KEY NOT NULL,\n"
+ "\tname TEXT NOT NULL,\n"
+ "\ttitle TEXT,\n"
+ // probably won't be empty '' or unknown, but the source *could* return them...
+ "\tkind TEXT NOT NULL, -- 'category' 'class' 'constants' 'dir' 'enum' 'example' 'exception' 'file' 'group' 'interface' 'library' 'module' 'namespace' 'package' 'page' 'protocol' 'service' 'singleton' 'struct' 'type' 'union' 'unknown' ''\n"
+ "\tprot INTEGER,\n"
+ "\tfile_id INTEGER NOT NULL REFERENCES path,\n"
+ "\tline INTEGER NOT NULL,\n"
+ "\tcolumn INTEGER NOT NULL,\n"
+ "\theader_id INTEGER REFERENCES path,\n"
+ "\tdetaileddescription TEXT,\n"
+ "\tbriefdescription TEXT,\n"
+ "\tFOREIGN KEY (rowid) REFERENCES refid (rowid)\n"
+ ");"
},
- { "derivedcompoundref",
- "CREATE TABLE IF NOT EXISTS derivedcompoundref (\n"
- "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\tbase TEXT NOT NULL,\n"
- "\tderived TEXT NOT NULL,\n"
- "\trefid INTEGER NOT NULL,\n"
- "\tprot INTEGER NOT NULL,\n"
- "\tvirt INTEGER NOT NULL\n"
- ");"
+ { "compoundref",
+ "CREATE TABLE IF NOT EXISTS compoundref (\n"
+ "\t-- Inheritance relation.\n"
+ "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
+ "\tbase_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
+ "\tderived_rowid INTEGER NOT NULL REFERENCES compounddef,\n"
+ "\tprot INTEGER NOT NULL,\n"
+ "\tvirt INTEGER NOT NULL,\n"
+ "\tUNIQUE(base_rowid, derived_rowid)\n"
+ ");"
},
- { "params",
- "CREATE TABLE IF NOT EXISTS params (\n"
+ { "param",
+ "CREATE TABLE IF NOT EXISTS param (\n"
"\t-- All processed parameters.\n"
"\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
"\tattributes TEXT,\n"
@@ -196,24 +280,222 @@ const char * schema_queries[][2] = {
"\tarray TEXT,\n"
"\tdefval TEXT,\n"
"\tbriefdescription TEXT\n"
- ");"
- "CREATE UNIQUE INDEX idx_params ON params\n"
+ ");"
+ "CREATE UNIQUE INDEX idx_param ON param\n"
"\t(type, defname);"
},
- { "memberdef_params",
- "CREATE TABLE IF NOT EXISTS memberdef_params (\n"
+ { "memberdef_param",
+ "CREATE TABLE IF NOT EXISTS memberdef_param (\n"
"\t-- Junction table for memberdef parameters.\n"
"\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\tid_memberdef INTEGER NOT NULL,\n"
- "\tid_param INTEGER NOT NULL\n"
- ");"
+ "\tmemberdef_id INTEGER NOT NULL REFERENCES memberdef,\n"
+ "\tparam_id INTEGER NOT NULL REFERENCES param\n"
+ ");"
},
- { "innernamespaces",
- "CREATE TABLE IF NOT EXISTS innernamespaces (\n"
- "\trowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n"
- "\trefid INTEGER NOT NULL,\n"
- "\tname TEXT NOT NULL\n"
- ");"
+};
+ const char * view_schema[][2] = {
+ /* VIEWS *
+ We'll set these up AFTER we build the database, so that they can be indexed,
+ but so we don't have to pay a performance penalty for inserts as we build.
+ */
+ {
+ /*
+ Makes all reference/relation tables easier to use. For example:
+ 1. query xrefs and join this view on either xrefs.dst_rowid=def.rowid or
+ xrefs.src_rowid=def.rowid
+ 2. get everything you need to output a list of references to/from an entity
+
+ Also supports simple name search/lookup for both compound and member types.
+
+ NOTES:
+ - summary for compounds generalizes title and briefdescription because
+ there's no single field that works as a quick introduction for both
+ pages and classes
+ - May be value in eventually extending this to fulltext or levenshtein
+ distance-driven lookup/search, but I'm avoiding these for now as it
+ takes some effort to enable them.
+ */
+ "def",
+ "CREATE VIEW IF NOT EXISTS def (\n"
+ "\t-- Combined summary of all -def types for easier joins.\n"
+ "\trowid,\n"
+ "\trefid,\n"
+ "\tkind,\n"
+ "\tname,\n"
+ "\tsummary"
+ ")\n"
+ "as SELECT \n"
+ "\trefid.rowid,\n"
+ "\trefid.refid,\n"
+ "\tmemberdef.kind,\n"
+ "\tmemberdef.name,\n"
+ "\tmemberdef.briefdescription \n"
+ "FROM refid \n"
+ "JOIN memberdef ON refid.rowid=memberdef.rowid \n"
+ "UNION ALL \n"
+ "SELECT \n"
+ "\trefid.rowid,\n"
+ "\trefid.refid,\n"
+ "\tcompounddef.kind,\n"
+ "\tcompounddef.name,\n"
+ "\tCASE \n"
+ "\t\tWHEN briefdescription IS NOT NULL \n"
+ "\t\tTHEN briefdescription \n"
+ "\t\tELSE title \n"
+ "\tEND summary\n"
+ "FROM refid \n"
+ "JOIN compounddef ON refid.rowid=compounddef.rowid;"
+ },
+ {
+ "local_file",
+ "CREATE VIEW IF NOT EXISTS local_file (\n"
+ "\t-- File paths found within the project.\n"
+ "\trowid,\n"
+ "\tfound,\n"
+ "\tname\n"
+ ")\n"
+ "as SELECT \n"
+ "\tpath.rowid,\n"
+ "\tpath.found,\n"
+ "\tpath.name\n"
+ "FROM path WHERE path.type=1 AND path.local=1 AND path.found=1;\n"
+ },
+ {
+ "external_file",
+ "CREATE VIEW IF NOT EXISTS external_file (\n"
+ "\t-- File paths outside the project (found or not).\n"
+ "\trowid,\n"
+ "\tfound,\n"
+ "\tname\n"
+ ")\n"
+ "as SELECT \n"
+ "\tpath.rowid,\n"
+ "\tpath.found,\n"
+ "\tpath.name\n"
+ "FROM path WHERE path.type=1 AND path.local=0;\n"
+ },
+ {
+ "inline_xrefs",
+ "CREATE VIEW IF NOT EXISTS inline_xrefs (\n"
+ "\t-- Crossrefs from inline member source.\n"
+ "\trowid,\n"
+ "\tsrc_rowid,\n"
+ "\tdst_rowid\n"
+ ")\n"
+ "as SELECT \n"
+ "\txrefs.rowid,\n"
+ "\txrefs.src_rowid,\n"
+ "\txrefs.dst_rowid\n"
+ "FROM xrefs WHERE xrefs.context='inline';\n"
+ },
+ {
+ "argument_xrefs",
+ "CREATE VIEW IF NOT EXISTS argument_xrefs (\n"
+ "\t-- Crossrefs from member def/decl arguments\n"
+ "\trowid,\n"
+ "\tsrc_rowid,\n"
+ "\tdst_rowid\n"
+ ")\n"
+ "as SELECT \n"
+ "\txrefs.rowid,\n"
+ "\txrefs.src_rowid,\n"
+ "\txrefs.dst_rowid\n"
+ "FROM xrefs WHERE xrefs.context='argument';\n"
+ },
+ {
+ "initializer_xrefs",
+ "CREATE VIEW IF NOT EXISTS initializer_xrefs (\n"
+ "\t-- Crossrefs from member initializers\n"
+ "\trowid,\n"
+ "\tsrc_rowid,\n"
+ "\tdst_rowid\n"
+ ")\n"
+ "as SELECT \n"
+ "\txrefs.rowid,\n"
+ "\txrefs.src_rowid,\n"
+ "\txrefs.dst_rowid\n"
+ "FROM xrefs WHERE xrefs.context='initializer';\n"
+ },
+ {
+ "inner_outer",
+ "CREATE VIEW IF NOT EXISTS inner_outer\n"
+ "\t-- Joins 'contains' relations to simplify inner/outer 'rel' queries.\n"
+ "as SELECT \n"
+ "\tinner.*,\n"
+ "\touter.*\n"
+ "FROM def as inner\n"
+ "\tJOIN contains ON inner.rowid=contains.inner_rowid\n"
+ "\tJOIN def AS outer ON outer.rowid=contains.outer_rowid;\n"
+ },
+ {
+ "rel",
+ "CREATE VIEW IF NOT EXISTS rel (\n"
+ "\t-- Boolean indicator of relations available for a given entity.\n"
+ "\t-- Join to (compound-|member-)def to find fetch-worthy relations.\n"
+ "\trowid,\n"
+ "\treimplemented,\n"
+ "\treimplements,\n"
+ "\tinnercompounds,\n"
+ "\toutercompounds,\n"
+ "\tinnerpages,\n"
+ "\touterpages,\n"
+ "\tinnerdirs,\n"
+ "\touterdirs,\n"
+ "\tinnerfiles,\n"
+ "\touterfiles,\n"
+ "\tinnerclasses,\n"
+ "\touterclasses,\n"
+ "\tinnernamespaces,\n"
+ "\touternamespaces,\n"
+ "\tinnergroups,\n"
+ "\toutergroups,\n"
+ "\tmembers,\n"
+ "\tcompounds,\n"
+ "\tsubclasses,\n"
+ "\tsuperclasses,\n"
+ "\tlinks_in,\n"
+ "\tlinks_out,\n"
+ "\targument_links_in,\n"
+ "\targument_links_out,\n"
+ "\tinitializer_links_in,\n"
+ "\tinitializer_links_out\n"
+ ")\n"
+ "as SELECT \n"
+ "\tdef.rowid,\n"
+ "\tEXISTS (SELECT rowid FROM reimplements WHERE reimplemented_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM reimplements WHERE memberdef_rowid=def.rowid),\n"
+ "\t-- rowid/kind for inner, [rowid:1/kind:1] for outer\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='page'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='page'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='dir'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='dir'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='file'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='file'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind in (\n"
+ "'category','class','enum','exception','interface','module','protocol',\n"
+ "'service','singleton','struct','type','union'\n"
+ ")),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1] in (\n"
+ "'category','class','enum','exception','interface','module','protocol',\n"
+ "'service','singleton','struct','type','union'\n"
+ ")),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='namespace'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='namespace'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE [rowid:1]=def.rowid AND kind='group'),\n"
+ "\tEXISTS (SELECT * FROM inner_outer WHERE rowid=def.rowid AND [kind:1]='group'),\n"
+ "\tEXISTS (SELECT rowid FROM member WHERE scope_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM member WHERE memberdef_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM compoundref WHERE base_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM compoundref WHERE derived_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM inline_xrefs WHERE dst_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM inline_xrefs WHERE src_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM argument_xrefs WHERE dst_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM argument_xrefs WHERE src_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM initializer_xrefs WHERE dst_rowid=def.rowid),\n"
+ "\tEXISTS (SELECT rowid FROM initializer_xrefs WHERE src_rowid=def.rowid)\n"
+ "FROM def ORDER BY def.rowid;"
}
};
@@ -224,193 +506,298 @@ struct SqlStmt {
sqlite3 *db;
};
//////////////////////////////////////////////////////
-SqlStmt incl_insert = { "INSERT INTO includes "
- "( local, id_src, id_dst ) "
- "VALUES "
- "(:local,:id_src,:id_dst )"
- ,NULL
+/* If you add a new statement below, make sure to add it to
+ prepareStatements(). If sqlite3 is segfaulting (especially in
+ sqlite3_clear_bindings()), using an un-prepared statement may
+ be the cause. */
+SqlStmt meta_insert = {
+ "INSERT INTO meta "
+ "( doxygen_version, schema_version, generated_at, generated_on, project_name, project_number, project_brief )"
+ "VALUES "
+ "(:doxygen_version,:schema_version,:generated_at,:generated_on,:project_name,:project_number,:project_brief )"
+ ,NULL
+};
+//////////////////////////////////////////////////////
+SqlStmt incl_insert = {
+ "INSERT INTO includes "
+ "( local, src_id, dst_id ) "
+ "VALUES "
+ "(:local,:src_id,:dst_id )"
+ ,NULL
};
-SqlStmt incl_select = { "SELECT COUNT(*) FROM includes WHERE "
- "local=:local AND id_src=:id_src AND id_dst=:id_dst"
- ,NULL
+SqlStmt incl_select = {
+ "SELECT COUNT(*) FROM includes WHERE "
+ "local=:local AND src_id=:src_id AND dst_id=:dst_id"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt innerclass_insert={"INSERT INTO innerclass "
- "( refid, prot, name )"
- "VALUES "
- "(:refid,:prot,:name )"
- ,NULL
+SqlStmt contains_insert={
+ "INSERT INTO contains "
+ "( inner_rowid, outer_rowid )"
+ "VALUES "
+ "(:inner_rowid,:outer_rowid )"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt files_select = {"SELECT rowid FROM files WHERE name=:name"
+SqlStmt path_select = {
+ "SELECT rowid FROM path WHERE name=:name"
,NULL
};
-SqlStmt files_insert = {"INSERT INTO files "
- "( name )"
- "VALUES "
- "(:name )"
- ,NULL
+SqlStmt path_insert = {
+ "INSERT INTO path "
+ "( type, local, found, name )"
+ "VALUES "
+ "(:type,:local,:found,:name )"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt refids_select = {"SELECT rowid FROM refids WHERE "
- "refid=:refid"
- ,NULL
+SqlStmt refid_select = {
+ "SELECT rowid FROM refid WHERE refid=:refid"
+ ,NULL
};
-SqlStmt refids_insert = {"INSERT INTO refids "
- "( refid )"
- "VALUES "
+SqlStmt refid_insert = {
+ "INSERT INTO refid "
+ "( refid )"
+ "VALUES "
"(:refid )"
- ,NULL
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt xrefs_insert= {"INSERT INTO xrefs "
- "( refid_src, refid_dst, id_file, line, column )"
- "VALUES "
- "(:refid_src,:refid_dst,:id_file,:line,:column )"
- ,NULL
+SqlStmt xrefs_insert= {
+ "INSERT INTO xrefs "
+ "( src_rowid, dst_rowid, context )"
+ "VALUES "
+ "(:src_rowid,:dst_rowid,:context )"
+ ,NULL
+};//////////////////////////////////////////////////////
+SqlStmt reimplements_insert= {
+ "INSERT INTO reimplements "
+ "( memberdef_rowid, reimplemented_rowid )"
+ "VALUES "
+ "(:memberdef_rowid,:reimplemented_rowid )"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt memberdef_insert={"INSERT INTO memberdef "
- "("
- "refid,"
- "name,"
- "definition,"
- "type,"
- "argsstring,"
- "scope,"
- "initializer,"
- "bitfield,"
- "read,"
- "write,"
- "prot,"
- "static,"
- "const,"
- "explicit,"
- "inline,"
- "final,"
- "sealed,"
- "new,"
- "optional,"
- "required,"
- "volatile,"
- "virt,"
- "mutable,"
- "initonly,"
- "attribute,"
- "property,"
- "readonly,"
- "bound,"
- "constrained,"
- "transient,"
- "maybevoid,"
- "maybedefault,"
- "maybeambiguous,"
- "readable,"
- "writable,"
- "gettable,"
- "protectedsettable,"
- "protectedgettable,"
- "settable,"
- "privatesettable,"
- "privategettable,"
- "accessor,"
- "addable,"
- "removable,"
- "raisable,"
- "kind,"
- "bodystart,"
- "bodyend,"
- "id_bodyfile,"
- "id_file,"
- "line,"
- "column,"
- "detaileddescription,"
- "briefdescription,"
- "inbodydescription"
- ")"
- "VALUES "
- "("
- ":refid,"
- ":name,"
- ":definition,"
- ":type,"
- ":argsstring,"
- ":scope,"
- ":initializer,"
- ":bitfield,"
- ":read,"
- ":write,"
- ":prot,"
- ":static,"
- ":const,"
- ":explicit,"
- ":inline,"
- ":final,"
- ":sealed,"
- ":new,"
- ":optional,"
- ":required,"
- ":volatile,"
- ":virt,"
- ":mutable,"
- ":initonly,"
- ":attribute,"
- ":property,"
- ":readonly,"
- ":bound,"
- ":constrained,"
- ":transient,"
- ":maybevoid,"
- ":maybedefault,"
- ":maybeambiguous,"
- ":readable,"
- ":writable,"
- ":gettable,"
- ":protectedsettable,"
- ":protectedgettable,"
- ":settable,"
- ":privatesettable,"
- ":privategettable,"
- ":accessor,"
- ":addable,"
- ":removable,"
- ":raisable,"
- ":kind,"
- ":bodystart,"
- ":bodyend,"
- ":id_bodyfile,"
- ":id_file,"
- ":line,"
- ":column,"
- ":detaileddescription,"
- ":briefdescription,"
- ":inbodydescription"
- ")"
- ,NULL
+SqlStmt memberdef_exists={
+ "SELECT EXISTS (SELECT * FROM memberdef WHERE rowid = :rowid)"
+ ,NULL
+};
+
+SqlStmt memberdef_incomplete={
+ "SELECT EXISTS ("
+ "SELECT * FROM memberdef WHERE "
+ "rowid = :rowid AND inline != 2 AND inline != :new_inline"
+ ")"
+ ,NULL
+};
+
+SqlStmt memberdef_insert={
+ "INSERT INTO memberdef "
+ "("
+ "rowid,"
+ "name,"
+ "definition,"
+ "type,"
+ "argsstring,"
+ "scope,"
+ "initializer,"
+ "bitfield,"
+ "read,"
+ "write,"
+ "prot,"
+ "static,"
+ "const,"
+ "explicit,"
+ "inline,"
+ "final,"
+ "sealed,"
+ "new,"
+ "optional,"
+ "required,"
+ "volatile,"
+ "virt,"
+ "mutable,"
+ "initonly,"
+ "attribute,"
+ "property,"
+ "readonly,"
+ "bound,"
+ "constrained,"
+ "transient,"
+ "maybevoid,"
+ "maybedefault,"
+ "maybeambiguous,"
+ "readable,"
+ "writable,"
+ "gettable,"
+ "protectedsettable,"
+ "protectedgettable,"
+ "settable,"
+ "privatesettable,"
+ "privategettable,"
+ "accessor,"
+ "addable,"
+ "removable,"
+ "raisable,"
+ "kind,"
+ "bodystart,"
+ "bodyend,"
+ "bodyfile_id,"
+ "file_id,"
+ "line,"
+ "column,"
+ "detaileddescription,"
+ "briefdescription,"
+ "inbodydescription"
+ ")"
+ "VALUES "
+ "("
+ ":rowid,"
+ ":name,"
+ ":definition,"
+ ":type,"
+ ":argsstring,"
+ ":scope,"
+ ":initializer,"
+ ":bitfield,"
+ ":read,"
+ ":write,"
+ ":prot,"
+ ":static,"
+ ":const,"
+ ":explicit,"
+ ":inline,"
+ ":final,"
+ ":sealed,"
+ ":new,"
+ ":optional,"
+ ":required,"
+ ":volatile,"
+ ":virt,"
+ ":mutable,"
+ ":initonly,"
+ ":attribute,"
+ ":property,"
+ ":readonly,"
+ ":bound,"
+ ":constrained,"
+ ":transient,"
+ ":maybevoid,"
+ ":maybedefault,"
+ ":maybeambiguous,"
+ ":readable,"
+ ":writable,"
+ ":gettable,"
+ ":protectedsettable,"
+ ":protectedgettable,"
+ ":settable,"
+ ":privatesettable,"
+ ":privategettable,"
+ ":accessor,"
+ ":addable,"
+ ":removable,"
+ ":raisable,"
+ ":kind,"
+ ":bodystart,"
+ ":bodyend,"
+ ":bodyfile_id,"
+ ":file_id,"
+ ":line,"
+ ":column,"
+ ":detaileddescription,"
+ ":briefdescription,"
+ ":inbodydescription"
+ ")"
+ ,NULL
+};
+/*
+We have a slightly different need than the XML here. The XML can have two
+memberdef nodes with the same refid to document the declaration and the
+definition. This doesn't play very nice with a referential model. It isn't a
+big issue if only one is documented, but in case both are, we'll fall back on
+this kludge to combine them in a single row...
+*/
+SqlStmt memberdef_update_decl={
+ "UPDATE memberdef SET "
+ "inline = :inline,"
+ "file_id = :file_id,"
+ "line = :line,"
+ "column = :column,"
+ "detaileddescription = 'Declaration: ' || :detaileddescription || 'Definition: ' || detaileddescription,"
+ "briefdescription = 'Declaration: ' || :briefdescription || 'Definition: ' || briefdescription,"
+ "inbodydescription = 'Declaration: ' || :inbodydescription || 'Definition: ' || inbodydescription "
+ "WHERE rowid = :rowid"
+ ,NULL
+};
+SqlStmt memberdef_update_def={
+ "UPDATE memberdef SET "
+ "inline = :inline,"
+ "bodystart = :bodystart,"
+ "bodyend = :bodyend,"
+ "bodyfile_id = :bodyfile_id,"
+ "detaileddescription = 'Declaration: ' || detaileddescription || 'Definition: ' || :detaileddescription,"
+ "briefdescription = 'Declaration: ' || briefdescription || 'Definition: ' || :briefdescription,"
+ "inbodydescription = 'Declaration: ' || inbodydescription || 'Definition: ' || :inbodydescription "
+ "WHERE rowid = :rowid"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt compounddef_insert={"INSERT INTO compounddef "
- "( name, kind, prot, refid, id_file, line, column ) "
- "VALUES "
- "(:name,:kind,:prot,:refid,:id_file,:line,:column )"
- ,NULL
+SqlStmt member_insert={
+ "INSERT INTO member "
+ "( scope_rowid, memberdef_rowid, prot, virt ) "
+ "VALUES "
+ "(:scope_rowid,:memberdef_rowid,:prot,:virt )"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt basecompoundref_insert={"INSERT INTO basecompoundref "
- "( base, derived, refid, prot, virt ) "
- "VALUES "
- "(:base,:derived,:refid,:prot,:virt )"
- ,NULL
+SqlStmt compounddef_insert={
+ "INSERT INTO compounddef "
+ "("
+ "rowid,"
+ "name,"
+ "title,"
+ "kind,"
+ "prot,"
+ "file_id,"
+ "line,"
+ "column,"
+ "header_id,"
+ "briefdescription,"
+ "detaileddescription"
+ ")"
+ "VALUES "
+ "("
+ ":rowid,"
+ ":name,"
+ ":title,"
+ ":kind,"
+ ":prot,"
+ ":file_id,"
+ ":line,"
+ ":column,"
+ ":header_id,"
+ ":briefdescription,"
+ ":detaileddescription"
+ ")"
+ ,NULL
+};
+SqlStmt compounddef_exists={
+ "SELECT EXISTS ("
+ "SELECT * FROM compounddef WHERE rowid = :rowid"
+ ")"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt derivedcompoundref_insert={"INSERT INTO derivedcompoundref "
- "( refid, prot, virt, base, derived ) "
- "VALUES "
- "(:refid,:prot,:virt,:base,:derived )"
- ,NULL
+SqlStmt compoundref_insert={
+ "INSERT INTO compoundref "
+ "( base_rowid, derived_rowid, prot, virt ) "
+ "VALUES "
+ "(:base_rowid,:derived_rowid,:prot,:virt )"
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt params_select = { "SELECT rowid FROM params WHERE "
+SqlStmt param_select = {
+ "SELECT rowid FROM param WHERE "
"(attributes IS NULL OR attributes=:attributes) AND "
"(type IS NULL OR type=:type) AND "
"(declname IS NULL OR declname=:declname) AND "
@@ -418,27 +805,22 @@ SqlStmt params_select = { "SELECT rowid FROM params WHERE "
"(array IS NULL OR array=:array) AND "
"(defval IS NULL OR defval=:defval) AND "
"(briefdescription IS NULL OR briefdescription=:briefdescription)"
- ,NULL
+ ,NULL
};
-SqlStmt params_insert = { "INSERT INTO params "
- "( attributes, type, declname, defname, array, defval, briefdescription ) "
- "VALUES "
+SqlStmt param_insert = {
+ "INSERT INTO param "
+ "( attributes, type, declname, defname, array, defval, briefdescription ) "
+ "VALUES "
"(:attributes,:type,:declname,:defname,:array,:defval,:briefdescription)"
- ,NULL
-};
-//////////////////////////////////////////////////////
-SqlStmt memberdef_params_insert={ "INSERT INTO memberdef_params "
- "( id_memberdef, id_param)"
- "VALUES "
- "(:id_memberdef,:id_param)"
- ,NULL
+ ,NULL
};
//////////////////////////////////////////////////////
-SqlStmt innernamespace_insert={"INSERT INTO innernamespaces "
- "( refid, name)"
- "VALUES "
- "(:refid,:name)",
- NULL
+SqlStmt memberdef_param_insert={
+ "INSERT INTO memberdef_param "
+ "( memberdef_id, param_id)"
+ "VALUES "
+ "(:memberdef_id,:param_id)"
+ ,NULL
};
@@ -491,7 +873,7 @@ static bool bindIntParameter(SqlStmt &s,const char *name,int value)
{
int idx = sqlite3_bind_parameter_index(s.stmt, name);
if (idx==0) {
- msg("sqlite3_bind_parameter_index(%s)[%s] failed: %s\n", name, s.query, sqlite3_errmsg(s.db));
+ msg("sqlite3_bind_parameter_index(%s)[%s] failed to find column: %s\n", name, s.query, sqlite3_errmsg(s.db));
return false;
}
int rv = sqlite3_bind_int(s.stmt, idx, value);
@@ -508,7 +890,7 @@ static int step(SqlStmt &s,bool getRowId=FALSE, bool select=FALSE)
int rc = sqlite3_step(s.stmt);
if (rc!=SQLITE_DONE && rc!=SQLITE_ROW)
{
- msg("sqlite3_step: %s\n", sqlite3_errmsg(s.db));
+ DBG_CTX(("sqlite3_step: %s (rc: %d)\n", sqlite3_errmsg(s.db), rc));
sqlite3_reset(s.stmt);
sqlite3_clear_bindings(s.stmt);
return -1;
@@ -520,76 +902,122 @@ static int step(SqlStmt &s,bool getRowId=FALSE, bool select=FALSE)
return rowid;
}
-static int insertFile(const char* name)
+static int insertPath(QCString name, bool local=TRUE, bool found=TRUE, int type=1)
{
int rowid=-1;
if (name==0) return rowid;
- bindTextParameter(files_select,":name",name);
- rowid=step(files_select,TRUE,TRUE);
+ name = stripFromPath(name);
+
+ bindTextParameter(path_select,":name",name.data(),FALSE);
+ rowid=step(path_select,TRUE,TRUE);
if (rowid==0)
{
- bindTextParameter(files_insert,":name",name);
- rowid=step(files_insert,TRUE);
+ bindTextParameter(path_insert,":name",name.data(),FALSE);
+ bindIntParameter(path_insert,":type",type);
+ bindIntParameter(path_insert,":local",local?1:0);
+ bindIntParameter(path_insert,":found",found?1:0);
+ rowid=step(path_insert,TRUE);
}
return rowid;
}
-static int insertRefid(const char *refid)
+static void recordMetadata()
{
- int rowid=-1;
- if (refid==0) return rowid;
+ bindTextParameter(meta_insert,":doxygen_version",versionString);
+ bindTextParameter(meta_insert,":schema_version","0.2.0"); //TODO: this should be a constant somewhere; not sure where
+ bindTextParameter(meta_insert,":generated_at",dateToString(TRUE), FALSE);
+ bindTextParameter(meta_insert,":generated_on",dateToString(FALSE), FALSE);
+ bindTextParameter(meta_insert,":project_name",Config_getString(PROJECT_NAME));
+ bindTextParameter(meta_insert,":project_number",Config_getString(PROJECT_NUMBER));
+ bindTextParameter(meta_insert,":project_brief",Config_getString(PROJECT_BRIEF));
+ step(meta_insert);
+}
- bindTextParameter(refids_select,":refid",refid);
- rowid=step(refids_select,TRUE,TRUE);
- if (rowid==0)
+struct Refid {
+ int rowid;
+ const char *refid;
+ bool created;
+};
+
+struct Refid insertRefid(const char *refid)
+{
+ struct Refid ret;
+ ret.rowid=-1;
+ ret.refid=refid;
+ ret.created = FALSE;
+ if (refid==0) return ret;
+
+ bindTextParameter(refid_select,":refid",refid);
+ ret.rowid=step(refid_select,TRUE,TRUE);
+ if (ret.rowid==0)
{
- bindTextParameter(refids_insert,":refid",refid);
- rowid=step(refids_insert,TRUE);
+ bindTextParameter(refid_insert,":refid",refid);
+ ret.rowid=step(refid_insert,TRUE);
+ ret.created = TRUE;
}
- return rowid;
+
+ return ret;
+}
+
+static bool memberdefExists(struct Refid refid)
+{
+ bindIntParameter(memberdef_exists,":rowid",refid.rowid);
+ int test = step(memberdef_exists,TRUE,TRUE);
+ return test ? true : false;
}
+static bool memberdefIncomplete(struct Refid refid, const MemberDef* md)
+{
+ bindIntParameter(memberdef_incomplete,":rowid",refid.rowid);
+ bindIntParameter(memberdef_incomplete,":new_inline",md->isInline());
+ int test = step(memberdef_incomplete,TRUE,TRUE);
+ return test ? true : false;
+}
-static bool insertMemberReference(int refid_src, int refid_dst,
- int id_file, int line, int column)
+static bool compounddefExists(struct Refid refid)
{
- if (id_file==-1||refid_src==-1||refid_dst==-1)
+ bindIntParameter(compounddef_exists,":rowid",refid.rowid);
+ int test = step(compounddef_exists,TRUE,TRUE);
+ return test ? true : false;
+}
+
+static bool insertMemberReference(struct Refid src_refid, struct Refid dst_refid, const char *context)
+{
+ if (src_refid.rowid==-1||dst_refid.rowid==-1)
return false;
if (
- !bindIntParameter(xrefs_insert,":refid_src",refid_src) ||
- !bindIntParameter(xrefs_insert,":refid_dst",refid_dst) ||
- !bindIntParameter(xrefs_insert,":id_file",id_file) ||
- !bindIntParameter(xrefs_insert,":line",line) ||
- !bindIntParameter(xrefs_insert,":column",column)
+ !bindIntParameter(xrefs_insert,":src_rowid",src_refid.rowid) ||
+ !bindIntParameter(xrefs_insert,":dst_rowid",dst_refid.rowid)
)
{
return false;
}
+ else
+ {
+ bindTextParameter(xrefs_insert,":context",context);
+ }
step(xrefs_insert);
return true;
}
-static void insertMemberReference(const MemberDef *src, const MemberDef *dst)
+static void insertMemberReference(const MemberDef *src, const MemberDef *dst, const char *context)
{
- QCString qrefid_dst = dst->getOutputFileBase() + "_1" + dst->anchor();
- QCString qrefid_src = src->getOutputFileBase() + "_1" + src->anchor();
- if (dst->getStartBodyLine()!=-1 && dst->getBodyDef())
- {
- int refid_src = insertRefid(qrefid_src.data());
- int refid_dst = insertRefid(qrefid_dst.data());
- int id_file = insertFile("no-file"); // TODO: replace no-file with proper file
- insertMemberReference(refid_src,refid_dst,id_file,dst->getStartBodyLine(),-1);
- }
+ QCString qdst_refid = dst->getOutputFileBase() + "_1" + dst->anchor();
+ QCString qsrc_refid = src->getOutputFileBase() + "_1" + src->anchor();
+
+ struct Refid src_refid = insertRefid(qsrc_refid);
+ struct Refid dst_refid = insertRefid(qdst_refid);
+ insertMemberReference(src_refid,dst_refid,context);
}
-static void insertMemberFunctionParams(int id_memberdef, const MemberDef *md, const Definition *def)
+static void insertMemberFunctionParams(int memberdef_id, const MemberDef *md, const Definition *def)
{
ArgumentList *declAl = md->declArgumentList();
ArgumentList *defAl = md->argumentList();
- if (declAl!=0 && declAl->count()>0)
+ if (declAl!=0 && defAl!=0 && declAl->count()>0)
{
ArgumentListIterator declAli(*declAl);
ArgumentListIterator defAli(*defAl);
@@ -600,8 +1028,8 @@ static void insertMemberFunctionParams(int id_memberdef, const MemberDef *md, co
if (!a->attrib.isEmpty())
{
- bindTextParameter(params_select,":attributes",a->attrib.data());
- bindTextParameter(params_insert,":attributes",a->attrib.data());
+ bindTextParameter(param_select,":attributes",a->attrib);
+ bindTextParameter(param_insert,":attributes",a->attrib);
}
if (!a->type.isEmpty())
{
@@ -612,57 +1040,56 @@ static void insertMemberFunctionParams(int id_memberdef, const MemberDef *md, co
QCString *s;
while ((s=li.current()))
{
- QCString qrefid_src = md->getOutputFileBase() + "_1" + md->anchor();
- int refid_src = insertRefid(qrefid_src.data());
- int refid_dst = insertRefid(s->data());
- int id_file = insertFile(stripFromPath(def->getDefFileName()));
- insertMemberReference(refid_src,refid_dst,id_file,md->getDefLine(),-1);
+ QCString qsrc_refid = md->getOutputFileBase() + "_1" + md->anchor();
+ struct Refid src_refid = insertRefid(qsrc_refid);
+ struct Refid dst_refid = insertRefid(s->data());
+ insertMemberReference(src_refid,dst_refid, "argument");
++li;
}
- bindTextParameter(params_select,":type",a->type.data());
- bindTextParameter(params_insert,":type",a->type.data());
+ bindTextParameter(param_select,":type",a->type);
+ bindTextParameter(param_insert,":type",a->type);
}
if (!a->name.isEmpty())
{
- bindTextParameter(params_select,":declname",a->name.data());
- bindTextParameter(params_insert,":declname",a->name.data());
+ bindTextParameter(param_select,":declname",a->name);
+ bindTextParameter(param_insert,":declname",a->name);
}
if (defArg && !defArg->name.isEmpty() && defArg->name!=a->name)
{
- bindTextParameter(params_select,":defname",defArg->name.data());
- bindTextParameter(params_insert,":defname",defArg->name.data());
+ bindTextParameter(param_select,":defname",defArg->name);
+ bindTextParameter(param_insert,":defname",defArg->name);
}
if (!a->array.isEmpty())
{
- bindTextParameter(params_select,":array",a->array.data());
- bindTextParameter(params_insert,":array",a->array.data());
+ bindTextParameter(param_select,":array",a->array);
+ bindTextParameter(param_insert,":array",a->array);
}
if (!a->defval.isEmpty())
{
StringList l;
linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,a->defval);
- bindTextParameter(params_select,":defval",a->defval.data());
- bindTextParameter(params_insert,":defval",a->defval.data());
+ bindTextParameter(param_select,":defval",a->defval);
+ bindTextParameter(param_insert,":defval",a->defval);
}
if (defArg) ++defAli;
- int id_param=step(params_select,TRUE,TRUE);
- if (id_param==0) {
- id_param=step(params_insert,TRUE);
+ int param_id=step(param_select,TRUE,TRUE);
+ if (param_id==0) {
+ param_id=step(param_insert,TRUE);
}
- if (id_param==-1) {
- msg("error INSERT params failed\n");
+ if (param_id==-1) {
+ DBG_CTX(("error INSERT params failed\n"));
continue;
}
- bindIntParameter(memberdef_params_insert,":id_memberdef",id_memberdef);
- bindIntParameter(memberdef_params_insert,":id_param",id_param);
- step(memberdef_params_insert);
+ bindIntParameter(memberdef_param_insert,":memberdef_id",memberdef_id);
+ bindIntParameter(memberdef_param_insert,":param_id",param_id);
+ step(memberdef_param_insert);
}
}
}
-static void insertMemberDefineParams(int id_memberdef,const MemberDef *md, const Definition *def)
+static void insertMemberDefineParams(int memberdef_id,const MemberDef *md, const Definition *def)
{
if (md->argumentList()->count()==0) // special case for "foo()" to
// disguish it from "foo".
@@ -675,20 +1102,34 @@ static void insertMemberDefineParams(int id_memberdef,const MemberDef *md, const
Argument *a;
for (ali.toFirst();(a=ali.current());++ali)
{
- bindTextParameter(params_insert,":defname",a->type.data());
- int id_param=step(params_insert,TRUE);
- if (id_param==-1) {
- msg("error INSERT param(%s) failed\n", a->type.data());
+ bindTextParameter(param_insert,":defname",a->type);
+ int param_id=step(param_insert,TRUE);
+ if (param_id==-1) {
continue;
}
- bindIntParameter(memberdef_params_insert,":id_memberdef",id_memberdef);
- bindIntParameter(memberdef_params_insert,":id_param",id_param);
- step(memberdef_params_insert);
+ bindIntParameter(memberdef_param_insert,":memberdef_id",memberdef_id);
+ bindIntParameter(memberdef_param_insert,":param_id",param_id);
+ step(memberdef_param_insert);
}
}
}
+static void associateMember(const MemberDef *md, struct Refid member_refid, struct Refid scope_refid)
+{
+ // TODO: skip EnumValue only to guard against recording refids and member records
+ // for enumvalues until we can support documenting them as entities.
+ if (md->memberType()==MemberType_EnumValue) return;
+ if (md->name().at(0)!='@') // skip anonymous members
+ {
+ bindIntParameter(member_insert, ":scope_rowid", scope_refid.rowid);
+ bindIntParameter(member_insert, ":memberdef_rowid", member_refid.rowid);
+
+ bindIntParameter(member_insert, ":prot", md->protection());
+ bindIntParameter(member_insert, ":virt", md->virtualness());
+ step(member_insert);
+ }
+}
static void stripQualifiers(QCString &typeStr)
{
@@ -720,22 +1161,28 @@ static int prepareStatement(sqlite3 *db, SqlStmt &s)
static int prepareStatements(sqlite3 *db)
{
if (
+ -1==prepareStatement(db, meta_insert) ||
+ -1==prepareStatement(db, memberdef_exists) ||
+ -1==prepareStatement(db, memberdef_incomplete) ||
-1==prepareStatement(db, memberdef_insert) ||
- -1==prepareStatement(db, files_insert) ||
- -1==prepareStatement(db, files_select) ||
- -1==prepareStatement(db, refids_insert) ||
- -1==prepareStatement(db, refids_select) ||
+ -1==prepareStatement(db, memberdef_update_def) ||
+ -1==prepareStatement(db, memberdef_update_decl) ||
+ -1==prepareStatement(db, member_insert) ||
+ -1==prepareStatement(db, path_insert) ||
+ -1==prepareStatement(db, path_select) ||
+ -1==prepareStatement(db, refid_insert) ||
+ -1==prepareStatement(db, refid_select) ||
-1==prepareStatement(db, incl_insert)||
-1==prepareStatement(db, incl_select)||
- -1==prepareStatement(db, params_insert) ||
- -1==prepareStatement(db, params_select) ||
+ -1==prepareStatement(db, param_insert) ||
+ -1==prepareStatement(db, param_select) ||
-1==prepareStatement(db, xrefs_insert) ||
- -1==prepareStatement(db, innerclass_insert) ||
+ -1==prepareStatement(db, reimplements_insert) ||
+ -1==prepareStatement(db, contains_insert) ||
+ -1==prepareStatement(db, compounddef_exists) ||
-1==prepareStatement(db, compounddef_insert) ||
- -1==prepareStatement(db, basecompoundref_insert) ||
- -1==prepareStatement(db, derivedcompoundref_insert) ||
- -1==prepareStatement(db, memberdef_params_insert)||
- -1==prepareStatement(db, innernamespace_insert)
+ -1==prepareStatement(db, compoundref_insert) ||
+ -1==prepareStatement(db, memberdef_param_insert)
)
{
return -1;
@@ -763,15 +1210,35 @@ static void pragmaTuning(sqlite3 *db)
sqlite3_exec(db, "PRAGMA temp_store = MEMORY;", NULL, NULL, &sErrMsg);
}
-static int initializeSchema(sqlite3* db)
+static int initializeTables(sqlite3* db)
+{
+ int rc;
+ sqlite3_stmt *stmt = 0;
+
+ msg("Initializing DB schema (tables)...\n");
+ for (unsigned int k = 0; k < sizeof(table_schema) / sizeof(table_schema[0]); k++)
+ {
+ const char *q = table_schema[k][1];
+ char *errmsg;
+ rc = sqlite3_exec(db, q, NULL, NULL, &errmsg);
+ if (rc != SQLITE_OK)
+ {
+ msg("failed to execute query: %s\n\t%s\n", q, errmsg);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int initializeViews(sqlite3* db)
{
int rc;
sqlite3_stmt *stmt = 0;
- msg("Initializing DB schema...\n");
- for (unsigned int k = 0; k < sizeof(schema_queries) / sizeof(schema_queries[0]); k++)
+ msg("Initializing DB schema (views)...\n");
+ for (unsigned int k = 0; k < sizeof(view_schema) / sizeof(view_schema[0]); k++)
{
- const char *q = schema_queries[k][1];
+ const char *q = view_schema[k][1];
char *errmsg;
rc = sqlite3_exec(db, q, NULL, NULL, &errmsg);
if (rc != SQLITE_OK)
@@ -784,40 +1251,122 @@ static int initializeSchema(sqlite3* db)
}
////////////////////////////////////////////
-static void writeInnerClasses(const ClassSDict *cl)
+/* TODO:
+I collapsed all innerX tables into 'contains', which raises the prospect that
+all of these very similar writeInnerX funcs could be refactored into a one,
+or a small set of common parts.
+
+I think the hurdles are:
+- picking a first argument that every call location can pass
+- which yields a consistent iterator
+- accommodates PageDef's slightly different rules for generating the
+ inner_refid (unless I'm missing a method that would uniformly return
+ the correct refid for all types).
+*/
+static void writeInnerClasses(const ClassSDict *cl, struct Refid outer_refid)
{
if (!cl) return;
ClassSDict::Iterator cli(*cl);
- ClassDef *cd;
+ const ClassDef *cd;
for (cli.toFirst();(cd=cli.current());++cli)
{
if (!cd->isHidden() && cd->name().find('@')==-1) // skip anonymous scopes
{
- int refid = insertRefid(cd->getOutputFileBase());
- bindIntParameter(innerclass_insert,":refid", refid);
- bindIntParameter(innerclass_insert,":prot",cd->protection());
- bindTextParameter(innerclass_insert,":name",cd->name());
- step(innerclass_insert);
+ struct Refid inner_refid = insertRefid(cd->getOutputFileBase());
+
+ bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
+ bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
+ step(contains_insert);
}
}
}
+static void writeInnerPages(const PageSDict *pl, struct Refid outer_refid)
+{
+ if (!pl) return;
+
+ PageSDict::Iterator pli(*pl);
+ const PageDef *pd;
+ for (pli.toFirst();(pd=pli.current());++pli)
+ {
+ struct Refid inner_refid = insertRefid(
+ pd->getGroupDef() ? pd->getOutputFileBase()+"_"+pd->name() : pd->getOutputFileBase()
+ );
+
+ bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
+ bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
+ step(contains_insert);
-static void writeInnerNamespaces(const NamespaceSDict *nl)
+ }
+}
+
+static void writeInnerGroups(const GroupList *gl, struct Refid outer_refid)
+{
+ if (gl)
+ {
+ GroupListIterator gli(*gl);
+ const GroupDef *sgd;
+ for (gli.toFirst();(sgd=gli.current());++gli)
+ {
+ struct Refid inner_refid = insertRefid(sgd->getOutputFileBase());
+
+ bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
+ bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
+ step(contains_insert);
+ }
+ }
+}
+
+static void writeInnerFiles(const FileList *fl, struct Refid outer_refid)
+{
+ if (fl)
+ {
+ QListIterator<FileDef> fli(*fl);
+ const FileDef *fd;
+ for (fli.toFirst();(fd=fli.current());++fli)
+ {
+ struct Refid inner_refid = insertRefid(fd->getOutputFileBase());
+
+ bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
+ bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
+ step(contains_insert);
+ }
+ }
+}
+
+static void writeInnerDirs(const DirList *dl, struct Refid outer_refid)
+{
+ if (dl)
+ {
+ QListIterator<DirDef> subdirs(*dl);
+ const DirDef *subdir;
+ for (subdirs.toFirst();(subdir=subdirs.current());++subdirs)
+ {
+ struct Refid inner_refid = insertRefid(subdir->getOutputFileBase());
+
+ bindIntParameter(contains_insert,":inner_rowid", inner_refid.rowid);
+ bindIntParameter(contains_insert,":outer_rowid", outer_refid.rowid);
+ step(contains_insert);
+ }
+ }
+}
+
+static void writeInnerNamespaces(const NamespaceSDict *nl, struct Refid outer_refid)
{
if (nl)
{
NamespaceSDict::Iterator nli(*nl);
- NamespaceDef *nd;
+ const NamespaceDef *nd;
for (nli.toFirst();(nd=nli.current());++nli)
{
- if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymouse scopes
+ if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymous scopes
{
- int refid = insertRefid(nd->getOutputFileBase());
- bindIntParameter(innernamespace_insert,":refid",refid);
- bindTextParameter(innernamespace_insert,":name",nd->name(),FALSE);
- step(innernamespace_insert);
+ struct Refid inner_refid = insertRefid(nd->getOutputFileBase());
+
+ bindIntParameter(contains_insert,":inner_rowid",inner_refid.rowid);
+ bindIntParameter(contains_insert,":outer_rowid",outer_refid.rowid);
+ step(contains_insert);
}
}
}
@@ -837,24 +1386,24 @@ static void writeTemplateArgumentList(const ArgumentList * al,
if (!a->type.isEmpty())
{
#warning linkifyText(TextGeneratorXMLImpl(t),scope,fileScope,0,a->type);
- bindTextParameter(params_select,":type",a->type);
- bindTextParameter(params_insert,":type",a->type);
+ bindTextParameter(param_select,":type",a->type);
+ bindTextParameter(param_insert,":type",a->type);
}
if (!a->name.isEmpty())
{
- bindTextParameter(params_select,":declname",a->name);
- bindTextParameter(params_insert,":declname",a->name);
- bindTextParameter(params_select,":defname",a->name);
- bindTextParameter(params_insert,":defname",a->name);
+ bindTextParameter(param_select,":declname",a->name);
+ bindTextParameter(param_insert,":declname",a->name);
+ bindTextParameter(param_select,":defname",a->name);
+ bindTextParameter(param_insert,":defname",a->name);
}
if (!a->defval.isEmpty())
{
#warning linkifyText(TextGeneratorXMLImpl(t),scope,fileScope,0,a->defval);
- bindTextParameter(params_select,":defval",a->defval);
- bindTextParameter(params_insert,":defval",a->defval);
+ bindTextParameter(param_select,":defval",a->defval);
+ bindTextParameter(param_insert,":defval",a->defval);
}
- if (!step(params_select,TRUE,TRUE))
- step(params_insert);
+ if (!step(param_select,TRUE,TRUE))
+ step(param_insert);
}
}
}
@@ -871,15 +1420,132 @@ static void writeTemplateList(const ClassDef *cd)
{
writeTemplateArgumentList(cd->templateArguments(),cd,0);
}
+
+QCString getSQLDocBlock(const Definition *scope,
+ const Definition *def,
+ const QCString &doc,
+ const QCString &fileName,
+ int lineNr)
+{
+ QGString s;
+ if (doc.isEmpty()) return s.data();
+ FTextStream t(&s);
+ DocNode *root = validatingParseDoc(
+ fileName,
+ lineNr,
+ const_cast<Definition*>(scope),
+ const_cast<MemberDef*>(reinterpret_cast<const MemberDef*>(def)),
+ doc,
+ FALSE,
+ FALSE
+ );
+ XMLCodeGenerator codeGen(t);
+ // create a parse tree visitor for XML
+ XmlDocVisitor *visitor = new XmlDocVisitor(t,codeGen);
+ root->accept(visitor);
+ delete visitor;
+ delete root;
+ QCString result = convertCharEntitiesToUTF8(s.data());
+ return result.data();
+}
+
+static void getSQLDesc(SqlStmt &s,const char *col,const char *value,const Definition *def)
+{
+ bindTextParameter(
+ s,
+ col,
+ getSQLDocBlock(
+ def->getOuterScope(),
+ def,
+ value,
+ def->docFile(),
+ def->docLine()
+ ),
+ FALSE
+ );
+}
////////////////////////////////////////////
+/* (updated Sep 01 2018)
+DoxMemberKind and DoxCompoundKind (compound.xsd) gave me some
+faulty assumptions about "kind" strings, so I compiled a reference
+
+The XML schema claims:
+ DoxMemberKind: (14)
+ dcop define enum event friend function interface property prototype
+ service signal slot typedef variable
+
+ DoxCompoundKind: (17)
+ category class dir example exception file group interface module
+ namespace page protocol service singleton struct type union
+
+Member kind comes from MemberDef::memberTypeName()
+ types.h defines 14 MemberType_*s
+ _DCOP _Define _Enumeration _EnumValue _Event _Friend _Function _Interface
+ _Property _Service _Signal _Slot _Typedef _Variable
+ - xml doesn't include enumvalue here
+ (but renders enumvalue as) a sub-node of memberdef/templateparamlist
+ - xml includes 'prototype' that is unlisted here
+ vestigial? commented out in docsets.cpp and perlmodgen.cpp
+ MemberDef::memberTypeName() can return 15 strings:
+ (sorted by MemberType to match above; quoted because whitespace...)
+ "dcop" "macro definition" "enumeration" "enumvalue" "event" "friend"
+ "function" "interface" "property" "service" "signal" "slot" "typedef"
+ "variable"
+
+ Above describes potential values for memberdef.kind
+
+Compound kind is more complex. *Def::compoundTypeString()
+ ClassDef kind comes from ::compoundTypeString()
+ classdef.h defines 9 compound types
+ Category Class Exception Interface Protocol Service Singleton Struct Union
+ But ClassDef::compoundTypeString() "could" return 13 strings
+ - default "unknown" shouldn't actually return
+ - other 12 can vary by source language; see method for specifics
+ category class enum exception interface module protocol service
+ singleton struct type union
+
+ DirDef, FileDef, GroupDef have no method to return a string
+ tagfile/outputs hard-code kind to 'dir' 'file' or 'group'
+
+ NamespaceDef kind comes from ::compoundTypeString()
+ NamespaceDef::compoundTypeString() "could" return 6 strings
+ - default empty ("") string
+ - other 5 differ by source language
+ constants library module namespace package
+
+ PageDef also has no method to return a string
+ - some locations hard-code the kind to 'page'
+ - others conditionally output 'page' or 'example'
+
+ All together, that's 23 potential strings (21 excl "" and unknown)
+ "" category class constants dir enum example exception file group
+ interface library module namespace package page protocol service singleton
+ struct type union unknown
+
+ Above describes potential values for compounddef.kind
+
+For reference, there are 35 potential values of def.kind (33 excl "" and unknown):
+ "" "category" "class" "constants" "dcop" "dir" "enum" "enumeration"
+ "enumvalue" "event" "example" "exception" "file" "friend" "function" "group"
+ "interface" "library" "macro definition" "module" "namespace" "package"
+ "page" "property" "protocol" "service" "signal" "singleton" "slot" "struct"
+ "type" "typedef" "union" "unknown" "variable"
+
+This is relevant because the 'def' view generalizes memberdef and compounddef,
+and two member+compound kind strings (interface and service) overlap.
+
+I have no grasp of whether a real user docset would include one or more
+member and compound using the interface or service kind.
+*/
+
//////////////////////////////////////////////////////////////////////////////
-static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
+static void generateSqlite3ForMember(const MemberDef *md, struct Refid scope_refid, const Definition *def)
{
// + declaration/definition arg lists
// + reimplements
// + reimplementedBy
- // + exceptions
+ // - exceptions
// + const/volatile specifiers
// - examples
// + source definition
@@ -893,18 +1559,102 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
// enum values are written as part of the enum
if (md->memberType()==MemberType_EnumValue) return;
if (md->isHidden()) return;
- //if (md->name().at(0)=='@') return; // anonymous member
- // group members are only visible in their group
- //if (def->definitionType()!=Definition::TypeGroup && md->getGroupDef()) return;
QCString memType;
// memberdef
QCString qrefid = md->getOutputFileBase() + "_1" + md->anchor();
- int refid = insertRefid(qrefid.data());
+ struct Refid refid = insertRefid(qrefid);
+
+ associateMember(md, refid, scope_refid);
+
+ // compacting duplicate defs
+ if(!refid.created && memberdefExists(refid) && memberdefIncomplete(refid, md))
+ {
+ /*
+ For performance, ideal to skip a member we've already added.
+ Unfortunately, we can have two memberdefs with the same refid documenting
+ the declaration and definition. memberdefIncomplete() uses the 'inline'
+ value to figure this out. Once we get to this point, we should *only* be
+ seeing the *other* type of def/decl, so we'll set inline to a new value (2),
+ indicating that this entry covers both inline types.
+ */
+ struct SqlStmt memberdef_update;
+
+ // definitions have bodyfile/start/end
+ if (md->getStartBodyLine()!=-1)
+ {
+ memberdef_update = memberdef_update_def;
+ int bodyfile_id = insertPath(md->getBodyDef()->absFilePath(),!md->getBodyDef()->isReference());
+ if (bodyfile_id == -1)
+ {
+ sqlite3_clear_bindings(memberdef_update.stmt);
+ }
+ else
+ {
+ bindIntParameter(memberdef_update,":bodyfile_id",bodyfile_id);
+ bindIntParameter(memberdef_update,":bodystart",md->getStartBodyLine());
+ bindIntParameter(memberdef_update,":bodyend",md->getEndBodyLine());
+ }
+ }
+ // declarations don't
+ else
+ {
+ memberdef_update = memberdef_update_decl;
+ if (md->getDefLine() != -1)
+ {
+ int file_id = insertPath(md->getDefFileName(),!md->isReference());
+ if (file_id!=-1)
+ {
+ bindIntParameter(memberdef_update,":file_id",file_id);
+ bindIntParameter(memberdef_update,":line",md->getDefLine());
+ bindIntParameter(memberdef_update,":column",md->getDefColumn());
+ }
+ }
+ }
- bindIntParameter(memberdef_insert,":refid", refid);
- bindIntParameter(memberdef_insert,":kind",md->memberType());
+ bindIntParameter(memberdef_update, ":rowid", refid.rowid);
+ // value 2 indicates we've seen "both" inline types.
+ bindIntParameter(memberdef_update,":inline", 2);
+
+ /* in case both are used, append/prepend descriptions */
+ getSQLDesc(memberdef_update,":briefdescription",md->briefDescription(),md);
+ getSQLDesc(memberdef_update,":detaileddescription",md->documentation(),md);
+ getSQLDesc(memberdef_update,":inbodydescription",md->inbodyDocumentation(),md);
+
+ step(memberdef_update,TRUE);
+
+ // don't think we need to repeat params; should have from first encounter
+
+ // + source references
+ // The cross-references in initializers only work when both the src and dst
+ // are defined.
+ MemberSDict *mdict = md->getReferencesMembers();
+ if (mdict!=0)
+ {
+ MemberSDict::IteratorDict mdi(*mdict);
+ const MemberDef *rmd;
+ for (mdi.toFirst();(rmd=mdi.current());++mdi)
+ {
+ insertMemberReference(md,rmd, "inline");
+ }
+ }
+ // + source referenced by
+ mdict = md->getReferencedByMembers();
+ if (mdict!=0)
+ {
+ MemberSDict::IteratorDict mdi(*mdict);
+ const MemberDef *rmd;
+ for (mdi.toFirst();(rmd=mdi.current());++mdi)
+ {
+ insertMemberReference(rmd,md, "inline");
+ }
+ }
+ return;
+ }
+
+ bindIntParameter(memberdef_insert,":rowid", refid.rowid);
+ bindTextParameter(memberdef_insert,":kind",md->memberTypeName(),FALSE);
bindIntParameter(memberdef_insert,":prot",md->protection());
bindIntParameter(memberdef_insert,":static",md->isStatic());
@@ -973,6 +1723,7 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
bindIntParameter(memberdef_insert,":settable",md->isSettable());
bindIntParameter(memberdef_insert,":privatesettable",md->isPrivateSettable());
bindIntParameter(memberdef_insert,":protectedsettable",md->isProtectedSettable());
+
if (md->isAssign() || md->isCopy() || md->isRetain()
|| md->isStrong() || md->isWeak())
{
@@ -995,6 +1746,18 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
bindIntParameter(memberdef_insert,":raisable",md->isRaisable());
}
+ const MemberDef *rmd = md->reimplements();
+ if(rmd)
+ {
+ QCString qreimplemented_refid = rmd->getOutputFileBase() + "_1" + rmd->anchor();
+
+ struct Refid reimplemented_refid = insertRefid(qreimplemented_refid);
+
+ bindIntParameter(reimplements_insert,":memberdef_rowid", refid.rowid);
+ bindIntParameter(reimplements_insert,":reimplemented_rowid", reimplemented_refid.rowid);
+ step(reimplements_insert,TRUE);
+ }
+
// + declaration/definition arg lists
if (md->memberType()!=MemberType_Define &&
md->memberType()!=MemberType_Enumeration
@@ -1008,9 +1771,9 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
stripQualifiers(typeStr);
StringList l;
linkifyText(TextGeneratorSqlite3Impl(l), def, md->getBodyDef(),md,typeStr);
- if (typeStr.data())
+ if (typeStr)
{
- bindTextParameter(memberdef_insert,":type",typeStr.data(),FALSE);
+ bindTextParameter(memberdef_insert,":type",typeStr,FALSE);
}
if (md->definition())
@@ -1029,7 +1792,7 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
// Extract references from initializer
if (md->hasMultiLineInitializer() || md->hasOneLineInitializer())
{
- bindTextParameter(memberdef_insert,":initializer",md->initializer().data());
+ bindTextParameter(memberdef_insert,":initializer",md->initializer());
StringList l;
linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,md->initializer());
@@ -1044,11 +1807,10 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
s->data(),
md->getBodyDef()->getDefFileName().data(),
md->getStartBodyLine()));
- QCString qrefid_src = md->getOutputFileBase() + "_1" + md->anchor();
- int refid_src = insertRefid(qrefid_src.data());
- int refid_dst = insertRefid(s->data());
- int id_file = insertFile(stripFromPath(md->getBodyDef()->getDefFileName()));
- insertMemberReference(refid_src,refid_dst,id_file,md->getStartBodyLine(),-1);
+ QCString qsrc_refid = md->getOutputFileBase() + "_1" + md->anchor();
+ struct Refid src_refid = insertRefid(qsrc_refid);
+ struct Refid dst_refid = insertRefid(s->data());
+ insertMemberReference(src_refid,dst_refid, "initializer");
}
++li;
}
@@ -1056,34 +1818,35 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
if ( md->getScopeString() )
{
- bindTextParameter(memberdef_insert,":scope",md->getScopeString().data(),FALSE);
+ bindTextParameter(memberdef_insert,":scope",md->getScopeString(),FALSE);
}
// +Brief, detailed and inbody description
- bindTextParameter(memberdef_insert,":briefdescription",md->briefDescription(),FALSE);
- bindTextParameter(memberdef_insert,":detaileddescription",md->documentation(),FALSE);
- bindTextParameter(memberdef_insert,":inbodydescription",md->inbodyDocumentation(),FALSE);
+ getSQLDesc(memberdef_insert,":briefdescription",md->briefDescription(),md);
+ getSQLDesc(memberdef_insert,":detaileddescription",md->documentation(),md);
+ getSQLDesc(memberdef_insert,":inbodydescription",md->inbodyDocumentation(),md);
// File location
if (md->getDefLine() != -1)
{
- int id_file = insertFile(stripFromPath(md->getDefFileName()));
- if (id_file!=-1)
+ int file_id = insertPath(md->getDefFileName(),!md->isReference());
+ if (file_id!=-1)
{
- bindIntParameter(memberdef_insert,":id_file",id_file);
+ bindIntParameter(memberdef_insert,":file_id",file_id);
bindIntParameter(memberdef_insert,":line",md->getDefLine());
bindIntParameter(memberdef_insert,":column",md->getDefColumn());
+ // definitions also have bodyfile/start/end
if (md->getStartBodyLine()!=-1)
{
- int id_bodyfile = insertFile(stripFromPath(md->getBodyDef()->absFilePath()));
- if (id_bodyfile == -1)
+ int bodyfile_id = insertPath(md->getBodyDef()->absFilePath(),!md->getBodyDef()->isReference());
+ if (bodyfile_id == -1)
{
sqlite3_clear_bindings(memberdef_insert.stmt);
}
else
{
- bindIntParameter(memberdef_insert,":id_bodyfile",id_bodyfile);
+ bindIntParameter(memberdef_insert,":bodyfile_id",bodyfile_id);
bindIntParameter(memberdef_insert,":bodystart",md->getStartBodyLine());
bindIntParameter(memberdef_insert,":bodyend",md->getEndBodyLine());
}
@@ -1091,16 +1854,16 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
}
}
- int id_memberdef=step(memberdef_insert,TRUE);
+ int memberdef_id=step(memberdef_insert,TRUE);
if (isFunc)
{
- insertMemberFunctionParams(id_memberdef,md,def);
+ insertMemberFunctionParams(memberdef_id,md,def);
}
else if (md->memberType()==MemberType_Define &&
md->argsString())
{
- insertMemberDefineParams(id_memberdef,md,def);
+ insertMemberDefineParams(memberdef_id,md,def);
}
// + source references
@@ -1110,10 +1873,10 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
if (mdict!=0)
{
MemberSDict::IteratorDict mdi(*mdict);
- MemberDef *rmd;
+ const MemberDef *rmd;
for (mdi.toFirst();(rmd=mdi.current());++mdi)
{
- insertMemberReference(md,rmd);//,mdi.currentKey());
+ insertMemberReference(md,rmd, "inline");
}
}
// + source referenced by
@@ -1121,62 +1884,79 @@ static void generateSqlite3ForMember(const MemberDef *md, const Definition *def)
if (mdict!=0)
{
MemberSDict::IteratorDict mdi(*mdict);
- MemberDef *rmd;
+ const MemberDef *rmd;
for (mdi.toFirst();(rmd=mdi.current());++mdi)
{
- insertMemberReference(rmd,md);//,mdi.currentKey());
+ insertMemberReference(rmd,md, "inline");
}
}
}
static void generateSqlite3Section( const Definition *d,
const MemberList *ml,
+ struct Refid scope_refid,
const char * /*kind*/,
const char * /*header*/=0,
const char * /*documentation*/=0)
{
if (ml==0) return;
MemberListIterator mli(*ml);
- MemberDef *md;
- int count=0;
+ const MemberDef *md;
+
for (mli.toFirst();(md=mli.current());++mli)
{
+ // TODO: necessary? just tracking what xmlgen does; xmlgen says:
// namespace members are also inserted in the file scope, but
// to prevent this duplication in the XML output, we filter those here.
if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0)
{
- count++;
+ generateSqlite3ForMember(md, scope_refid, d);
}
}
- if (count==0) return; // empty list
- for (mli.toFirst();(md=mli.current());++mli)
+}
+
+static void associateAllClassMembers(const ClassDef *cd, struct Refid scope_refid)
+{
+ if (cd->memberNameInfoSDict())
{
- // namespace members are also inserted in the file scope, but
- // to prevent this duplication in the XML output, we filter those here.
- //if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0)
+ MemberNameInfoSDict::Iterator mnii(*cd->memberNameInfoSDict());
+ MemberNameInfo *mni;
+ for (mnii.toFirst();(mni=mnii.current());++mnii)
{
- generateSqlite3ForMember(md,d);
+ MemberNameInfoIterator mii(*mni);
+ MemberInfo *mi;
+ for (mii.toFirst();(mi=mii.current());++mii)
+ {
+ MemberDef *md = mi->memberDef;
+ QCString qrefid = md->getOutputFileBase() + "_1" + md->anchor();
+ associateMember(md, insertRefid(qrefid), scope_refid);
+ }
}
}
}
-
+// many kinds: category class enum exception interface
+// module protocol service singleton struct type union
+// enum is Java only (and is distinct from enum memberdefs)
static void generateSqlite3ForClass(const ClassDef *cd)
{
+ // NOTE: Skeptical about XML's version of these
+ // 'x' marks missing items XML claims to include
+
+ // + brief description
+ // + detailed description
+ // + template argument list(s)
+ // + include file
+ // + member groups
+ // x inheritance DOT diagram
// + list of direct super classes
// + list of direct sub classes
- // + include file
// + list of inner classes
- // - template argument list(s)
- // + member groups
+ // x collaboration DOT diagram
// + list of all members
- // - brief description
- // - detailed description
- // - inheritance DOT diagram
- // - collaboration DOT diagram
- // - user defined member sections
- // - standard member sections
- // - detailed member documentation
+ // x user defined member sections
+ // x standard member sections
+ // x detailed member documentation
// - examples using the class
if (cd->isReference()) return; // skip external references.
@@ -1184,43 +1964,86 @@ static void generateSqlite3ForClass(const ClassDef *cd)
if (cd->name().find('@')!=-1) return; // skip anonymous compounds.
if (cd->templateMaster()!=0) return; // skip generated template instances.
- msg("Generating Sqlite3 output for class %s\n",cd->name().data());
+ struct Refid refid = insertRefid(cd->getOutputFileBase());
+
+ // can omit a class that already has a refid
+ if(!refid.created && compounddefExists(refid)){return;}
+
+ bindIntParameter(compounddef_insert,":rowid", refid.rowid);
bindTextParameter(compounddef_insert,":name",cd->name());
+ bindTextParameter(compounddef_insert,":title",cd->title(), FALSE);
bindTextParameter(compounddef_insert,":kind",cd->compoundTypeString(),FALSE);
bindIntParameter(compounddef_insert,":prot",cd->protection());
- int refid = insertRefid(cd->getOutputFileBase());
- bindIntParameter(compounddef_insert,":refid", refid);
- int id_file = insertFile(stripFromPath(cd->getDefFileName()));
- bindIntParameter(compounddef_insert,":id_file",id_file);
+ int file_id = insertPath(cd->getDefFileName());
+ bindIntParameter(compounddef_insert,":file_id",file_id);
bindIntParameter(compounddef_insert,":line",cd->getDefLine());
bindIntParameter(compounddef_insert,":column",cd->getDefColumn());
+ // + include file
+ /*
+ TODO: I wonder if this can actually be cut (just here)
+
+ We were adding this "include" to the "includes" table alongside
+ other includes (from a FileDef). However, FileDef and ClassDef are using
+ "includes" nodes in very a different way:
+ - With FileDef, it means the file includes another.
+ - With ClassDef, it means you should include this file to use this class.
+
+ Because of this difference, I added a column to compounddef, header_id, and
+ linked it back to the appropriate file. We could just add a nullable text
+ column that would hold a string equivalent to what the HTML docs include,
+ but the logic for generating it is embedded in
+ ClassDef::writeIncludeFiles(OutputList &ol).
+
+ That said, at least on the handful of test sets I have, header_id == file_id,
+ suggesting it could be cut and clients might be able to reconstruct it from
+ other values if there's a solid heuristic for *when a class will
+ have a header file*.
+ */
+ IncludeInfo *ii=cd->includeInfo();
+ if (ii)
+ {
+ QCString nm = ii->includeName;
+ if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName();
+ if (!nm.isEmpty())
+ {
+ int header_id=insertPath(ii->fileDef->absFilePath(),!ii->fileDef->isReference());
+ DBG_CTX(("-----> ClassDef includeInfo for %s\n", nm.data()));
+ DBG_CTX((" local : %d\n", ii->local));
+ DBG_CTX((" imported : %d\n", ii->imported));
+ DBG_CTX((" indirect : %d\n", ii->indirect));
+ DBG_CTX(("header: %s\n", ii->fileDef->absFilePath().data()));
+ DBG_CTX((" file_id : %d\n", file_id));
+ DBG_CTX((" header_id: %d\n", header_id));
+
+ if(header_id!=-1)
+ {
+ bindIntParameter(compounddef_insert,":header_id",header_id);
+ }
+ }
+ }
+
+ getSQLDesc(compounddef_insert,":briefdescription",cd->briefDescription(),cd);
+ getSQLDesc(compounddef_insert,":detaileddescription",cd->documentation(),cd);
+
step(compounddef_insert);
// + list of direct super classes
if (cd->baseClasses())
{
BaseClassListIterator bcli(*cd->baseClasses());
- BaseClassDef *bcd;
+ const BaseClassDef *bcd;
for (bcli.toFirst();(bcd=bcli.current());++bcli)
{
- int refid = insertRefid(bcd->classDef->getOutputFileBase());
- bindIntParameter(basecompoundref_insert,":refid", refid);
- bindIntParameter(basecompoundref_insert,":prot",bcd->prot);
- bindIntParameter(basecompoundref_insert,":virt",bcd->virt);
-
- if (!bcd->templSpecifiers.isEmpty())
- {
- bindTextParameter(basecompoundref_insert,":base",insertTemplateSpecifierInScope(bcd->classDef->name(),bcd->templSpecifiers),FALSE);
- }
- else
- {
- bindTextParameter(basecompoundref_insert,":base",bcd->classDef->displayName(),FALSE);
- }
- bindTextParameter(basecompoundref_insert,":derived",cd->displayName(),FALSE);
- step(basecompoundref_insert);
+ struct Refid base_refid = insertRefid(bcd->classDef->getOutputFileBase());
+ struct Refid derived_refid = insertRefid(cd->getOutputFileBase());
+ bindIntParameter(compoundref_insert,":base_rowid", base_refid.rowid);
+ bindIntParameter(compoundref_insert,":derived_rowid", derived_refid.rowid);
+ bindIntParameter(compoundref_insert,":prot",bcd->prot);
+ bindIntParameter(compoundref_insert,":virt",bcd->virt);
+ step(compoundref_insert);
}
}
@@ -1228,54 +2051,23 @@ static void generateSqlite3ForClass(const ClassDef *cd)
if (cd->subClasses())
{
BaseClassListIterator bcli(*cd->subClasses());
- BaseClassDef *bcd;
+ const BaseClassDef *bcd;
for (bcli.toFirst();(bcd=bcli.current());++bcli)
{
- bindTextParameter(derivedcompoundref_insert,":base",cd->displayName(),FALSE);
- if (!bcd->templSpecifiers.isEmpty())
- {
- bindTextParameter(derivedcompoundref_insert,":derived",insertTemplateSpecifierInScope(bcd->classDef->name(),bcd->templSpecifiers),FALSE);
- }
- else
- {
- bindTextParameter(derivedcompoundref_insert,":derived",bcd->classDef->displayName(),FALSE);
- }
- int refid = insertRefid(bcd->classDef->getOutputFileBase());
- bindIntParameter(derivedcompoundref_insert,":refid", refid);
- bindIntParameter(derivedcompoundref_insert,":prot",bcd->prot);
- bindIntParameter(derivedcompoundref_insert,":virt",bcd->virt);
- step(derivedcompoundref_insert);
+ struct Refid derived_refid = insertRefid(bcd->classDef->getOutputFileBase());
+ struct Refid base_refid = insertRefid(cd->getOutputFileBase());
+ bindIntParameter(compoundref_insert,":base_rowid", base_refid.rowid);
+ bindIntParameter(compoundref_insert,":derived_rowid", derived_refid.rowid);
+ bindIntParameter(compoundref_insert,":prot",bcd->prot);
+ bindIntParameter(compoundref_insert,":virt",bcd->virt);
+ step(compoundref_insert);
}
}
- // + include file
- IncludeInfo *ii=cd->includeInfo();
- if (ii)
- {
- QCString nm = ii->includeName;
- if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName();
- if (!nm.isEmpty())
- {
- int id_dst=insertFile(nm);
- if (id_dst!=-1) {
- bindIntParameter(incl_select,":local",ii->local);
- bindIntParameter(incl_select,":id_src",id_file);
- bindIntParameter(incl_select,":id_dst",id_dst);
- int count=step(incl_select,TRUE,TRUE);
- if (count==0)
- {
- bindIntParameter(incl_insert,":local",ii->local);
- bindIntParameter(incl_insert,":id_src",id_file);
- bindIntParameter(incl_insert,":id_dst",id_dst);
- step(incl_insert);
- }
- }
- }
- }
// + list of inner classes
- writeInnerClasses(cd->getClassSDict());
+ writeInnerClasses(cd->getClassSDict(),refid);
- // - template argument list(s)
+ // + template argument list(s)
writeTemplateList(cd);
// + member groups
@@ -1285,41 +2077,62 @@ static void generateSqlite3ForClass(const ClassDef *cd)
MemberGroup *mg;
for (;(mg=mgli.current());++mgli)
{
- generateSqlite3Section(cd,mg->members(),"user-defined",mg->header(),
+ generateSqlite3Section(cd,mg->members(),refid,"user-defined",mg->header(),
mg->documentation());
}
}
- // + list of all members
+ // this is just a list of *local* members
QListIterator<MemberList> mli(cd->getMemberLists());
MemberList *ml;
for (mli.toFirst();(ml=mli.current());++mli)
{
if ((ml->listType()&MemberListType_detailedLists)==0)
{
- generateSqlite3Section(cd,ml,"user-defined");//g_xmlSectionMapper.find(ml->listType()));
+ generateSqlite3Section(cd,ml,refid,"user-defined");
}
}
+
+ // + list of all members
+ associateAllClassMembers(cd, refid);
}
+// kinds: constants library module namespace package
static void generateSqlite3ForNamespace(const NamespaceDef *nd)
{
// + contained class definitions
// + contained namespace definitions
// + member groups
// + normal members
- // - brief desc
- // - detailed desc
- // - location
+ // + brief desc
+ // + detailed desc
+ // + location (file_id, line, column)
// - files containing (parts of) the namespace definition
if (nd->isReference() || nd->isHidden()) return; // skip external references
+ struct Refid refid = insertRefid(nd->getOutputFileBase());
+ if(!refid.created && compounddefExists(refid)){return;}
+ bindIntParameter(compounddef_insert,":rowid", refid.rowid);
+
+ bindTextParameter(compounddef_insert,":name",nd->name());
+ bindTextParameter(compounddef_insert,":title",nd->title(), FALSE);
+ bindTextParameter(compounddef_insert,":kind","namespace",FALSE);
+
+ int file_id = insertPath(nd->getDefFileName());
+ bindIntParameter(compounddef_insert,":file_id",file_id);
+ bindIntParameter(compounddef_insert,":line",nd->getDefLine());
+ bindIntParameter(compounddef_insert,":column",nd->getDefColumn());
+
+ getSQLDesc(compounddef_insert,":briefdescription",nd->briefDescription(),nd);
+ getSQLDesc(compounddef_insert,":detaileddescription",nd->documentation(),nd);
+
+ step(compounddef_insert);
// + contained class definitions
- writeInnerClasses(nd->getClassSDict());
+ writeInnerClasses(nd->getClassSDict(),refid);
// + contained namespace definitions
- writeInnerNamespaces(nd->getNamespaceSDict());
+ writeInnerNamespaces(nd->getNamespaceSDict(),refid);
// + member groups
if (nd->getMemberGroupSDict())
@@ -1328,7 +2141,7 @@ static void generateSqlite3ForNamespace(const NamespaceDef *nd)
MemberGroup *mg;
for (;(mg=mgli.current());++mgli)
{
- generateSqlite3Section(nd,mg->members(),"user-defined",mg->header(),
+ generateSqlite3Section(nd,mg->members(),refid,"user-defined",mg->header(),
mg->documentation());
}
}
@@ -1340,29 +2153,48 @@ static void generateSqlite3ForNamespace(const NamespaceDef *nd)
{
if ((ml->listType()&MemberListType_declarationLists)!=0)
{
- generateSqlite3Section(nd,ml,"user-defined");//g_xmlSectionMapper.find(ml->listType()));
+ generateSqlite3Section(nd,ml,refid,"user-defined");
}
}
}
+// kind: file
static void generateSqlite3ForFile(const FileDef *fd)
{
// + includes files
// + includedby files
- // - include graph
- // - included by graph
+ // x include graph
+ // x included by graph
// + contained class definitions
// + contained namespace definitions
// + member groups
// + normal members
- // - brief desc
- // - detailed desc
- // - source code
- // - location
+ // + brief desc
+ // + detailed desc
+ // x source code
+ // + location (file_id, line, column)
// - number of lines
if (fd->isReference()) return; // skip external references
+ struct Refid refid = insertRefid(fd->getOutputFileBase());
+ if(!refid.created && compounddefExists(refid)){return;}
+ bindIntParameter(compounddef_insert,":rowid", refid.rowid);
+
+ bindTextParameter(compounddef_insert,":name",fd->name(),FALSE);
+ bindTextParameter(compounddef_insert,":title",fd->title(),FALSE);
+ bindTextParameter(compounddef_insert,":kind","file",FALSE);
+
+ int file_id = insertPath(fd->getDefFileName());
+ bindIntParameter(compounddef_insert,":file_id",file_id);
+ bindIntParameter(compounddef_insert,":line",fd->getDefLine());
+ bindIntParameter(compounddef_insert,":column",fd->getDefColumn());
+
+ getSQLDesc(compounddef_insert,":briefdescription",fd->briefDescription(),fd);
+ getSQLDesc(compounddef_insert,":detaileddescription",fd->documentation(),fd);
+
+ step(compounddef_insert);
+
// + includes files
IncludeInfo *ii;
if (fd->includeFileList())
@@ -1370,15 +2202,48 @@ static void generateSqlite3ForFile(const FileDef *fd)
QListIterator<IncludeInfo> ili(*fd->includeFileList());
for (ili.toFirst();(ii=ili.current());++ili)
{
- int id_src=insertFile(fd->absFilePath().data());
- int id_dst=insertFile(ii->includeName.data());
+ int src_id=insertPath(fd->absFilePath(),!fd->isReference());
+ int dst_id;
+ QCString dst_path;
+
+ if(ii->fileDef) // found file
+ {
+ if(ii->fileDef->isReference())
+ {
+ // strip tagfile from path
+ QCString tagfile = ii->fileDef->getReference();
+ dst_path = ii->fileDef->absFilePath().copy();
+ dst_path.stripPrefix(tagfile+":");
+ }
+ else
+ {
+ dst_path = ii->fileDef->absFilePath();
+ }
+ dst_id = insertPath(dst_path,ii->local);
+ }
+ else // can't find file
+ {
+ dst_id = insertPath(ii->includeName,ii->local,FALSE);
+ }
+
+ DBG_CTX(("-----> FileDef includeInfo for %s\n", ii->includeName.data()));
+ DBG_CTX((" local: %d\n", ii->local));
+ DBG_CTX((" imported: %d\n", ii->imported));
+ DBG_CTX((" indirect: %d\n", ii->indirect));
+ if(ii->fileDef)
+ {
+ DBG_CTX(("include: %s\n", ii->fileDef->absFilePath().data()));
+ }
+ DBG_CTX((" src_id : %d\n", src_id));
+ DBG_CTX((" dst_id: %d\n", dst_id));
+
bindIntParameter(incl_select,":local",ii->local);
- bindIntParameter(incl_select,":id_src",id_src);
- bindIntParameter(incl_select,":id_dst",id_dst);
+ bindIntParameter(incl_select,":src_id",src_id);
+ bindIntParameter(incl_select,":dst_id",dst_id);
if (step(incl_select,TRUE,TRUE)==0) {
bindIntParameter(incl_insert,":local",ii->local);
- bindIntParameter(incl_insert,":id_src",id_src);
- bindIntParameter(incl_insert,":id_dst",id_dst);
+ bindIntParameter(incl_insert,":src_id",src_id);
+ bindIntParameter(incl_insert,":dst_id",dst_id);
step(incl_insert);
}
}
@@ -1390,15 +2255,37 @@ static void generateSqlite3ForFile(const FileDef *fd)
QListIterator<IncludeInfo> ili(*fd->includedByFileList());
for (ili.toFirst();(ii=ili.current());++ili)
{
- int id_src=insertFile(ii->includeName);
- int id_dst=insertFile(fd->absFilePath());
+ int dst_id=insertPath(fd->absFilePath(),!fd->isReference());
+ int src_id;
+ QCString src_path;
+
+ if(ii->fileDef) // found file
+ {
+ if(ii->fileDef->isReference())
+ {
+ // strip tagfile from path
+ QCString tagfile = ii->fileDef->getReference();
+ src_path = ii->fileDef->absFilePath().copy();
+ src_path.stripPrefix(tagfile+":");
+ }
+ else
+ {
+ src_path = ii->fileDef->absFilePath();
+ }
+ src_id = insertPath(src_path,ii->local);
+ }
+ else // can't find file
+ {
+ src_id = insertPath(ii->includeName,ii->local,FALSE);
+ }
+
bindIntParameter(incl_select,":local",ii->local);
- bindIntParameter(incl_select,":id_src",id_src);
- bindIntParameter(incl_select,":id_dst",id_dst);
+ bindIntParameter(incl_select,":src_id",src_id);
+ bindIntParameter(incl_select,":dst_id",dst_id);
if (step(incl_select,TRUE,TRUE)==0) {
bindIntParameter(incl_insert,":local",ii->local);
- bindIntParameter(incl_insert,":id_src",id_src);
- bindIntParameter(incl_insert,":id_dst",id_dst);
+ bindIntParameter(incl_insert,":src_id",src_id);
+ bindIntParameter(incl_insert,":dst_id",dst_id);
step(incl_insert);
}
}
@@ -1407,13 +2294,13 @@ static void generateSqlite3ForFile(const FileDef *fd)
// + contained class definitions
if (fd->getClassSDict())
{
- writeInnerClasses(fd->getClassSDict());
+ writeInnerClasses(fd->getClassSDict(),refid);
}
// + contained namespace definitions
if (fd->getNamespaceSDict())
{
- writeInnerNamespaces(fd->getNamespaceSDict());
+ writeInnerNamespaces(fd->getNamespaceSDict(),refid);
}
// + member groups
@@ -1423,7 +2310,7 @@ static void generateSqlite3ForFile(const FileDef *fd)
MemberGroup *mg;
for (;(mg=mgli.current());++mgli)
{
- generateSqlite3Section(fd,mg->members(),"user-defined",mg->header(),
+ generateSqlite3Section(fd,mg->members(),refid,"user-defined",mg->header(),
mg->documentation());
}
}
@@ -1435,24 +2322,201 @@ static void generateSqlite3ForFile(const FileDef *fd)
{
if ((ml->listType()&MemberListType_declarationLists)!=0)
{
- generateSqlite3Section(fd,ml,"user-defined");//g_xmlSectionMapper.find(ml->listType()));
+ generateSqlite3Section(fd,ml,refid,"user-defined");
}
}
}
+// kind: group
static void generateSqlite3ForGroup(const GroupDef *gd)
{
-#warning WorkInProgress
+ // + members
+ // + member groups
+ // + files
+ // + classes
+ // + namespaces
+ // - packages
+ // + pages
+ // + child groups
+ // - examples
+ // + brief description
+ // + detailed description
+
+ if (gd->isReference()) return; // skip external references.
+
+ struct Refid refid = insertRefid(gd->getOutputFileBase());
+ if(!refid.created && compounddefExists(refid)){return;}
+ bindIntParameter(compounddef_insert,":rowid", refid.rowid);
+
+ bindTextParameter(compounddef_insert,":name",gd->name());
+ bindTextParameter(compounddef_insert,":title",gd->groupTitle(), FALSE);
+ bindTextParameter(compounddef_insert,":kind","group",FALSE);
+
+ int file_id = insertPath(gd->getDefFileName());
+ bindIntParameter(compounddef_insert,":file_id",file_id);
+ bindIntParameter(compounddef_insert,":line",gd->getDefLine());
+ bindIntParameter(compounddef_insert,":column",gd->getDefColumn());
+
+ getSQLDesc(compounddef_insert,":briefdescription",gd->briefDescription(),gd);
+ getSQLDesc(compounddef_insert,":detaileddescription",gd->documentation(),gd);
+
+ step(compounddef_insert);
+
+ // + files
+ writeInnerFiles(gd->getFiles(),refid);
+
+ // + classes
+ writeInnerClasses(gd->getClasses(),refid);
+
+ // + namespaces
+ writeInnerNamespaces(gd->getNamespaces(),refid);
+
+ // + pages
+ writeInnerPages(gd->getPages(),refid);
+
+ // + groups
+ writeInnerGroups(gd->getSubGroups(),refid);
+
+ // + member groups
+ if (gd->getMemberGroupSDict())
+ {
+ MemberGroupSDict::Iterator mgli(*gd->getMemberGroupSDict());
+ MemberGroup *mg;
+ for (;(mg=mgli.current());++mgli)
+ {
+ generateSqlite3Section(gd,mg->members(),refid,"user-defined",mg->header(),
+ mg->documentation());
+ }
+ }
+
+ // + members
+ QListIterator<MemberList> mli(gd->getMemberLists());
+ MemberList *ml;
+ for (mli.toFirst();(ml=mli.current());++mli)
+ {
+ if ((ml->listType()&MemberListType_declarationLists)!=0)
+ {
+ generateSqlite3Section(gd,ml,refid,"user-defined");
+ }
+ }
}
+// kind: dir
static void generateSqlite3ForDir(const DirDef *dd)
{
-#warning WorkInProgress
+ // + dirs
+ // + files
+ // + briefdescription
+ // + detaileddescription
+ // + location (below uses file_id, line, column; XML just uses file)
+ if (dd->isReference()) return; // skip external references
+
+ struct Refid refid = insertRefid(dd->getOutputFileBase());
+ if(!refid.created && compounddefExists(refid)){return;}
+ bindIntParameter(compounddef_insert,":rowid", refid.rowid);
+
+ bindTextParameter(compounddef_insert,":name",dd->displayName());
+ bindTextParameter(compounddef_insert,":kind","dir",FALSE);
+
+ int file_id = insertPath(dd->getDefFileName(),TRUE,TRUE,2);
+ bindIntParameter(compounddef_insert,":file_id",file_id);
+
+ /*
+ line and column are weird here, but:
+ - dir goes into compounddef with all of the others
+ - the semantics would be fine if we set them to NULL here
+ - but defining line and column as NOT NULL is an important promise
+ for other compounds, so I don't want to loosen it
+
+ For reference, the queries return 1.
+ 0 or -1 make more sense, but I see that as a change for DirDef.
+ */
+ bindIntParameter(compounddef_insert,":line",dd->getDefLine());
+ bindIntParameter(compounddef_insert,":column",dd->getDefColumn());
+
+ getSQLDesc(compounddef_insert,":briefdescription",dd->briefDescription(),dd);
+ getSQLDesc(compounddef_insert,":detaileddescription",dd->documentation(),dd);
+
+ step(compounddef_insert);
+
+ // + files
+ writeInnerDirs(&dd->subDirs(),refid);
+
+ // + files
+ writeInnerFiles(dd->getFiles(),refid);
}
+// kinds: page, example
static void generateSqlite3ForPage(const PageDef *pd,bool isExample)
{
-#warning WorkInProgress
+ // + name
+ // + title
+ // + brief description
+ // + documentation (detailed description)
+ // + inbody documentation
+ // + sub pages
+ if (pd->isReference()) return; // skip external references.
+
+ // TODO: do we more special handling if isExample?
+
+ QCString qrefid = pd->getOutputFileBase();
+ if (pd->getGroupDef())
+ {
+ qrefid+=(QCString)"_"+pd->name();
+ }
+ if (qrefid=="index") qrefid="indexpage"; // to prevent overwriting the generated index page.
+
+ struct Refid refid = insertRefid(qrefid);
+
+ // can omit a page that already has a refid
+ if(!refid.created && compounddefExists(refid)){return;}
+
+ bindIntParameter(compounddef_insert,":rowid",refid.rowid);
+ // + name
+ bindTextParameter(compounddef_insert,":name",pd->name());
+
+ QCString title;
+ if (pd==Doxygen::mainPage) // main page is special
+ {
+ if (!pd->title().isEmpty() && pd->title().lower()!="notitle")
+ {
+ title = filterTitle(convertCharEntitiesToUTF8(Doxygen::mainPage->title()));
+ }
+ else
+ {
+ title = Config_getString(PROJECT_NAME);
+ }
+ }
+ else
+ {
+ SectionInfo *si = Doxygen::sectionDict->find(pd->name());
+ if (si)
+ {
+ title = si->title;
+ }
+
+ if(!title){title = pd->title();}
+ }
+
+ // + title
+ bindTextParameter(compounddef_insert,":title",title,FALSE);
+
+ bindTextParameter(compounddef_insert,":kind", isExample ? "example" : "page");
+
+ int file_id = insertPath(pd->getDefFileName());
+
+ bindIntParameter(compounddef_insert,":file_id",file_id);
+ bindIntParameter(compounddef_insert,":line",pd->getDefLine());
+ bindIntParameter(compounddef_insert,":column",pd->getDefColumn());
+
+ // + brief description
+ getSQLDesc(compounddef_insert,":briefdescription",pd->briefDescription(),pd);
+ // + documentation (detailed description)
+ getSQLDesc(compounddef_insert,":detaileddescription",pd->documentation(),pd);
+
+ step(compounddef_insert);
+ // + sub pages
+ writeInnerPages(pd->getSubPages(),refid);
}
@@ -1463,6 +2527,7 @@ static sqlite3* openDbConnection()
QDir sqlite3Dir(outputDirectory);
sqlite3 *db;
int rc;
+ struct stat buf;
rc = sqlite3_initialize();
if (rc != SQLITE_OK)
@@ -1470,7 +2535,21 @@ static sqlite3* openDbConnection()
msg("sqlite3_initialize failed\n");
return NULL;
}
- rc = sqlite3_open_v2(outputDirectory+"/doxygen_sqlite3.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
+
+
+ if (stat (outputDirectory+"/doxygen_sqlite3.db", &buf) == 0)
+ {
+ msg("doxygen_sqlite3.db already exists! aborting sqlite3 output generation!\n");
+ msg("If you wish to re-generate the database, remove or archive the existing copy first.\n");
+ return NULL;
+ }
+
+ rc = sqlite3_open_v2(
+ outputDirectory+"/doxygen_sqlite3.db",
+ &db,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+ 0
+ );
if (rc != SQLITE_OK)
{
sqlite3_close(db);
@@ -1497,10 +2576,16 @@ void generateSqlite3()
{
return;
}
+
+# ifdef SQLITE3_DEBUG
+ // debug: show all executed statements
+ sqlite3_trace(db, &sqlLog, NULL);
+# endif
+
beginTransaction(db);
pragmaTuning(db);
- if (-1==initializeSchema(db))
+ if (-1==initializeTables(db))
return;
if ( -1 == prepareStatements(db) )
@@ -1509,9 +2594,11 @@ void generateSqlite3()
return;
}
+ recordMetadata();
+
// + classes
ClassSDict::Iterator cli(*Doxygen::classSDict);
- ClassDef *cd;
+ const ClassDef *cd;
for (cli.toFirst();(cd=cli.current());++cli)
{
msg("Generating Sqlite3 output for class %s\n",cd->name().data());
@@ -1520,7 +2607,7 @@ void generateSqlite3()
// + namespaces
NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
- NamespaceDef *nd;
+ const NamespaceDef *nd;
for (nli.toFirst();(nd=nli.current());++nli)
{
msg("Generating Sqlite3 output for namespace %s\n",nd->name().data());
@@ -1533,7 +2620,7 @@ void generateSqlite3()
for (;(fn=fnli.current());++fnli)
{
FileNameIterator fni(*fn);
- FileDef *fd;
+ const FileDef *fd;
for (;(fd=fni.current());++fni)
{
msg("Generating Sqlite3 output for file %s\n",fd->name().data());
@@ -1543,7 +2630,7 @@ void generateSqlite3()
// + groups
GroupSDict::Iterator gli(*Doxygen::groupSDict);
- GroupDef *gd;
+ const GroupDef *gd;
for (;(gd=gli.current());++gli)
{
msg("Generating Sqlite3 output for group %s\n",gd->name().data());
@@ -1553,7 +2640,7 @@ void generateSqlite3()
// + page
{
PageSDict::Iterator pdi(*Doxygen::pageSDict);
- PageDef *pd=0;
+ const PageDef *pd=0;
for (pdi.toFirst();(pd=pdi.current());++pdi)
{
msg("Generating Sqlite3 output for page %s\n",pd->name().data());
@@ -1563,7 +2650,7 @@ void generateSqlite3()
// + dirs
{
- DirDef *dir;
+ const DirDef *dir;
DirSDict::Iterator sdi(*Doxygen::directories);
for (sdi.toFirst();(dir=sdi.current());++sdi)
{
@@ -1575,7 +2662,7 @@ void generateSqlite3()
// + examples
{
PageSDict::Iterator pdi(*Doxygen::exampleSDict);
- PageDef *pd=0;
+ const PageDef *pd=0;
for (pdi.toFirst();(pd=pdi.current());++pdi)
{
msg("Generating Sqlite3 output for example %s\n",pd->name().data());
@@ -1590,6 +2677,11 @@ void generateSqlite3()
generateSqlite3ForPage(Doxygen::mainPage,FALSE);
}
+ // TODO: copied from initializeSchema; not certain if we should say/do more
+ // if there's a failure here?
+ if (-1==initializeViews(db))
+ return;
+
endTransaction(db);
}
diff --git a/src/tagreader.cpp b/src/tagreader.cpp
index dfa8511..1afa30d 100644
--- a/src/tagreader.cpp
+++ b/src/tagreader.cpp
@@ -18,6 +18,7 @@
#include "tagreader.h"
+#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
@@ -27,7 +28,7 @@
#include <qfileinfo.h>
#include <qlist.h>
#include <qstring.h>
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include "entry.h"
#include "classdef.h"
@@ -95,17 +96,18 @@ class TagMemberInfo
class TagClassInfo
{
public:
- enum Kind { Class, Struct, Union, Interface, Exception, Protocol, Category, Enum, Service, Singleton };
- TagClassInfo() { bases=0, templateArguments=0; members.setAutoDelete(TRUE); isObjC=FALSE; }
+ enum Kind { None=-1, Class, Struct, Union, Interface, Exception, Protocol, Category, Enum, Service, Singleton };
+ TagClassInfo() { bases=0, templateArguments=0; members.setAutoDelete(TRUE); isObjC=FALSE; kind = None; }
~TagClassInfo() { delete bases; delete templateArguments; }
QCString name;
QCString filename;
QCString clangId;
+ QCString anchor;
TagAnchorInfoList docAnchors;
QList<BaseInfo> *bases;
QList<TagMemberInfo> members;
QList<QCString> *templateArguments;
- QStringList classList;
+ QCStringList classList;
Kind kind;
bool isObjC;
};
@@ -118,8 +120,8 @@ class TagNamespaceInfo
QCString name;
QCString filename;
QCString clangId;
- QStringList classList;
- QStringList namespaceList;
+ QCStringList classList;
+ QCStringList namespaceList;
TagAnchorInfoList docAnchors;
QList<TagMemberInfo> members;
};
@@ -133,7 +135,7 @@ class TagPackageInfo
QCString filename;
TagAnchorInfoList docAnchors;
QList<TagMemberInfo> members;
- QStringList classList;
+ QCStringList classList;
};
/** Container for include info that can be read from a tagfile */
@@ -157,8 +159,8 @@ class TagFileInfo
QCString filename;
TagAnchorInfoList docAnchors;
QList<TagMemberInfo> members;
- QStringList classList;
- QStringList namespaceList;
+ QCStringList classList;
+ QCStringList namespaceList;
QList<TagIncludeInfo> includes;
};
@@ -172,12 +174,12 @@ class TagGroupInfo
QCString filename;
TagAnchorInfoList docAnchors;
QList<TagMemberInfo> members;
- QStringList subgroupList;
- QStringList classList;
- QStringList namespaceList;
- QStringList fileList;
- QStringList pageList;
- QStringList dirList;
+ QCStringList subgroupList;
+ QCStringList classList;
+ QCStringList namespaceList;
+ QCStringList fileList;
+ QCStringList pageList;
+ QCStringList dirList;
};
/** Container for page specific info that can be read from a tagfile */
@@ -197,8 +199,8 @@ class TagDirInfo
QCString name;
QCString filename;
QCString path;
- QStringList subdirList;
- QStringList fileList;
+ QCStringList subdirList;
+ QCStringList fileList;
TagAnchorInfoList docAnchors;
};
@@ -381,7 +383,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unknown compound attribute `%s' found!\n",kind.data());
+ warn("Unknown compound attribute `%s' found!",kind.data());
m_state = Invalid;
}
if (isObjC=="yes" && m_curClass)
@@ -409,7 +411,7 @@ class TagFileParser : public QXmlDefaultHandler
case InPackage: m_tagFilePackages.append(m_curPackage);
m_curPackage=0; break;
default:
- warn("tag `compound' was not expected!\n");
+ warn("tag `compound' was not expected!");
}
}
@@ -455,7 +457,7 @@ class TagFileParser : public QXmlDefaultHandler
case InNamespace: m_curNamespace->members.append(m_curMember); break;
case InGroup: m_curGroup->members.append(m_curMember); break;
case InPackage: m_curPackage->members.append(m_curMember); break;
- default: warn("Unexpected tag `member' found\n"); break;
+ default: warn("Unexpected tag `member' found"); break;
}
}
@@ -473,7 +475,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Found enumvalue tag outside of member tag\n");
+ warn("Found `enumvalue' tag outside of member tag");
}
}
@@ -501,7 +503,7 @@ class TagFileParser : public QXmlDefaultHandler
case InMember: m_curMember->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
case InPackage: m_curPackage->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
case InDir: m_curDir->docAnchors.append(new TagAnchorInfo(m_fileName,m_curString,m_title)); break;
- default: warn("Unexpected tag `member' found\n"); break;
+ default: warn("Unexpected tag `docanchor' found"); break;
}
}
@@ -514,7 +516,7 @@ class TagFileParser : public QXmlDefaultHandler
case InNamespace: m_curNamespace->classList.append(m_curString); break;
case InGroup: m_curGroup->classList.append(m_curString); break;
case InPackage: m_curPackage->classList.append(m_curString); break;
- default: warn("Unexpected tag `class' found\n"); break;
+ default: warn("Unexpected tag `class' found"); break;
}
}
@@ -525,7 +527,7 @@ class TagFileParser : public QXmlDefaultHandler
case InNamespace: m_curNamespace->classList.append(m_curString); break;
case InFile: m_curFile->namespaceList.append(m_curString); break;
case InGroup: m_curGroup->namespaceList.append(m_curString); break;
- default: warn("Unexpected tag `namespace' found\n"); break;
+ default: warn("Unexpected tag `namespace' found"); break;
}
}
@@ -535,7 +537,7 @@ class TagFileParser : public QXmlDefaultHandler
{
case InGroup: m_curGroup->fileList.append(m_curString); break;
case InDir: m_curDir->fileList.append(m_curString); break;
- default: warn("Unexpected tag `file' found\n"); break;
+ default: warn("Unexpected tag `file' found"); break;
}
}
@@ -544,7 +546,7 @@ class TagFileParser : public QXmlDefaultHandler
switch(m_state)
{
case InGroup: m_curGroup->fileList.append(m_curString); break;
- default: warn("Unexpected tag `page' found\n"); break;
+ default: warn("Unexpected tag `page' found"); break;
}
}
@@ -553,7 +555,7 @@ class TagFileParser : public QXmlDefaultHandler
switch(m_state)
{
case InDir: m_curDir->subdirList.append(m_curString); break;
- default: warn("Unexpected tag `page' found\n"); break;
+ default: warn("Unexpected tag `dir' found"); break;
}
}
@@ -577,7 +579,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `type' found\n");
+ warn("Unexpected tag `type' found");
}
}
@@ -593,7 +595,7 @@ class TagFileParser : public QXmlDefaultHandler
case InDir: m_curDir->name = m_curString; break;
case InMember: m_curMember->name = m_curString; break;
case InPackage: m_curPackage->name = m_curString; break;
- default: warn("Unexpected tag `name' found\n"); break;
+ default: warn("Unexpected tag `name' found"); break;
}
}
@@ -627,7 +629,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `base' found\n");
+ warn("Unexpected tag `base' found");
}
}
@@ -639,7 +641,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `base' found\n");
+ warn("Unexpected tag `base' found");
}
}
@@ -656,7 +658,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `includes' found\n");
+ warn("Unexpected tag `includes' found");
}
m_curString="";
}
@@ -679,7 +681,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `templarg' found\n");
+ warn("Unexpected tag `templarg' found");
}
}
@@ -694,7 +696,7 @@ class TagFileParser : public QXmlDefaultHandler
case InPage: m_curPage->filename = m_curString; break;
case InPackage: m_curPackage->filename = m_curString; break;
case InDir: m_curDir->filename = m_curString; break;
- default: warn("Unexpected tag `filename' found\n"); break;
+ default: warn("Unexpected tag `filename' found"); break;
}
}
@@ -704,7 +706,7 @@ class TagFileParser : public QXmlDefaultHandler
{
case InFile: m_curFile->path = m_curString; break;
case InDir: m_curDir->path = m_curString; break;
- default: warn("Unexpected tag `path' found\n"); break;
+ default: warn("Unexpected tag `path' found"); break;
}
}
@@ -714,9 +716,13 @@ class TagFileParser : public QXmlDefaultHandler
{
m_curMember->anchor = m_curString;
}
+ else if (m_state==InClass)
+ {
+ m_curClass->anchor = m_curString;
+ }
else
{
- warn("Unexpected tag `anchor' found\n");
+ warn("Unexpected tag `anchor' found");
}
}
@@ -736,7 +742,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("warning: Unexpected tag `anchor' found\n");
+ warn("Unexpected tag `clangid' found");
}
}
@@ -750,7 +756,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `anchorfile' found\n");
+ warn("Unexpected tag `anchorfile' found");
}
}
@@ -762,7 +768,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `arglist' found\n");
+ warn("Unexpected tag `arglist' found");
}
}
void endTitle()
@@ -771,7 +777,7 @@ class TagFileParser : public QXmlDefaultHandler
{
case InGroup: m_curGroup->title = m_curString; break;
case InPage: m_curPage->title = m_curString; break;
- default: warn("Unexpected tag `title' found\n"); break;
+ default: warn("Unexpected tag `title' found"); break;
}
}
@@ -783,7 +789,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `subgroup' found\n");
+ warn("Unexpected tag `subgroup' found");
}
}
@@ -878,7 +884,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unknown tag `%s' found!\n",name.data());
+ warn("Unknown tag `%s' found!",name.data());
}
return TRUE;
}
@@ -893,7 +899,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unknown tag `%s' found!\n",name.data());
+ warn("Unknown tag `%s' found!",name.data());
}
return TRUE;
}
@@ -1009,11 +1015,11 @@ void TagFileParser::dump()
{
msg("namespace `%s'\n",nd->name.data());
msg(" filename `%s'\n",nd->filename.data());
- QStringList::Iterator it;
+ QCStringList::Iterator it;
for ( it = nd->classList.begin();
it != nd->classList.end(); ++it )
{
- msg( " class: %s \n", (*it).latin1() );
+ msg( " class: %s \n", (*it).data() );
}
QListIterator<TagMemberInfo> mci(nd->members);
@@ -1034,16 +1040,16 @@ void TagFileParser::dump()
{
msg("file `%s'\n",fd->name.data());
msg(" filename `%s'\n",fd->filename.data());
- QStringList::Iterator it;
+ QCStringList::Iterator it;
for ( it = fd->namespaceList.begin();
it != fd->namespaceList.end(); ++it )
{
- msg( " namespace: %s \n", (*it).latin1() );
+ msg( " namespace: %s \n", (*it).data() );
}
for ( it = fd->classList.begin();
it != fd->classList.end(); ++it )
{
- msg( " class: %s \n", (*it).latin1() );
+ msg( " class: %s \n", (*it).data() );
}
QListIterator<TagMemberInfo> mci(fd->members);
@@ -1072,31 +1078,31 @@ void TagFileParser::dump()
{
msg("group `%s'\n",gd->name.data());
msg(" filename `%s'\n",gd->filename.data());
- QStringList::Iterator it;
+ QCStringList::Iterator it;
for ( it = gd->namespaceList.begin();
it != gd->namespaceList.end(); ++it )
{
- msg( " namespace: %s \n", (*it).latin1() );
+ msg( " namespace: %s \n", (*it).data() );
}
for ( it = gd->classList.begin();
it != gd->classList.end(); ++it )
{
- msg( " class: %s \n", (*it).latin1() );
+ msg( " class: %s \n", (*it).data() );
}
for ( it = gd->fileList.begin();
it != gd->fileList.end(); ++it )
{
- msg( " file: %s \n", (*it).latin1() );
+ msg( " file: %s \n", (*it).data() );
}
for ( it = gd->subgroupList.begin();
it != gd->subgroupList.end(); ++it )
{
- msg( " subgroup: %s \n", (*it).latin1() );
+ msg( " subgroup: %s \n", (*it).data() );
}
for ( it = gd->pageList.begin();
it != gd->pageList.end(); ++it )
{
- msg( " page: %s \n", (*it).latin1() );
+ msg( " page: %s \n", (*it).data() );
}
QListIterator<TagMemberInfo> mci(gd->members);
@@ -1126,16 +1132,16 @@ void TagFileParser::dump()
{
msg("dir `%s'\n",dd->name.data());
msg(" path `%s'\n",dd->path.data());
- QStringList::Iterator it;
+ QCStringList::Iterator it;
for ( it = dd->fileList.begin();
it != dd->fileList.end(); ++it )
{
- msg( " file: %s \n", (*it).latin1() );
+ msg( " file: %s \n", (*it).data() );
}
for ( it = dd->subdirList.begin();
it != dd->subdirList.end(); ++it )
{
- msg( " subdir: %s \n", (*it).latin1() );
+ msg( " subdir: %s \n", (*it).data() );
}
}
}
@@ -1157,7 +1163,7 @@ void TagFileParser::addDocAnchors(Entry *e,const TagAnchorInfoList &l)
}
else
{
- warn("Duplicate anchor %s found\n",ta->label.data());
+ warn("Duplicate anchor %s found",ta->label.data());
}
}
}
@@ -1322,6 +1328,9 @@ void TagFileParser::buildLists(Entry *root)
case TagClassInfo::Category: ce->spec = Entry::Category; break;
case TagClassInfo::Service: ce->spec = Entry::Service; break;
case TagClassInfo::Singleton: ce->spec = Entry::Singleton; break;
+ case TagClassInfo::None: // should never happen, means not properly initialized
+ assert(tci->kind != TagClassInfo::None);
+ break;
}
ce->name = tci->name;
if (tci->kind==TagClassInfo::Protocol)
@@ -1331,6 +1340,7 @@ void TagFileParser::buildLists(Entry *root)
addDocAnchors(ce,tci->docAnchors);
TagInfo *ti = new TagInfo;
ti->tagName = m_tagName;
+ ti->anchor = tci->anchor;
ti->fileName = tci->filename;
ce->id = tci->clangId;
ce->tagInfo = ti;
diff --git a/src/tclscanner.l b/src/tclscanner.l
index 56d2e3d..ca5294b 100644
--- a/src/tclscanner.l
+++ b/src/tclscanner.l
@@ -25,7 +25,7 @@
#include <ctype.h>
#include <qstring.h>
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include <qlist.h>
#include <qmap.h>
#include <qarray.h>
@@ -369,7 +369,7 @@ int Tcl_SplitList(
}
// END of tclUtil.c
-void tcl_split_list(QString &str, QStringList &list)
+void tcl_split_list(QCString &str, QCStringList &list)
{
int argc;
const char **argv;
@@ -383,17 +383,20 @@ void tcl_split_list(QString &str, QStringList &list)
{
str=str.mid(1,str.length()-2);
}
- if (Tcl_SplitList(str.ascii(),&argc,&argv) != TCL_OK)
+ if (!str.isEmpty())
{
- list.append(str);
- }
- else
- {
- for (int i = 0; i < argc; i++)
+ if (Tcl_SplitList(str,&argc,&argv) != TCL_OK)
+ {
+ list.append(str);
+ }
+ else
{
- list.append(argv[i]);
+ for (int i = 0; i < argc; i++)
+ {
+ list.append(argv[i]);
+ }
+ ckfree((char *) argv);
}
- ckfree((char *) argv);
}
}
@@ -409,7 +412,7 @@ typedef struct
Entry *entry_cl; // if set contain the current class
Entry *entry_scan; // current scan entry
Protection protection; // current protections state
- QStringList after; // option/value list (options: NULL comment keyword script)
+ QCStringList after; // option/value list (options: NULL comment keyword script)
} tcl_scan;
//* Structure containing all internal global variables.
@@ -446,7 +449,7 @@ static struct
Entry* entry_file; // entry of current file
Entry* entry_current; // currently used entry
Entry* entry_inside; // contain entry of current scan context
- QStringList list_commandwords; // list of command words
+ QCStringList list_commandwords; // list of command words
QList<tcl_scan> scan; // stack of scan contexts
QAsciiDict<Entry> ns; // all read namespace entries
QAsciiDict<Entry> cl; // all read class entries
@@ -602,7 +605,7 @@ Entry* tcl_entry_class(const QCString cl)
// @return 1 if keyword and 0 otherwise
static int tcl_keyword(QCString str)
{
- static QStringList myList;
+ static QCStringList myList;
static int myInit=1;
if (myInit)
{
@@ -639,7 +642,7 @@ static int tcl_keyword(QCString str)
myList <<"tkerror"<<"tkwait"<<"tk_bisque"<<"tk_focusNext"<<"tk_focusPrev"<<"tk_focusFollowsMouse"<<"tk_popup"<<"tk_setPalette"<<"tk_textCut"<<"tk_TextCopy"<<"tk_textPaste"<<"chooseColor"<<"tk_chooseColor"<<"tk_chooseDirectory"<<"tk_dialog"<<"tk_getOpenFile"<<"tkDialog"<<"tk_getSaveFile"<<"tk_messageBox";
myList <<"winfo"<<"wm";
myList <<"button"<<"canvas"<<"checkbutton"<<"entry"<<"frame"<<"image"<<"label"<<"labelframe"<<"listbox"<<"menu"<<"menubutton"<<"message"<<"panedwindow"<<"radiobutton"<<"scale"<<"scrollbar"<<"spinbox"<<"toplevel";
- myList.sort();
+ //myList.sort();
myInit=0;
}
str=str.stripWhiteSpace();
@@ -727,7 +730,7 @@ static void tcl_codify(const char *s,const char *str)
static void tcl_codify(const char *s,const QString &str)
{
if (tcl.code==NULL) return;
- tcl_codify(s,str.utf8());
+ tcl_codify(s,str);
}
//! Codify 'str' with special font class 's'.
@@ -740,7 +743,7 @@ static void tcl_codify(const char *s,const QCString &str)
static void tcl_codify_cmd(const char *s,int i)
{
- tcl_codify(s,(*tcl.list_commandwords.at(i)).utf8());
+ tcl_codify(s,(*tcl.list_commandwords.at(i)));
}
//! codify a string token
//
@@ -1193,7 +1196,7 @@ tcl_inf("line=%d\n",myScan->line1);
myStart=i;
break;
}
- tcl_codify(myScan->after[i].utf8(),myScan->after[i+1].utf8());
+ tcl_codify(myScan->after[i],myScan->after[i+1]);
}
yy_delete_buffer(myScan->buffer_state);
yy_pop_state();
@@ -1428,7 +1431,6 @@ tcl_inf("(%d) ?%s?\n",what,tcl.string_last.data());
yyless(0);
tcl_inf("(.%d) ?%s?\n",what,tcl.string_last.data());
return;
- myWhite=0;
break;
default:
tcl_err("wrong state: %d\n",what);
@@ -1608,12 +1610,12 @@ tcl_inf("-> %s\n",(const char *)tcl.string_comment);
}
//! Parse given \c arglist .
-static void tcl_command_ARGLIST(QString &arglist)
+static void tcl_command_ARGLIST(QCString &arglist)
{
D
Argument *myArg;
- QStringList myArgs;
- QString myArglist="";
+ QCStringList myArgs;
+ QCString myArglist="";
if (!tcl.entry_current->argList)
{
@@ -1622,14 +1624,14 @@ D
tcl_split_list(arglist,myArgs);
for (uint i=0;i<myArgs.count();i++)
{
- QStringList myArgs1;
+ QCStringList myArgs1;
myArg=new Argument;
tcl_split_list(*myArgs.at(i),myArgs1);
if (myArgs1.count()==2)
{
- myArg->name= (*myArgs1.at(0)).utf8();
- myArg->defval= (*myArgs1.at(1)).utf8();
+ myArg->name= (*myArgs1.at(0));
+ myArg->defval= (*myArgs1.at(1));
if (myArg->defval.isEmpty())
{
myArg->defval = " ";
@@ -1638,13 +1640,13 @@ D
}
else
{
- myArg->name= (*myArgs.at(i)).utf8();
- myArglist += QString(myArg->name) + " ";
+ myArg->name= (*myArgs.at(i));
+ myArglist += myArg->name + " ";
}
tcl.entry_current->argList->append(myArg);
}
arglist = myArglist;
- tcl.entry_current->args = arglist.utf8();
+ tcl.entry_current->args = arglist;
}
//! Create link.
@@ -1763,7 +1765,7 @@ static void tcl_codify_link(QCString name)
//! scan general argument for brackets
//
-// parses (*tcl.list_commandwords.at(i)).utf8() and checks for brackets.
+// parses (*tcl.list_commandwords.at(i)) and checks for brackets.
// Starts a new scan context if needed (*myScan==0 and brackets found).
// Returns NULL or the created scan context.
//
@@ -1773,7 +1775,7 @@ static tcl_scan *tcl_command_ARG(tcl_scan *myScan, unsigned int i, bool ignoreOu
bool insideQuotes=false;
unsigned int insideBrackets=0;
unsigned int insideBraces=0;
- myName = (*tcl.list_commandwords.at(i)).utf8();
+ myName = (*tcl.list_commandwords.at(i));
if (i%2 != 0)
{
// handle white space
@@ -1861,7 +1863,7 @@ D
// Example: eval [list set] [list NotInvoked] [Invoked NotInvoked]
for (unsigned int i = 1; i < tcl.list_commandwords.count(); i++)
{
- myString += (*tcl.list_commandwords.at(i)).utf8();
+ myString += (*tcl.list_commandwords.at(i));
}
myScan = tcl_scan_start('?', myString,
myScan->ns, myScan->entry_cl, myScan->entry_fn);
@@ -1882,7 +1884,7 @@ D
unsigned int lastOptionIndex = 0;
for (i = 2; i<tcl.list_commandwords.count(); i += 2)
{
- token = (*tcl.list_commandwords.at(i)).utf8();
+ token = (*tcl.list_commandwords.at(i));
if (token == "--")
{
lastOptionIndex = i;
@@ -1913,7 +1915,7 @@ D
int size;
const char *elem;
const char *next;
- token = (*tcl.list_commandwords.at(lastOptionIndex + 4)).utf8();
+ token = (*tcl.list_commandwords.at(lastOptionIndex + 4));
if (token[0] == '{')
{
inBraces = true;
@@ -1966,15 +1968,15 @@ D
//printf("detected: switch ?options? string pattern body ?pattern body ...?\n");
myScan = tcl_command_ARG(myScan, lastOptionIndex + 1, false);
myScan = tcl_command_ARG(myScan, lastOptionIndex + 2, false);
- //printf("value=%s\n",(const char*) (*tcl.list_commandwords.at(lastOptionIndex + 2)).utf8());
+ //printf("value=%s\n",(const char*) (*tcl.list_commandwords.at(lastOptionIndex + 2)));
for (i = lastOptionIndex + 3; i < tcl.list_commandwords.count(); i += 4)
{
myScan = tcl_command_ARG(myScan, i + 0, false); // whitespace
myScan = tcl_command_ARG(myScan, i + 1, false); // pattern
myScan = tcl_command_ARG(myScan, i + 2, false); // whitespace
- myScan = tcl_codify_token(myScan, "script", (*tcl.list_commandwords.at(i+3)).utf8()); // script
- //printf("pattern=%s\n",(const char*) (*tcl.list_commandwords.at(i+1)).utf8());
- //printf("script=%s\n",(const char*) (*tcl.list_commandwords.at(i+3)).utf8());
+ myScan = tcl_codify_token(myScan, "script", (*tcl.list_commandwords.at(i+3))); // script
+ //printf("pattern=%s\n",(const char*) (*tcl.list_commandwords.at(i+1))));
+ //printf("script=%s\n",(const char*) (*tcl.list_commandwords.at(i+3)));
}
}
else
@@ -2007,7 +2009,7 @@ D
//! Handle internal tcl commands.
// "if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?"
-static void tcl_command_IF(QStringList type)
+static void tcl_command_IF(QCStringList type)
{
D
tcl_codify_cmd("keyword",0);
@@ -2126,7 +2128,7 @@ D
tcl_codify_cmd(NULL,3);
tcl_codify_cmd(NULL,4);
tcl_codify_cmd(NULL,5);
- tcl_name_SnippetAware(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
+ tcl_name_SnippetAware(myScan->ns,(*tcl.list_commandwords.at(2)),myNs,myName);
if (myNs.length())
{
myEntryNs = tcl_entry_namespace(myNs);
@@ -2165,7 +2167,7 @@ D
tcl_codify_cmd(NULL,3);
tcl_codify_cmd(NULL,4);
tcl_codify_cmd(NULL,5);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)),myNs,myName);
if (myNs.length())
{
myEntryCl = tcl_entry_class(myNs);
@@ -2205,7 +2207,7 @@ D
tcl_codify_cmd(NULL,1);
tcl_codify_cmd(NULL,2);
tcl_codify_cmd(NULL,3);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(0)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(0)),myNs,myName);
if (myNs.length())
{
myEntryCl = tcl_entry_class(myNs);
@@ -2240,7 +2242,7 @@ D
tcl_codify_cmd("keyword",0);
tcl_codify_cmd(NULL,1);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(0)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(0)),myNs,myName);
if (myNs.length())
{
myEntryCl = tcl_entry_class(myNs);
@@ -2278,7 +2280,7 @@ D
tcl_codify_cmd(NULL,3);
tcl_codify_cmd(NULL,4);
tcl_codify_cmd(NULL,5);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)),myNs,myName);
if (myNs.length())
{
myName = myNs+"::"+myName;
@@ -2291,12 +2293,12 @@ D
tcl.entry_main->addSubEntry(tcl.entry_current);
tcl.ns.insert(myName,tcl.entry_current);
//myEntryNs = tcl.entry_current;
- myStr = (*tcl.list_commandwords.at(6)).utf8();
+ myStr = (*tcl.list_commandwords.at(6));
if (tcl.list_commandwords.count() > 7)
{
for (uint i=7;i<tcl.list_commandwords.count();i++)
{
- myStr.append((*tcl.list_commandwords.at(i)).utf8());
+ myStr.append((*tcl.list_commandwords.at(i)));
}
tcl.word_is=' ';
}
@@ -2315,7 +2317,7 @@ D
tcl_codify_cmd(NULL,1);
tcl_codify_cmd("NULL",2);
tcl_codify_cmd("NULL",3);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)),myNs,myName);
if (myNs.length())
{
myName = myNs+"::"+myName;
@@ -2347,7 +2349,7 @@ D
tcl_codify_cmd("NULL",3);
tcl_codify_cmd("NULL",4);
tcl_codify_cmd("NULL",5);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)),myNs,myName);
if (myNs.length())
{
myName = myNs+"::"+myName;
@@ -2377,13 +2379,13 @@ D
tcl_codify_cmd(NULL,1);
tcl_codify_cmd("NULL",2);
tcl_codify_cmd("NULL",3);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)),myNs,myName);
if (myNs.length())
{
myName = myNs+"::"+myName;
}
myEntryCl = tcl_entry_class(myName);
- myStr = (*tcl.list_commandwords.at(4)).utf8();
+ myStr = (*tcl.list_commandwords.at(4));
//
// special cases first
// oo::define classname method methodname args script
@@ -2400,7 +2402,7 @@ D
}
Entry *myEntry;
QCString myMethod;
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(n==11?6:4)).utf8(),myNs,myMethod);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(n==11?6:4)),myNs,myMethod);
// code snippet taken from tcl_command_METHOD()/tcl_command_CONSTRUCTOR
tcl.fn.remove(myMethod);
tcl.entry_current->section = Entry::FUNCTION_SEC;
@@ -2434,7 +2436,7 @@ D
{
for (uint i=5;i<tcl.list_commandwords.count();i++)
{
- myStr.append((*tcl.list_commandwords.at(i)).utf8());
+ myStr.append((*tcl.list_commandwords.at(i)));
}
tcl.word_is=' ';
}
@@ -2455,7 +2457,7 @@ D
{
tcl_codify_cmd(NULL,i);
}
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)).utf8(),myNs,myName);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(2)),myNs,myName);
if (myNs.length())
{// qualified variables go into namespace
myEntry = tcl_entry_namespace(myNs);
@@ -2535,7 +2537,7 @@ tcl_inf("->\n");
yy_pop_state();
// check command
- QCString myStr = (*tcl.list_commandwords.at(0)).utf8();
+ QCString myStr = (*tcl.list_commandwords.at(0));
tcl_scan *myScanBackup=tcl.scan.at(0);
int myLevel = 0;
Protection myProt = tcl.protection;
@@ -2580,7 +2582,7 @@ tcl_inf("->\n");
myProt = tcl.protection;
goto command_end;
}
- myStr = (*tcl.list_commandwords.at(0)).utf8();
+ myStr = (*tcl.list_commandwords.at(0));
// remove leading "::" and apply TCL_SUBST
if (myStr.left(2)=="::") myStr = myStr.mid(2);
if (tcl.config_subst.contains(myStr))
@@ -2624,7 +2626,7 @@ tcl_inf("->\n");
}
if (myStr=="namespace")
{
- if ((*tcl.list_commandwords.at(2)).utf8()=="eval")
+ if ((*tcl.list_commandwords.at(2))=="eval")
{
if (tcl.list_commandwords.count() < 7) {myLine=__LINE__;goto command_warn;}
tcl_command_NAMESPACE();
@@ -2647,7 +2649,7 @@ tcl_inf("->\n");
}
if (myStr=="oo::class")
{
- if ((*tcl.list_commandwords.at(2)).utf8()=="create")
+ if ((*tcl.list_commandwords.at(2))=="create")
{
if (tcl.list_commandwords.count() != 7) {myLine=__LINE__;goto command_warn;}
tcl_command_OO_CLASS();
@@ -2687,7 +2689,7 @@ tcl_inf("->\n");
{
for (unsigned int i = 2; i < tcl.list_commandwords.count(); i = i + 2)
{
- tcl.scan.at(0)->entry_cl->extends->append(new BaseInfo((*tcl.list_commandwords.at(i)).utf8(),Public,Normal));
+ tcl.scan.at(0)->entry_cl->extends->append(new BaseInfo((*tcl.list_commandwords.at(i)),Public,Normal));
}
}
goto command_end;
@@ -2731,12 +2733,12 @@ if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
*/
if (myStr=="if" && tcl.list_commandwords.count() > 4)
{
- QStringList myType;
+ QCStringList myType;
myType << "keyword" << "NULL" << "expr" << "NULL";
char myState='x';// last word: e'x'pr 't'hen 'b'ody 'e'lse else'i'f..
for (unsigned int i = 4; i < tcl.list_commandwords.count(); i = i + 2)
{
- QCString myStr=(*tcl.list_commandwords.at(i)).utf8();
+ QCString myStr=(*tcl.list_commandwords.at(i));
if (myState=='x')
{
if (myStr=="then")
@@ -2797,7 +2799,7 @@ if expr1 ?then? body1 elseif expr2 ?then? body2 elseif ... ?else? ?bodyN?
tcl_command_OTHER();
goto command_end;
command_warn:// print warning message because of wrong used syntax
- tcl_war("%d count=%d: %s\n",myLine,tcl.list_commandwords.count(),tcl.list_commandwords.join(" ").ascii());
+ tcl_war("%d count=%d: %s\n",myLine,tcl.list_commandwords.count(),tcl.list_commandwords.join(" ").data());
tcl_command_OTHER();
command_end:// add remaining text to current context
if (!myText.isEmpty())
diff --git a/src/template.cpp b/src/template.cpp
index 3e39d3c..b1435ce 100644
--- a/src/template.cpp
+++ b/src/template.cpp
@@ -698,7 +698,7 @@ class FilterTexLabel
{
if (v.isValid() && (v.type()==TemplateVariant::String))
{
- return TemplateVariant(latexEscapeLabelName(v.toString(),FALSE),TRUE);
+ return TemplateVariant(latexEscapeLabelName(v.toString()),TRUE);
}
else
{
@@ -717,7 +717,7 @@ class FilterTexIndex
{
if (v.isValid() && (v.type()==TemplateVariant::String))
{
- return TemplateVariant(latexEscapeIndexChars(v.toString(),FALSE),TRUE);
+ return TemplateVariant(latexEscapeIndexChars(v.toString()),TRUE);
}
else
{
diff --git a/src/textdocvisitor.cpp b/src/textdocvisitor.cpp
index c899232..691e426 100644
--- a/src/textdocvisitor.cpp
+++ b/src/textdocvisitor.cpp
@@ -21,6 +21,7 @@
#include "message.h"
#include "util.h"
#include "htmlentity.h"
+#include "emoji.h"
//-------------------------------------------------------------------------
@@ -37,6 +38,18 @@ void TextDocVisitor::visit(DocSymbol *s)
}
}
+void TextDocVisitor::visit(DocEmoji *s)
+{
+ const char *res = EmojiEntityMapper::instance()->html(s->emoji());
+ if (res)
+ {
+ filter(res);
+ }
+ else
+ {
+ err("text: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+}
void TextDocVisitor::filter(const char *str)
{
diff --git a/src/textdocvisitor.h b/src/textdocvisitor.h
index 1bbc357..bbc70e8 100644
--- a/src/textdocvisitor.h
+++ b/src/textdocvisitor.h
@@ -40,6 +40,7 @@ class TextDocVisitor : public DocVisitor
void visit(DocLinkedWord *w) { filter(w->word()); }
void visit(DocWhiteSpace *) { m_t << " "; }
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *u) { filter(u->url()); }
void visit(DocLineBreak *) { m_t << " "; }
void visit(DocHorRuler *) {}
diff --git a/src/types.h b/src/types.h
index e58c8fc..d6f0342 100644
--- a/src/types.h
+++ b/src/types.h
@@ -227,7 +227,8 @@ class LocalToc
Html = 0, // index / also to be used as bit position in mask (1 << Html)
Latex = 1, // ...
Xml = 2, // ...
- numTocTypes = 3 // number of enum values
+ Docbook = 3, // ...
+ numTocTypes = 4 // number of enum values
};
LocalToc() : m_mask(None) { memset(m_level,0,sizeof(m_level)); }
@@ -247,15 +248,22 @@ class LocalToc
m_mask|=(1<<Xml);
m_level[Xml]=level;
}
+ void enableDocbook(int level)
+ {
+ m_mask|=(1<<Docbook);
+ m_level[Docbook]=level;
+ }
// getters
bool isHtmlEnabled() const { return (m_mask & (1<<Html))!=0; }
bool isLatexEnabled() const { return (m_mask & (1<<Latex))!=0; }
bool isXmlEnabled() const { return (m_mask & (1<<Xml))!=0; }
+ bool isDocbookEnabled() const { return (m_mask & (1<<Docbook))!=0; }
bool nothingEnabled() const { return m_mask == None; }
int htmlLevel() const { return m_level[Html]; }
int latexLevel() const { return m_level[Latex]; }
int xmlLevel() const { return m_level[Xml]; }
+ int docbookLevel() const { return m_level[Docbook]; }
int mask() const { return m_mask; }
private:
diff --git a/src/util.cpp b/src/util.cpp
index 6c7e3d5..5d72a9d 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -251,6 +251,7 @@ void writePageRef(OutputDocInterface &od,const char *cn,const char *mn)
od.disable(OutputGenerator::Html);
od.disable(OutputGenerator::Man);
+ od.disable(OutputGenerator::Docbook);
if (Config_getBool(PDF_HYPERLINKS)) od.disable(OutputGenerator::Latex);
if (Config_getBool(RTF_HYPERLINKS)) od.disable(OutputGenerator::RTF);
od.startPageRef();
@@ -2215,6 +2216,7 @@ void writeExample(OutputList &ol,ExampleSDict *ed)
//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);
@@ -2591,7 +2593,7 @@ QCString dateToString(bool includeTime)
static bool warnedOnce=FALSE;
if (!warnedOnce)
{
- warn_uncond("Environment variable SOURCE_DATA_EPOCH must have a value smaller than or equal to %llu; actual value %llu\n",UINT_MAX,epoch);
+ warn_uncond("Environment variable SOURCE_DATE_EPOCH must have a value smaller than or equal to %llu; actual value %llu\n",UINT_MAX,epoch);
warnedOnce=TRUE;
}
}
@@ -2665,7 +2667,7 @@ Protection classInheritedProtectionLevel(ClassDef *cd,ClassDef *bcd,Protection p
if (level==256)
{
err("Internal inconsistency: found class %s seem to have a recursive "
- "inheritance relation! Please send a bug report to dimitri@stack.nl\n",cd->name().data());
+ "inheritance relation! Please send a bug report to doxygen@gmail.com\n",cd->name().data());
}
else if (cd->baseClasses())
{
@@ -5932,6 +5934,66 @@ QCString convertToXML(const char *s)
return growBuf.get();
}
+/*! Converts a string to an DocBook-encoded string */
+QCString convertToDocBook(const char *s)
+{
+ static GrowBuf growBuf;
+ growBuf.clear();
+ if (s==0) return "";
+ const unsigned char *q;
+ int cnt;
+ const unsigned char *p=(const unsigned char *)s;
+ char c;
+ while ((c=*p++))
+ {
+ switch (c)
+ {
+ case '<': growBuf.addStr("&lt;"); break;
+ case '>': growBuf.addStr("&gt;"); break;
+ case '&': // possibility to have a special symbol
+ q = p;
+ cnt = 2; // we have to count & and ; as well
+ while ((*q >= 'a' && *q <= 'z') || (*q >= 'A' && *q <= 'Z') || (*q >= '0' && *q <= '9'))
+ {
+ cnt++;
+ q++;
+ }
+ if (*q == ';')
+ {
+ --p; // we need & as well
+ DocSymbol::SymType res = HtmlEntityMapper::instance()->name2sym(QCString((char *)p).left(cnt));
+ if (res == DocSymbol::Sym_Unknown)
+ {
+ p++;
+ growBuf.addStr("&amp;");
+ }
+ else
+ {
+ growBuf.addStr(HtmlEntityMapper::instance()->docbook(res));
+ q++;
+ p = q;
+ }
+ }
+ else
+ {
+ growBuf.addStr("&amp;");
+ }
+ break;
+ case '\'': growBuf.addStr("&apos;"); break;
+ case '"': growBuf.addStr("&quot;"); break;
+ case '\007': growBuf.addStr("&#x2407;"); break;
+ case 1: case 2: case 3: case 4: case 5: case 6: case 8:
+ case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18:
+ case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26:
+ case 27: case 28: case 29: case 30: case 31:
+ break; // skip invalid XML characters (see http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char)
+ default: growBuf.addChar(c); break;
+ }
+ }
+ growBuf.addChar(0);
+ return growBuf.get();
+}
+
/*! Converts a string to a HTML-encoded string */
QCString convertToHtml(const char *s,bool keepEntities)
{
@@ -6576,6 +6638,8 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
// append documentation block to the page.
pd->setDocumentation(doc,fileName,startLine);
//printf("Adding page docs `%s' pi=%p name=%s\n",doc.data(),pd,name);
+ // append (x)refitems to the page.
+ pd->setRefItems(sli);
}
else // new page
{
@@ -6865,7 +6929,7 @@ void filterLatexString(FTextStream &t,const char *str,
}
}
-QCString latexEscapeLabelName(const char *s,bool insideTabbing)
+QCString latexEscapeLabelName(const char *s)
{
QGString result;
QCString tmp(qstrlen(s)+1);
@@ -6895,14 +6959,14 @@ QCString latexEscapeLabelName(const char *s,bool insideTabbing)
p++;
}
tmp[i]=0;
- filterLatexString(t,tmp.data(),insideTabbing);
+ filterLatexString(t,tmp,TRUE);
break;
}
}
return result.data();
}
-QCString latexEscapeIndexChars(const char *s,bool insideTabbing)
+QCString latexEscapeIndexChars(const char *s)
{
QGString result;
QCString tmp(qstrlen(s)+1);
@@ -6933,7 +6997,7 @@ QCString latexEscapeIndexChars(const char *s,bool insideTabbing)
p++;
}
tmp[i]=0;
- filterLatexString(t,tmp.data(),insideTabbing);
+ filterLatexString(t,tmp.data(),TRUE);
break;
}
}
@@ -6964,6 +7028,25 @@ QCString latexEscapePDFString(const char *s)
return result.data();
}
+QCString latexFilterURL(const char *s)
+{
+ QGString result;
+ FTextStream t(&result);
+ const char *p=s;
+ char c;
+ while ((c=*p++))
+ {
+ switch (c)
+ {
+ case '#': t << "\\#"; break;
+ default:
+ t << c;
+ break;
+ }
+ }
+ return result.data();
+}
+
QCString rtfFormatBmkStr(const char *name)
{
@@ -7949,8 +8032,8 @@ bool readInputFile(const char *fileName,BufStr &inBuf,bool filter,bool isSourceC
int start=0;
if (size>=2 &&
- ((inBuf.at(0)==-1 && inBuf.at(1)==-2) || // Little endian BOM
- (inBuf.at(0)==-2 && inBuf.at(1)==-1) // big endian BOM
+ (((uchar)inBuf.at(0)==0xFF && (uchar)inBuf.at(1)==0xFE) || // Little endian BOM
+ ((uchar)inBuf.at(0)==0xFE && (uchar)inBuf.at(1)==0xFF) // big endian BOM
)
) // UCS-2 encoded file
{
@@ -8443,12 +8526,9 @@ bool fileVisibleInIndex(FileDef *fd,bool &genSourceFile)
void addDocCrossReference(MemberDef *src,MemberDef *dst)
{
- static bool referencedByRelation = Config_getBool(REFERENCED_BY_RELATION);
- static bool referencesRelation = Config_getBool(REFERENCES_RELATION);
-
//printf("--> addDocCrossReference src=%s,dst=%s\n",src->name().data(),dst->name().data());
if (dst->isTypedef() || dst->isEnumerate()) return; // don't add types
- if ((referencedByRelation || dst->hasCallerGraph()) &&
+ if ((dst->hasReferencedByRelation() || dst->hasCallerGraph()) &&
src->showInCallGraph()
)
{
@@ -8464,7 +8544,7 @@ void addDocCrossReference(MemberDef *src,MemberDef *dst)
mdDecl->addSourceReferencedBy(src);
}
}
- if ((referencesRelation || src->hasCallGraph()) &&
+ if ((src->hasReferencesRelation() || src->hasCallGraph()) &&
src->showInCallGraph()
)
{
diff --git a/src/util.h b/src/util.h
index a9eee67..4274f65 100644
--- a/src/util.h
+++ b/src/util.h
@@ -284,6 +284,8 @@ QCString convertToLaTeX(const QCString &s,bool insideTabbing=FALSE,bool keepSpac
QCString convertToXML(const char *s);
+QCString convertToDocBook(const char *s);
+
QCString convertToJSString(const char *s, bool applyTextDir = true);
QCString getOverloadDocs();
@@ -343,9 +345,10 @@ void filterLatexString(FTextStream &t,const char *str,
bool insideItem=FALSE,
bool keepSpaces=FALSE);
-QCString latexEscapeLabelName(const char *s,bool insideTabbing);
-QCString latexEscapeIndexChars(const char *s,bool insideTabbing);
+QCString latexEscapeLabelName(const char *s);
+QCString latexEscapeIndexChars(const char *s);
QCString latexEscapePDFString(const char *s);
+QCString latexFilterURL(const char *s);
QCString rtfFormatBmkStr(const char *name);
diff --git a/src/vhdlcode.l b/src/vhdlcode.l
index 618258f..ee0731f 100644
--- a/src/vhdlcode.l
+++ b/src/vhdlcode.l
@@ -31,7 +31,7 @@
#include <ctype.h>
#include <qregexp.h>
#include <qdir.h>
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include "entry.h"
#include "doxygen.h"
@@ -138,8 +138,8 @@ static bool checkVhdlString(QCString &name)
int len=name.length();
if (name.at(0)=='"' && name.at(len-1)=='"' && len > 2)
{
- QStringList qrl=QStringList::split(regg,name,FALSE);
- if (VhdlDocGen::isNumber(qrl[0].utf8()))
+ QCStringList qrl=QCStringList::split(regg,name);
+ if (VhdlDocGen::isNumber(qrl[0]))
{
g_code->codify("\"");
startFontClass("vhdllogic");
@@ -370,7 +370,7 @@ static void codifyLines(const char *text,const char *cl=0,bool classlink=FALSE,b
//g_code->codify(sp);
if (comment)
{
- writeFont("keyword",line.data());
+ writeFont("comment",line.data());
}
else
{
@@ -381,7 +381,7 @@ static void codifyLines(const char *text,const char *cl=0,bool classlink=FALSE,b
else
{
if (comment)
- writeFont("keyword",sp);
+ writeFont("comment",sp);
else
writeWord(sp,cl,classlink);
done=TRUE;
@@ -691,8 +691,8 @@ static void writeFuncProto()
codifyLines(g_FuncProto.data(),g_CurrClass.data());
return;
}
- QStringList qlist=QStringList::split(name,g_FuncProto,FALSE);
- QCString temp=qlist[0].utf8();
+ QCStringList qlist=QCStringList::split(name,g_FuncProto);
+ QCString temp=qlist[0];
codifyLines(temp.data(),g_CurrClass.data());
g_FuncProto.stripPrefix(temp.data());
temp.resize(0);
@@ -831,11 +831,11 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
QCString tt(vhdlcodeYYtext);
VhdlDocGen::deleteAllChars(tt,',');
QRegExp r("=>");
- QStringList ql=QStringList::split(r,tt,FALSE);
+ QCStringList ql=QCStringList::split(r,tt);
if (ql.count()>=2)
{
unsigned int index=0;
- QCString t1=ql[0].utf8();
+ QCString t1=ql[0];
char cc=t1.at(index);
while (cc==' ' || cc=='\t')
{
@@ -866,7 +866,7 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
}
codifyLines("=>");
index=0;
- QCString s2=ql[1].utf8();
+ QCString s2=ql[1];
t1=s2;
cc=t1.at(index);
while (cc==' ' || cc=='\t')
@@ -959,7 +959,7 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
tt=tt.lower();
VhdlDocGen::deleteAllChars(tt,';');
tt.stripWhiteSpace();
- QStringList ql=QStringList::split(regg,tt,FALSE);
+ 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;
@@ -1168,13 +1168,12 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
<ParsePackage>[^:;]* { //found package
QCString temp(vhdlcodeYYtext);
- QStringList strl=QStringList::split(".",temp,FALSE);
-
+ QCStringList strl=QCStringList::split(".",temp);
if (strl.count()>2)
{
- QCString s1=strl[0].utf8();
- QCString s2=strl[1].utf8();
- QCString s3=strl[2].utf8();
+ QCString s1=strl[0];
+ QCString s2=strl[1];
+ QCString s3=strl[2];
s1.append(".");
s3.prepend(".");
codifyLines(s1.data(),g_CurrClass.data());
@@ -1297,8 +1296,8 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
<Bases>^{B}*("package "){BN}*("body"){BN}*{FUNCNAME} { // found package body
QCString ss(vhdlcodeYYtext);
QCString temp=VhdlDocGen::getIndexWord(vhdlcodeYYtext,2);
- QStringList ql=QStringList::split(temp,ss,FALSE);
- QCString ll=ql[0].utf8();
+ QCStringList ql=QCStringList::split(temp,ss);
+ QCString ll=ql[0];
codifyLines(ll.data(),g_CurrClass.data());
temp=temp.stripWhiteSpace();
temp.prepend("_");
@@ -1479,11 +1478,11 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
writeFont("keyword",vhdlcodeYYtext);
}
-<Bases>^{B}*{XILINX}[^\n]* {
- writeWord(yytext);
- //codifyLines(vhdlcodeYYtext,g_CurrClass.data(),TRUE);
- }
-
+<Bases>^{B}*{XILINX}/[^a-zA-Z0-9_] {
+ writeWord(yytext);
+ //codifyLines(vhdlcodeYYtext,g_CurrClass.data(),TRUE);
+ }
+
<Bases>^{B}*"set_"[^\n]* {
writeWord(yytext);
}
@@ -1498,37 +1497,38 @@ XILINX "INST"|"NET"|"PIN"|"BLKNM"|"BUFG"|"COLLAPSE"|"CPLD"|"COMPGRP"|"CONFI
}
<*>\n{TEXTT} { // found normal or special comment on its own line
- QCString text(vhdlcodeYYtext);
- int i=text.find("--");
- if (text.mid(i,3)=="--!" && // hide special comment
- Config_getBool(STRIP_CODE_COMMENTS))
- {
- g_yyLineNr++; // skip complete line
- }
- else // normal comment
- {
- // startFontClass("keyword");
- codifyLines(text,0,FALSE,TRUE);
- // endFontClass();
- }
+ QCString text(vhdlcodeYYtext);
+ int i=text.find("--");
+ if (text.mid(i,3)=="--!") // && // hide special comment
+ {
+ if (!Config_getBool(STRIP_CODE_COMMENTS))
+ {
+ codifyLines(text,0,FALSE,TRUE);
+ }
+ g_yyLineNr++; // skip complete line
+ }
+ else // normal comment
+ {
+ codifyLines(text,0,FALSE,TRUE);
+ }
}
<*>{TEXTT} { // found normal or special comment after something
- QCString text(vhdlcodeYYtext);
- int i=text.find("--");
- if (text.mid(i,3)=="--!" &&
- Config_getBool(STRIP_CODE_COMMENTS))
- {
- // hide special comment
- }
- else // normal comment
- {
- // startFontClass("keyword");
- codifyLines(text,0,FALSE,TRUE);
- // endFontClass();
- }
+ QCString text(vhdlcodeYYtext);
+ int i=text.find("--");
+ if (text.mid(i,3)=="--!")
+ {
+ // hide special comment
+ if (!Config_getBool(STRIP_CODE_COMMENTS))
+ {
+ codifyLines(text,0,FALSE,TRUE);
+ }
+ }
+ else // normal comment
+ {
+ codifyLines(text,0,FALSE,TRUE);
+ }
}
-
%%
/*@ ----------------------------------------------------------------------------
diff --git a/src/vhdldocgen.cpp b/src/vhdldocgen.cpp
index 007c45f..f603ddd 100644
--- a/src/vhdldocgen.cpp
+++ b/src/vhdldocgen.cpp
@@ -26,7 +26,7 @@
#include <string.h>
#include <qcstring.h>
#include <qfileinfo.h>
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include <qmap.h>
/* --------------------------------------------------------------- */
@@ -299,10 +299,10 @@ static QCString formatBriefNote(const QCString &brief,ClassDef * cd)
int k=cd->briefLine();
- QStringList qsl=QStringList::split(ep,brief);
+ QCStringList qsl=QCStringList::split(ep,brief);
for(uint j=0;j<qsl.count();j++)
{
- QCString qcs=qsl[j].data();
+ QCString qcs=qsl[j];
vForm+=parseCommentAsText(cd,NULL,qcs,file,k);
k++;
vForm+='\n';
@@ -602,7 +602,7 @@ const char* g_vhdlKeyWordMap1[] =
{
"natural","unsigned","signed","string","boolean", "bit","bit_vector","character",
"std_ulogic","std_ulogic_vector","std_logic","std_logic_vector","integer",
- "real","float","ufixed","sfixed","time",0
+ "real","float","ufixed","sfixed","time","positive",0
};
// logic
@@ -667,7 +667,7 @@ const char* g_vhdlKeyWordMap3[] =
QCString* VhdlDocGen::findKeyWord(const QCString& tmp)
{
static QCString vhdlkeyword("vhdlkeyword");
- static QCString vhdltype("comment");
+ static QCString vhdltype("keywordtype");
static QCString vhdllogic("vhdllogic");
static QCString preprocessor("keywordflow");
@@ -1028,8 +1028,8 @@ void VhdlDocGen::writeInlineClassLink(const ClassDef* cd ,OutputList& ol)
}
else if (ii==VhdlDocGen::ARCHITECTURE)
{
- QStringList qlist=QStringList::split("-",nn,FALSE);
- nn=qlist[1].utf8();
+ QCStringList qlist=QCStringList::split("-",nn);
+ nn=qlist[1];
cd=VhdlDocGen::getClass(nn.data());
}
@@ -1041,9 +1041,9 @@ void VhdlDocGen::writeInlineClassLink(const ClassDef* cd ,OutputList& ol)
for (int i=0;i<j;i++)
{
QCString *temp=ql.at(i);
- QStringList qlist=QStringList::split("-",*temp,FALSE);
- QCString s1=qlist[0].utf8();
- QCString s2=qlist[1].utf8();
+ QCStringList qlist=QCStringList::split("-",*temp);
+ QCString s1=qlist[0];
+ QCString s2=qlist[1];
s1.stripPrefix("_");
if (j==1) s1.resize(0);
ClassDef*cc = getClass(temp->data());
@@ -1075,8 +1075,8 @@ void VhdlDocGen::findAllArchitectures(QList<QCString>& qll,const ClassDef *cd)
QCString jj=citer->className();
if (cd != citer && jj.contains('-')!=-1)
{
- QStringList ql=QStringList::split("-",jj,FALSE);
- QCString temp=ql[1].utf8();
+ QCStringList ql=QCStringList::split("-",jj);
+ QCString temp=ql[1];
if (qstricmp(cd->className(),temp)==0)
{
QCString *cl=new QCString(jj);
@@ -1095,10 +1095,10 @@ ClassDef* VhdlDocGen::findArchitecture(const ClassDef *cd)
for ( ; (citer=cli.current()) ; ++cli )
{
QCString jj=citer->name();
- QStringList ql=QStringList::split(":",jj,FALSE);
+ QCStringList ql=QCStringList::split(":",jj);
if (ql.count()>1)
{
- if (ql[0].utf8()==nn )
+ if (ql[0]==nn )
{
return citer;
}
@@ -1211,15 +1211,15 @@ void VhdlDocGen::parseFuncProto(const char* text,QList<Argument>& qlist,
QCString VhdlDocGen::getIndexWord(const char* c,int index)
{
- QStringList ql;
+ QCStringList ql;
QCString temp(c);
QRegExp reg("[\\s:|]");
- ql=QStringList::split(reg,temp,FALSE);
+ ql=QCStringList::split(reg,temp);
if (ql.count() > (unsigned int)index)
{
- return ql[index].utf8();
+ return ql[index];
}
return "";
@@ -2466,8 +2466,8 @@ void VhdlDocGen::writeSource(MemberDef *mdef,OutputList& ol,QCString & cname)
if (cname.isEmpty()) return;
mdef->writeSourceDef(ol,cname);
- mdef->writeSourceRefs(ol,cname);
- mdef->writeSourceReffedBy(ol,cname);
+ if (mdef->hasReferencesRelation()) mdef->writeSourceRefs(ol,cname);
+ if (mdef->hasReferencedByRelation()) mdef->writeSourceReffedBy(ol,cname);
}
@@ -2678,11 +2678,11 @@ QCString VhdlDocGen::parseForConfig(QCString & entity,QCString & arch)
if (!entity.contains(":")) return "";
QRegExp exp("[:()\\s]");
- QStringList ql=QStringList::split(exp,entity,FALSE);
+ QCStringList ql=QCStringList::split(exp,entity);
//int ii=ql.findIndex(ent);
assert(ql.count()>=2);
- label = ql[0].utf8();
- entity = ql[1].utf8();
+ label = ql[0];
+ entity = ql[1];
if ((index=entity.findRev("."))>=0)
{
entity.remove(0,index+1);
@@ -2690,8 +2690,8 @@ QCString VhdlDocGen::parseForConfig(QCString & entity,QCString & arch)
if (ql.count()==3)
{
- arch= ql[2].utf8();
- ql=QStringList::split(exp,arch,FALSE);
+ arch= ql[2];
+ ql=QCStringList::split(exp,arch);
if (ql.count()>1) // expression
{
arch="";
@@ -2708,16 +2708,16 @@ QCString VhdlDocGen::parseForBinding(QCString & entity,QCString & arch)
QRegExp exp("[()\\s]");
QCString label="";
- QStringList ql=QStringList::split(exp,entity,FALSE);
+ QCStringList ql=QCStringList::split(exp,entity);
if (ql.contains("open"))
{
return "open";
}
- label=ql[0].utf8();
+ label=ql[0];
- entity = ql[1].utf8();
+ entity = ql[1];
if ((index=entity.findRev("."))>=0)
{
entity.remove(0,index+1);
@@ -2725,7 +2725,7 @@ QCString VhdlDocGen::parseForBinding(QCString & entity,QCString & arch)
if (ql.count()==3)
{
- arch=ql[2].utf8();
+ arch=ql[2];
}
return label;
}
@@ -2843,7 +2843,7 @@ void assignBinding(VhdlConfNode * conf)
QCString inst1=VhdlDocGen::getIndexWord(archy.data(),0).lower();
QCString comp=VhdlDocGen::getIndexWord(archy.data(),1).lower();
- QStringList ql=QStringList::split(",",inst1);
+ QCStringList ql=QCStringList::split(",",inst1);
for (uint j=0;j<ql.count();j++)
{
@@ -2855,7 +2855,7 @@ void assignBinding(VhdlConfNode * conf)
}
else
{
- archy1=comp+":"+ql[j].utf8();
+ archy1=comp+":"+ql[j];
sign1=cur->type+":"+cur->name;
}
@@ -3029,11 +3029,11 @@ ferr:
void VhdlDocGen::writeRecorUnit(QCString & largs,OutputList& ol ,const MemberDef *mdef)
{
- QStringList ql=QStringList::split("#",largs,FALSE);
+ QCStringList ql=QCStringList::split("#",largs,FALSE);
uint len=ql.count();
for(uint i=0;i<len;i++)
{
- QCString n=ql[i].utf8();
+ QCString n=ql[i];
VhdlDocGen::formatString(n,ol,mdef);
if ((len-i)>1) ol.lineBreak();
}
@@ -3046,14 +3046,14 @@ void VhdlDocGen::writeRecUnitDocu(
QCString largs)
{
- QStringList ql=QStringList::split("#",largs,FALSE);
+ QCStringList ql=QCStringList::split("#",largs);
uint len=ql.count();
ol.startParameterList(TRUE);
bool first=TRUE;
for(uint i=0;i<len;i++)
{
- QCString n=ql[i].utf8();
+ QCString n=ql[i];
ol.startParameterType(first,"");
ol.endParameterType();
ol.startParameterName(TRUE);
@@ -3486,14 +3486,14 @@ void FlowChart::alignCommentNode(FTextStream &t,QCString com)
{
uint max=0;
QCString s;
- QStringList ql=QStringList::split("\n",com);
+ QCStringList ql=QCStringList::split("\n",com);
for (uint j=0;j<ql.count();j++)
{
- s=(QCString)ql[j].utf8();
+ s=(QCString)ql[j];
if (max<s.length()) max=s.length();
}
- s=ql.last().utf8();
+ s=ql.last();
int diff=max-s.length();
QCString n(1);
@@ -3508,7 +3508,7 @@ void FlowChart::alignCommentNode(FTextStream &t,QCString com)
for (uint j=0;j<ql.count();j++)
{
- s=(QCString)ql[j].utf8();
+ s=ql[j];
if (j<ql.count()-1)
{
s+="\n";
diff --git a/src/vhdljjparser.cpp b/src/vhdljjparser.cpp
index 706e8db..81a7ca1 100644
--- a/src/vhdljjparser.cpp
+++ b/src/vhdljjparser.cpp
@@ -12,7 +12,7 @@
#include <qcstring.h>
#include <qfileinfo.h>
-#include <qstringlist.h>
+#include <qcstringlist.h>
#include "vhdljjparser.h"
#include "vhdlcode.h"
#include "vhdldocgen.h"
@@ -381,11 +381,11 @@ void VhdlParser::addVhdlType(const char *n,int startLine,int section,
spec= VhdlDocGen::GENERIC;
}
- QStringList ql=QStringList::split(",",name,FALSE);
+ QCStringList ql=QCStringList::split(",",name);
for (uint u=0;u<ql.count();u++)
{
- current->name=ql[u].utf8();
+ current->name=ql[u];
current->startLine=startLine;
current->bodyLine=startLine;
current->section=section;
@@ -442,11 +442,11 @@ void VhdlParser::createFunction(const char *imp,uint64 spec,const char *fn)
VhdlDocGen::deleteAllChars(current->args,' ');
if (!fname.isEmpty())
{
- QStringList q1=QStringList::split(",",fname);
+ QCStringList q1=QCStringList::split(",",fname);
for (uint ii=0;ii<q1.count();ii++)
{
Argument *arg=new Argument;
- arg->name=q1[ii].utf8();
+ arg->name=q1[ii];
current->argList->append(arg);
}
}
@@ -540,12 +540,12 @@ void VhdlParser::addProto(const char *s1,const char *s2,const char *s3,
{
(void)s5; // avoid unused warning
QCString name=s2;
- QStringList ql=QStringList::split(",",name,FALSE);
+ QCStringList ql=QCStringList::split(",",name);
for (uint u=0;u<ql.count();u++)
{
Argument *arg=new Argument;
- arg->name=ql[u].utf8();
+ arg->name=ql[u];
if (s3)
{
arg->type=s3;
diff --git a/src/vhdljjparser.h b/src/vhdljjparser.h
index a0851d7..3a2ed61 100644
--- a/src/vhdljjparser.h
+++ b/src/vhdljjparser.h
@@ -7,6 +7,7 @@
#include <assert.h>
#include <ctype.h>
#include <qarray.h>
+#include <qcstringlist.h>
#include <qfile.h>
#include <qdict.h>
@@ -14,7 +15,6 @@
#include "types.h"
#include "entry.h"
#include "vhdldocgen.h"
-#include "qstringlist.h"
#include "vhdlcode.h"
#include "memberlist.h"
#include "config.h"
@@ -30,7 +30,6 @@ class ClassSDict;
class FileStorage;
class ClassDef;
class MemberDef;
-class QStringList;
struct VhdlConfNode;
diff --git a/src/xmldocvisitor.cpp b/src/xmldocvisitor.cpp
index 8b00702..4aa81ca 100644
--- a/src/xmldocvisitor.cpp
+++ b/src/xmldocvisitor.cpp
@@ -31,6 +31,7 @@
#include "filename.h"
#include "config.h"
#include "htmlentity.h"
+#include "emoji.h"
static void visitCaption(XmlDocVisitor *parent, QList<DocNode> children)
{
@@ -39,10 +40,10 @@ static void visitCaption(XmlDocVisitor *parent, QList<DocNode> children)
for (cli.toFirst();(n=cli.current());++cli) n->accept(parent);
}
-static void visitPreStart(FTextStream &t, const char *cmd, const bool doCaption,
+static void visitPreStart(FTextStream &t, const char *cmd, bool doCaption,
XmlDocVisitor *parent, QList<DocNode> children,
const QCString &name, bool writeType, DocImage::Type type, const QCString &width,
- const QCString &height, const bool inlineImage = FALSE)
+ const QCString &height, bool inlineImage = FALSE)
{
t << "<" << cmd;
if (writeType)
@@ -65,7 +66,7 @@ static void visitPreStart(FTextStream &t, const char *cmd, const bool doCaption,
{
t << " width=\"" << convertToXML(width) << "\"";
}
- else if (!height.isEmpty())
+ if (!height.isEmpty())
{
t << " height=\"" << convertToXML(height) << "\"";
}
@@ -134,6 +135,20 @@ void XmlDocVisitor::visit(DocSymbol *s)
}
}
+void XmlDocVisitor::visit(DocEmoji *s)
+{
+ if (m_hide) return;
+ const char *res = EmojiEntityMapper::instance()->xml(s->emoji());
+ if (res)
+ {
+ m_t << res;
+ }
+ else
+ {
+ err("XML: non supported Emoji-entity found: %s\n",EmojiEntityMapper::instance()->html(s->emoji()));
+ }
+}
+
void XmlDocVisitor::visit(DocURL *u)
{
if (m_hide) return;
@@ -165,6 +180,12 @@ void XmlDocVisitor::visit(DocStyleChange *s)
case DocStyleChange::Bold:
if (s->enable()) m_t << "<bold>"; else m_t << "</bold>";
break;
+ case DocStyleChange::Strike:
+ if (s->enable()) m_t << "<strike>"; else m_t << "</strike>";
+ break;
+ case DocStyleChange::Underline:
+ if (s->enable()) m_t << "<underline>"; else m_t << "</underline>";
+ break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "<emphasis>"; else m_t << "</emphasis>";
break;
@@ -489,7 +510,7 @@ void XmlDocVisitor::visitPre(DocPara *)
void XmlDocVisitor::visitPost(DocPara *)
{
if (m_hide) return;
- m_t << "</para>";
+ m_t << "</para>" << endl;
}
void XmlDocVisitor::visitPre(DocRoot *)
diff --git a/src/xmldocvisitor.h b/src/xmldocvisitor.h
index c65688f..c2c6537 100644
--- a/src/xmldocvisitor.h
+++ b/src/xmldocvisitor.h
@@ -41,6 +41,7 @@ class XmlDocVisitor : public DocVisitor
void visit(DocLinkedWord *);
void visit(DocWhiteSpace *);
void visit(DocSymbol *);
+ void visit(DocEmoji *);
void visit(DocURL *);
void visit(DocLineBreak *);
void visit(DocHorRuler *);
diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp
index e68c454..e003319 100644
--- a/src/xmlgen.cpp
+++ b/src/xmlgen.cpp
@@ -222,146 +222,117 @@ class TextGeneratorXMLImpl : public TextGeneratorIntf
/** Generator for producing XML formatted source code. */
-class XMLCodeGenerator : public CodeOutputInterface
+void XMLCodeGenerator::codify(const char *text)
{
- public:
-
- XMLCodeGenerator(FTextStream &t) : m_t(t), m_lineNumber(-1), m_isMemberRef(FALSE), m_col(0),
- m_insideCodeLine(FALSE), m_normalHLNeedStartTag(TRUE), m_insideSpecialHL(FALSE) {}
- virtual ~XMLCodeGenerator() { }
-
- void codify(const char *text)
- {
- XML_DB(("(codify \"%s\")\n",text));
- if (m_insideCodeLine && !m_insideSpecialHL && m_normalHLNeedStartTag)
- {
- m_t << "<highlight class=\"normal\">";
- m_normalHLNeedStartTag=FALSE;
- }
- writeXMLCodeString(m_t,text,m_col);
- }
- void writeCodeLink(const char *ref,const char *file,
- const char *anchor,const char *name,
- const char *tooltip)
- {
- XML_DB(("(writeCodeLink)\n"));
- if (m_insideCodeLine && !m_insideSpecialHL && m_normalHLNeedStartTag)
- {
- m_t << "<highlight class=\"normal\">";
- m_normalHLNeedStartTag=FALSE;
- }
- writeXMLLink(m_t,ref,file,anchor,name,tooltip);
- m_col+=qstrlen(name);
- }
- void writeTooltip(const char *, const DocLinkInfo &, const char *,
- const char *, const SourceLinkInfo &, const SourceLinkInfo &
- )
- {
- XML_DB(("(writeToolTip)\n"));
- }
- void startCodeLine(bool)
- {
- XML_DB(("(startCodeLine)\n"));
- m_t << "<codeline";
- if (m_lineNumber!=-1)
- {
- m_t << " lineno=\"" << m_lineNumber << "\"";
- if (!m_refId.isEmpty())
- {
- m_t << " refid=\"" << m_refId << "\"";
- if (m_isMemberRef)
- {
- m_t << " refkind=\"member\"";
- }
- else
- {
- m_t << " refkind=\"compound\"";
- }
- }
- if (!m_external.isEmpty())
- {
- m_t << " external=\"" << m_external << "\"";
- }
- }
- m_t << ">";
- m_insideCodeLine=TRUE;
- m_col=0;
- }
- void endCodeLine()
- {
- XML_DB(("(endCodeLine)\n"));
- if (!m_insideSpecialHL && !m_normalHLNeedStartTag)
- {
- m_t << "</highlight>";
- m_normalHLNeedStartTag=TRUE;
- }
- m_t << "</codeline>" << endl; // non DocBook
- m_lineNumber = -1;
- m_refId.resize(0);
- m_external.resize(0);
- m_insideCodeLine=FALSE;
- }
- void startFontClass(const char *colorClass)
+ XML_DB(("(codify \"%s\")\n",text));
+ if (m_insideCodeLine && !m_insideSpecialHL && m_normalHLNeedStartTag)
+ {
+ m_t << "<highlight class=\"normal\">";
+ m_normalHLNeedStartTag=FALSE;
+ }
+ writeXMLCodeString(m_t,text,m_col);
+}
+void XMLCodeGenerator::writeCodeLink(const char *ref,const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip)
+{
+ XML_DB(("(writeCodeLink)\n"));
+ if (m_insideCodeLine && !m_insideSpecialHL && m_normalHLNeedStartTag)
+ {
+ m_t << "<highlight class=\"normal\">";
+ m_normalHLNeedStartTag=FALSE;
+ }
+ writeXMLLink(m_t,ref,file,anchor,name,tooltip);
+ m_col+=qstrlen(name);
+}
+void XMLCodeGenerator::writeTooltip(const char *, const DocLinkInfo &, const char *,
+ const char *, const SourceLinkInfo &, const SourceLinkInfo &
+ )
+{
+ XML_DB(("(writeToolTip)\n"));
+}
+void XMLCodeGenerator::startCodeLine(bool)
+{
+ XML_DB(("(startCodeLine)\n"));
+ m_t << "<codeline";
+ if (m_lineNumber!=-1)
+ {
+ m_t << " lineno=\"" << m_lineNumber << "\"";
+ if (!m_refId.isEmpty())
{
- XML_DB(("(startFontClass)\n"));
- if (m_insideCodeLine && !m_insideSpecialHL && !m_normalHLNeedStartTag)
+ m_t << " refid=\"" << m_refId << "\"";
+ if (m_isMemberRef)
{
- m_t << "</highlight>";
- m_normalHLNeedStartTag=TRUE;
+ m_t << " refkind=\"member\"";
}
- m_t << "<highlight class=\"" << colorClass << "\">"; // non DocBook
- m_insideSpecialHL=TRUE;
- }
- void endFontClass()
- {
- XML_DB(("(endFontClass)\n"));
- m_t << "</highlight>"; // non DocBook
- m_insideSpecialHL=FALSE;
- }
- void writeCodeAnchor(const char *)
- {
- XML_DB(("(writeCodeAnchor)\n"));
- }
- void writeLineNumber(const char *extRef,const char *compId,
- const char *anchorId,int l)
- {
- XML_DB(("(writeLineNumber)\n"));
- // we remember the information provided here to use it
- // at the <codeline> start tag.
- m_lineNumber = l;
- if (compId)
+ else
{
- m_refId=compId;
- if (anchorId) m_refId+=(QCString)"_1"+anchorId;
- m_isMemberRef = anchorId!=0;
- if (extRef) m_external=extRef;
+ m_t << " refkind=\"compound\"";
}
}
- void setCurrentDoc(Definition *,const char *,bool)
- {
- }
- void addWord(const char *,bool)
+ if (!m_external.isEmpty())
{
+ m_t << " external=\"" << m_external << "\"";
}
-
- void finish()
- {
- if (m_insideCodeLine) endCodeLine();
- }
-
- private:
- FTextStream &m_t;
- QCString m_refId;
- QCString m_external;
- int m_lineNumber;
- bool m_isMemberRef;
- int m_col;
-
- bool m_insideCodeLine;
- bool m_normalHLNeedStartTag;
- bool m_insideSpecialHL;
-};
-
+ }
+ m_t << ">";
+ m_insideCodeLine=TRUE;
+ m_col=0;
+}
+void XMLCodeGenerator::endCodeLine()
+{
+ XML_DB(("(endCodeLine)\n"));
+ if (!m_insideSpecialHL && !m_normalHLNeedStartTag)
+ {
+ m_t << "</highlight>";
+ m_normalHLNeedStartTag=TRUE;
+ }
+ m_t << "</codeline>" << endl; // non DocBook
+ m_lineNumber = -1;
+ m_refId.resize(0);
+ m_external.resize(0);
+ m_insideCodeLine=FALSE;
+}
+void XMLCodeGenerator::startFontClass(const char *colorClass)
+{
+ XML_DB(("(startFontClass)\n"));
+ if (m_insideCodeLine && !m_insideSpecialHL && !m_normalHLNeedStartTag)
+ {
+ m_t << "</highlight>";
+ m_normalHLNeedStartTag=TRUE;
+ }
+ m_t << "<highlight class=\"" << colorClass << "\">"; // non DocBook
+ m_insideSpecialHL=TRUE;
+}
+void XMLCodeGenerator::endFontClass()
+{
+ XML_DB(("(endFontClass)\n"));
+ m_t << "</highlight>"; // non DocBook
+ m_insideSpecialHL=FALSE;
+}
+void XMLCodeGenerator::writeCodeAnchor(const char *)
+{
+ XML_DB(("(writeCodeAnchor)\n"));
+}
+void XMLCodeGenerator::writeLineNumber(const char *extRef,const char *compId,
+ const char *anchorId,int l)
+{
+ XML_DB(("(writeLineNumber)\n"));
+ // we remember the information provided here to use it
+ // at the <codeline> start tag.
+ m_lineNumber = l;
+ if (compId)
+ {
+ m_refId=compId;
+ if (anchorId) m_refId+=(QCString)"_1"+anchorId;
+ m_isMemberRef = anchorId!=0;
+ if (extRef) m_external=extRef;
+ }
+}
+void XMLCodeGenerator::finish()
+{
+ if (m_insideCodeLine) endCodeLine();
+}
static void writeTemplateArgumentList(ArgumentList *al,
FTextStream &t,
@@ -1163,7 +1134,7 @@ static void writeInnerNamespaces(const NamespaceSDict *nl,FTextStream &t)
NamespaceDef *nd;
for (nli.toFirst();(nd=nli.current());++nli)
{
- if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymouse scopes
+ if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymous scopes
{
t << " <innernamespace refid=\"" << nd->getOutputFileBase()
<< "\">" << convertToXML(nd->name()) << "</innernamespace>" << endl;
@@ -1845,7 +1816,7 @@ static void generateXMLForPage(PageDef *pd,FTextStream &ti,bool isExample)
SDict<SectionInfo>::Iterator li(*sectionDict);
SectionInfo *si;
int level=1,l;
- bool inLi[5]={ FALSE, FALSE, FALSE, FALSE };
+ bool inLi[5]={ FALSE, FALSE, FALSE, FALSE, FALSE };
int maxLevel = pd->localToc().xmlLevel();
for (li.toFirst();(si=li.current());++li)
{
@@ -1872,16 +1843,16 @@ static void generateXMLForPage(PageDef *pd,FTextStream &ti,bool isExample)
if (l <= maxLevel) t << " </tableofcontents>" << endl;
}
}
- if (l <= maxLevel && inLi[nextLevel]) t << " </tocsect>" << endl;
if (nextLevel <= maxLevel)
{
+ if (inLi[nextLevel]) t << " </tocsect>" << endl;
QCString titleDoc = convertToXML(si->title);
t << " <tocsect>" << endl;
t << " <name>" << (si->title.isEmpty()?si->label:titleDoc) << "</name>" << endl;
t << " <reference>" << convertToXML(pageName) << "_1" << convertToXML(si -> label) << "</reference>" << endl;
+ inLi[nextLevel]=TRUE;
+ level = nextLevel;
}
- inLi[nextLevel]=TRUE;
- level = nextLevel;
}
}
while (level>1 && level <= maxLevel)
diff --git a/src/xmlgen.h b/src/xmlgen.h
index 0447591..0555546 100644
--- a/src/xmlgen.h
+++ b/src/xmlgen.h
@@ -15,6 +15,48 @@
#ifndef XMLGEN_H
#define XMLGEN_H
+#include "outputgen.h"
+
+class XMLCodeGenerator : public CodeOutputInterface
+{
+ public:
+
+ XMLCodeGenerator(FTextStream &t) : m_t(t), m_lineNumber(-1), m_isMemberRef(FALSE), m_col(0),
+ m_insideCodeLine(FALSE), m_normalHLNeedStartTag(TRUE), m_insideSpecialHL(FALSE) {}
+ virtual ~XMLCodeGenerator() { }
+
+ void codify(const char *text);
+ void writeCodeLink(const char *ref,const char *file,
+ const char *anchor,const char *name,
+ const char *tooltip);
+ void writeTooltip(const char *, const DocLinkInfo &, const char *,
+ const char *, const SourceLinkInfo &, const SourceLinkInfo &
+ );
+ void startCodeLine(bool);
+ void endCodeLine();
+ void startFontClass(const char *colorClass);
+ void endFontClass();
+ void writeCodeAnchor(const char *);
+ void writeLineNumber(const char *extRef,const char *compId,
+ const char *anchorId,int l);
+ void setCurrentDoc(Definition *,const char *,bool){}
+ void addWord(const char *,bool){}
+
+ void finish();
+
+ private:
+ FTextStream &m_t;
+ QCString m_refId;
+ QCString m_external;
+ int m_lineNumber;
+ bool m_isMemberRef;
+ int m_col;
+
+ bool m_insideCodeLine;
+ bool m_normalHLNeedStartTag;
+ bool m_insideSpecialHL;
+};
+
void generateXML();
#endif
diff --git a/templates/html/doxygen.css b/templates/html/doxygen.css
index 4b4c8ea..c9bf428 100644
--- a/templates/html/doxygen.css
+++ b/templates/html/doxygen.css
@@ -80,6 +80,15 @@ p.endtd {
margin-bottom: 2px;
}
+p.interli {
+}
+
+p.interdd {
+}
+
+p.intertd {
+}
+
/* @end */
caption {
@@ -1112,14 +1121,12 @@ div.headertitle
direction: rtl;
}
-dl
-{
- padding: 0 0 0 10px;
+dl {
+ padding: 0 0 0 0;
}
-/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
-dl.section
-{
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */
+dl.section {
margin-left: 0px;
padding-left: 0px;
}
@@ -1750,3 +1757,8 @@ tt, code, kbd, samp
direction:ltr;
}
/* @end */
+
+u {
+ text-decoration: underline;
+}
+
diff --git a/templates/html/navtree.css b/templates/html/navtree.css
index 7d1cb67..81c54c2 100644
--- a/templates/html/navtree.css
+++ b/templates/html/navtree.css
@@ -96,7 +96,7 @@
.ui-resizable-e {
background-image:url("splitbar.png");
background-size:100%;
- background-repeat:no-repeat;
+ background-repeat:repeat-y;
background-attachment: scroll;
cursor:ew-resize;
height:100%;
diff --git a/templates/latex/doxygen.sty b/templates/latex/doxygen.sty
index d0d255c..cf92712 100644
--- a/templates/latex/doxygen.sty
+++ b/templates/latex/doxygen.sty
@@ -19,7 +19,7 @@
\RequirePackage{adjustbox}
\RequirePackage{amssymb}
\RequirePackage{stackengine}
-
+\RequirePackage[normalem]{ulem} % for strikeout, but don't modify emphasis
%---------- Internal commands used in this style file ----------------
diff --git a/templates/xml/compound.xsd b/templates/xml/compound.xsd
index 72d9097..61da4a7 100644
--- a/templates/xml/compound.xsd
+++ b/templates/xml/compound.xsd
@@ -384,6 +384,8 @@
<xsd:choice>
<xsd:element name="ulink" type="docURLLink" />
<xsd:element name="bold" type="docMarkupType" />
+ <xsd:element name="strike" type="docMarkupType" />
+ <xsd:element name="underline" type="docMarkupType" />
<xsd:element name="emphasis" type="docMarkupType" />
<xsd:element name="computeroutput" type="docMarkupType" />
<xsd:element name="subscript" type="docMarkupType" />
diff --git a/testing/005_attention.dox b/testing/005_attention.dox
index c3c390e..90f67f5 100644
--- a/testing/005_attention.dox
+++ b/testing/005_attention.dox
@@ -1,4 +1,4 @@
-// objective: test \attention, \not, \remark, \warning, and \par commands
+// objective: test \attention, \note, \remark, \warning, and \par commands
// check: indexpage.xml
/** \mainpage
* \attention Attention message.
diff --git a/testing/009/bug.xml b/testing/009/bug.xml
index a6dfe88..34a411b 100644
--- a/testing/009/bug.xml
+++ b/testing/009/bug.xml
@@ -9,17 +9,16 @@
<para>
<variablelist>
<varlistentry>
- <term><anchor id="bug_1_bug000001"/>Class <ref refid="class_bug" kindref="compound">Bug</ref></term>
+ <term>Class <ref refid="class_bug" kindref="compound">Bug</ref></term>
</varlistentry>
<listitem>
- <para>Class bug. </para>
+ <para><anchor id="bug_1_bug000001"/>Class bug. </para>
</listitem>
<varlistentry>
- <term><anchor id="bug_1_bug000002"/>Member <ref refid="class_bug_1a1f720954dd97cd1203e80501a6eae74c" kindref="member">Bug::foo</ref> ()</term>
+ <term>Member <ref refid="class_bug_1a1f720954dd97cd1203e80501a6eae74c" kindref="member">Bug::foo</ref> ()</term>
</varlistentry>
<listitem>
- <para>Function bug<itemizedlist><listitem><para>list item 1 in bug</para></listitem><listitem><para>list item 2 in bug</para></listitem></itemizedlist>
-</para>
+ <para><anchor id="bug_1_bug000002"/>Function bug<itemizedlist><listitem><para>list item 1 in bug</para></listitem><listitem><para>list item 2 in bug</para></listitem></itemizedlist></para>
</listitem>
</variablelist>
</para>
diff --git a/testing/009/deprecated.xml b/testing/009/deprecated.xml
index 5db2acd..a787015 100644
--- a/testing/009/deprecated.xml
+++ b/testing/009/deprecated.xml
@@ -9,16 +9,16 @@
<para>
<variablelist>
<varlistentry>
- <term><anchor id="deprecated_1_deprecated000001"/>Class <ref refid="class_deprecated" kindref="compound">Deprecated</ref></term>
+ <term>Class <ref refid="class_deprecated" kindref="compound">Deprecated</ref></term>
</varlistentry>
<listitem>
- <para>This class is deprecated </para>
+ <para><anchor id="deprecated_1_deprecated000001"/>This class is deprecated </para>
</listitem>
<varlistentry>
- <term><anchor id="deprecated_1_deprecated000002"/>Member <ref refid="class_deprecated_1a1d5f6803e72c625727e7083d1722dbf9" kindref="member">Deprecated::deprecated</ref> ()</term>
+ <term>Member <ref refid="class_deprecated_1a1d5f6803e72c625727e7083d1722dbf9" kindref="member">Deprecated::deprecated</ref> ()</term>
</varlistentry>
<listitem>
- <para>No not use this function anymore. </para>
+ <para><anchor id="deprecated_1_deprecated000002"/>No not use this function anymore. </para>
</listitem>
</variablelist>
</para>
diff --git a/testing/009/reminders.xml b/testing/009/reminders.xml
index a5c5560..f848e3c 100644
--- a/testing/009/reminders.xml
+++ b/testing/009/reminders.xml
@@ -9,16 +9,16 @@
<para>
<variablelist>
<varlistentry>
- <term><anchor id="reminders_1_reminders000001"/>Class <ref refid="class_reminder" kindref="compound">Reminder</ref></term>
+ <term>Class <ref refid="class_reminder" kindref="compound">Reminder</ref></term>
</varlistentry>
<listitem>
- <para>A reminder </para>
+ <para><anchor id="reminders_1_reminders000001"/>A reminder </para>
</listitem>
<varlistentry>
- <term><anchor id="reminders_1_reminders000002"/>Member <ref refid="class_reminder_1a173b5218bb11287b0e86a550d9f0728d" kindref="member">Reminder::reminder</ref> ()</term>
+ <term>Member <ref refid="class_reminder_1a173b5218bb11287b0e86a550d9f0728d" kindref="member">Reminder::reminder</ref> ()</term>
</varlistentry>
<listitem>
- <para>Need to rework this before the next release. </para>
+ <para><anchor id="reminders_1_reminders000002"/>Need to rework this before the next release. </para>
</listitem>
</variablelist>
</para>
diff --git a/testing/009/test.xml b/testing/009/test.xml
index e206440..828316d 100644
--- a/testing/009/test.xml
+++ b/testing/009/test.xml
@@ -9,16 +9,16 @@
<para>
<variablelist>
<varlistentry>
- <term><anchor id="test_1_test000001"/>Class <ref refid="class_test" kindref="compound">Test</ref></term>
+ <term>Class <ref refid="class_test" kindref="compound">Test</ref></term>
</varlistentry>
<listitem>
- <para>This is part of testing </para>
+ <para><anchor id="test_1_test000001"/>This is part of testing </para>
</listitem>
<varlistentry>
- <term><anchor id="test_1_test000002"/>Member <ref refid="class_test_1a9fc54b716f326514a4c5f434137f4fc0" kindref="member">Test::test</ref> ()</term>
+ <term>Member <ref refid="class_test_1a9fc54b716f326514a4c5f434137f4fc0" kindref="member">Test::test</ref> ()</term>
</varlistentry>
<listitem>
- <para>more things to test. </para>
+ <para><anchor id="test_1_test000002"/>more things to test. </para>
</listitem>
</variablelist>
</para>
diff --git a/testing/009/todo.xml b/testing/009/todo.xml
index 88d050e..394f07d 100644
--- a/testing/009/todo.xml
+++ b/testing/009/todo.xml
@@ -9,16 +9,16 @@
<para>
<variablelist>
<varlistentry>
- <term><anchor id="todo_1_todo000001"/>Class <ref refid="class_todo" kindref="compound">Todo</ref></term>
+ <term>Class <ref refid="class_todo" kindref="compound">Todo</ref></term>
</varlistentry>
<listitem>
- <para>This still needs to be done. </para>
+ <para><anchor id="todo_1_todo000001"/>This still needs to be done. </para>
</listitem>
<varlistentry>
- <term><anchor id="todo_1_todo000002"/>Member <ref refid="class_todo_1a9e70ec9176ac4c1b20e011b4daddc9d8" kindref="member">Todo::todo</ref> ()</term>
+ <term>Member <ref refid="class_todo_1a9e70ec9176ac4c1b20e011b4daddc9d8" kindref="member">Todo::todo</ref> ()</term>
</varlistentry>
<listitem>
- <para>more things to do here </para>
+ <para><anchor id="todo_1_todo000002"/>more things to do here </para>
</listitem>
</variablelist>
</para>
diff --git a/testing/012/citelist.xml b/testing/012/citelist.xml
index 96b94a3..f415968 100644
--- a/testing/012/citelist.xml
+++ b/testing/012/citelist.xml
@@ -9,7 +9,7 @@
<para>
<variablelist>
<varlistentry>
- <term><anchor id="_1CITEREF_knuth79"/>[1]</term>
+ <term><anchor id="citelist_1CITEREF_knuth79"/>[1]</term>
</varlistentry>
<listitem>
<para>Donald<nonbreakablespace/>E. Knuth. <emphasis>Tex and Metafont, New Directions in Typesetting</emphasis>. American Mathematical Society and Digital Press, Stanford, 1979.</para>
diff --git a/testing/031/indexpage.xml b/testing/031/indexpage.xml
index 3b3a2e3..2c1dfd7 100644
--- a/testing/031/indexpage.xml
+++ b/testing/031/indexpage.xml
@@ -8,6 +8,7 @@
<detaileddescription>
<para>Some text. <image type="html" name="sample.png"/>
<image type="latex" name="sample.png" width="5cm">Doxygen logo</image>
+ <image type="docbook" name="sample.png"/>
More text. </para>
</detaileddescription>
</compounddef>
diff --git a/testing/031_image.dox b/testing/031_image.dox
index f437086..8ba47b7 100644
--- a/testing/031_image.dox
+++ b/testing/031_image.dox
@@ -5,5 +5,6 @@
* Some text.
* \image html sample.png
* \image latex sample.png "Doxygen logo" width=5cm
+ * \image docbook sample.png
* More text.
*/
diff --git a/testing/043_page.dox b/testing/043_page.dox
index d554da2..9ac5c0e 100644
--- a/testing/043_page.dox
+++ b/testing/043_page.dox
@@ -4,7 +4,7 @@
/** \page mypage Page Title
* \brief Page brief description.
*
- * @tableofcontents{xml,html,latex}
+ * @tableofcontents{xml,html,latex,docbook}
*
* Text at page level. See \ref mysect for more.
* \section mysect Section Title.
diff --git a/testing/051/indexpage.xml b/testing/051/indexpage.xml
index 776f525..50a6ff8 100644
--- a/testing/051/indexpage.xml
+++ b/testing/051/indexpage.xml
@@ -6,7 +6,7 @@
<briefdescription>
</briefdescription>
<detaileddescription>
- <para>Dollar $ At @ Backslash \ Amphasand &amp; Less &lt; Greater &gt; Hash # Percent % Quote " Dot . Double colon :: Pipe | Plus + Minus - </para>
+ <para>Dollar $ At @ Backslash \ Ampersand &amp; Less &lt; Greater &gt; Hash # Percent % Quote " Dot . Double colon :: Pipe | Plus + Minus - </para>
</detaileddescription>
</compounddef>
</doxygen>
diff --git a/testing/051_escape.dox b/testing/051_escape.dox
index 290b298..2165564 100644
--- a/testing/051_escape.dox
+++ b/testing/051_escape.dox
@@ -5,7 +5,7 @@
Dollar \$
At \@
Backslash \\
-Amphasand \&
+Ampersand \&
Less \<
Greater \>
Hash \#
diff --git a/testing/README.txt b/testing/README.txt
index a5a0ad9..39b2345 100644
--- a/testing/README.txt
+++ b/testing/README.txt
@@ -1,4 +1,4 @@
-Doxygen regession test suite
+Doxygen regression test suite
============================
This directory contains a set of regression tests. Each test consists of a
@@ -7,7 +7,7 @@ has the same 3 digit number. The directory contains one or more reference
files that are compared against the XML output produced by doxygen. If the
result is the same, there is no regression and the test passes. If there is a
difference the test fails and the difference (in diff -u format) will be shown.
-It is also possible to see whether or not the test can be build to a xhtml set
+It is also possible to see whether or not the test can be built to a xhtml set
of files (and tested against a DTD), it is also possible to create a pdf file
for each test to see if the LaTeX / pdf generation is possible.
@@ -17,6 +17,8 @@ optional parameters:
--doxygen [DOXYGEN] path/name of the doxygen executable
--xmllint [XMLLINT] path/name of the xmllint executable
--id IDS [IDS ...] id of the test to perform
+ --start_id START_ID run tests starting with number n
+ --end_id END_ID run tests ending with number n
--all perform all tests
--inputdir [INPUTDIR]
input directory containing the tests
@@ -24,10 +26,15 @@ optional parameters:
output directory to write the doxygen output to
--noredir disable redirection of doxygen warnings
--xml create xml output and check
+ --rtf create rtf output
+ --docbook create docbook output and check with xmllint
--xhtml create xhtml output and check with xmllint
--pdf create LaTeX output and create pdf from it
+ --subdirs use the configuration parameter CREATE_SUBDIRS=YES
--keep keep result directories
-In case neither --xml, --pdf or --xhtml is used the default is set to --xml.
+ --cfg CFGS [CFGS ...] run test with extra doxygen configuration settings
+ (the option may be specified multiple times
+In case neither --xml, --pdf, --rtf, --docbook or --xhtml is used the default is set to --xml.
The runtest.pl has the following dependencies on 3rd party tools:
- python to run the script
@@ -57,4 +64,3 @@ There is also a CMakeLists.txt, which can be used from the build directory
to run all tests by simply invoking 'make tests', to use the specific options use
the flag TEST_FLAGS with make
e.g. make tests TEST_FLAGS="--id=5 --id=10 --pdf --xhtml"
-
diff --git a/testing/runtests.py b/testing/runtests.py
index 9330d23..452c36e 100644
--- a/testing/runtests.py
+++ b/testing/runtests.py
@@ -43,6 +43,28 @@ class Tester:
rtnmsg += o
return rtnmsg
+ def cleanup_xmllint_docbook(self,errmsg):
+ # For future work, first get everything valid XML
+ msg = self.cleanup_xmllint(errmsg).split('\n')
+ rtnmsg = ""
+ cnt = 0
+ for o in msg:
+ if (o):
+ if (cnt):
+ cnt -= 1
+ pass
+ elif (o.endswith("does not validate")):
+ pass
+ elif (o.find("no DTD found!")!=-1):
+ pass
+ elif (o.find("is not an NCName")!=-1):
+ cnt = 2
+ else:
+ if (rtnmsg):
+ rtnmsg += '\n'
+ rtnmsg += o
+ return rtnmsg
+
def get_config(self):
config = {}
with open(self.args.inputdir+'/'+self.test,'r') as f:
@@ -53,7 +75,7 @@ class Tester:
value = m.group('value')
if (key=='config'):
value = value.replace('$INPUTDIR',self.args.inputdir)
- #print('key=%s value=%s' % (key,value))
+ # print('key=%s value=%s' % (key,value))
config.setdefault(key, []).append(value)
return config
@@ -74,6 +96,16 @@ class Tester:
print('XML_OUTPUT=%s/out' % self.test_out, file=f)
else:
print('GENERATE_XML=NO', file=f)
+ if (self.args.rtf):
+ print('GENERATE_RTF=YES', file=f)
+ print('RTF_OUTPUT=%s/rtf' % self.test_out, file=f)
+ else:
+ print('GENERATE_RTF=NO', file=f)
+ if (self.args.docbook):
+ print('GENERATE_DOCBOOK=YES', file=f)
+ print('DOCBOOK_OUTPUT=%s/docbook' % self.test_out, file=f)
+ else:
+ print('GENERATE_DOCBOOK=NO', file=f)
if (self.args.xhtml):
print('GENERATE_HTML=YES', file=f)
# HTML_OUTPUT can also be set locally
@@ -82,6 +114,14 @@ class Tester:
if (self.args.pdf):
print('GENERATE_LATEX=YES', file=f)
print('LATEX_OUTPUT=%s/latex' % self.test_out, file=f)
+ if self.args.subdirs:
+ print('CREATE_SUBDIRS=YES', file=f)
+ if (self.args.cfgs):
+ for cfg in list(itertools.chain.from_iterable(self.args.cfgs)):
+ if cfg.find('=') == -1:
+ print("Not a doxygen configuration item, missing '=' sign: '%s'."%cfg)
+ sys.exit(1)
+ print(cfg, file=f)
if 'check' not in self.config or not self.config['check']:
print('Test doesn\'t specify any files to check')
@@ -97,7 +137,7 @@ class Tester:
redir=''
if os.system('%s %s/Doxyfile %s' % (self.args.doxygen,self.test_out,redir))!=0:
- print('Error: failed to run %s on %s/Doxyfile' % (self.args.doxygen,self.test_out));
+ print('Error: failed to run %s on %s/Doxyfile' % (self.args.doxygen,self.test_out))
sys.exit(1)
# update the reference data for this test
@@ -140,6 +180,8 @@ class Tester:
failed_xml=False
failed_html=False
failed_latex=False
+ failed_docbook=False
+ failed_rtf=False
msg = ()
# look for files to check against the reference
if self.args.xml:
@@ -149,8 +191,14 @@ class Tester:
check_file='%s/out/%s' % (self.test_out,check)
# check if the file we need to check is actually generated
if not os.path.isfile(check_file):
- msg += ('Non-existing file %s after \'check:\' statement' % check_file,)
- break
+ # try with sub dirs
+ check_file = glob.glob('%s/out/*/*/%s' % (self.test_out,check))
+ if not check_file:
+ check_file='%s/out/%s' % (self.test_out,check)
+ msg += ('Non-existing file %s after \'check:\' statement' % check_file,)
+ break
+ else:
+ check_file = check_file[0]
# convert output to canonical form
data = os.popen('%s --format --noblanks --nowarning %s' % (self.args.xmllint,check_file)).read()
if data:
@@ -171,6 +219,34 @@ class Tester:
xml_output='%s/out' % self.test_out
shutil.rmtree(xml_output,ignore_errors=True)
+ if (self.args.rtf):
+ # no tests defined yet
+ pass
+
+ if (self.args.docbook):
+ docbook_output='%s/docbook' % self.test_out
+ if (sys.platform == 'win32'):
+ redirx=' 2> %s/temp >nul:'%docbook_output
+ else:
+ redirx='2>%s/temp >/dev/null'%docbook_output
+ # For future work, first get everything valid XML
+ # exe_string = '%s --relaxng db/docbook.rng --nonet --postvalid %s/*xml %s % (self.args.xmllint,docbook_output,redirx)
+ tests = []
+ tests.append(glob.glob('%s/*.xml' % (docbook_output)))
+ tests.append(glob.glob('%s/*/*/*.xml' % (docbook_output)))
+ tests = ' '.join(list(itertools.chain.from_iterable(tests))).replace(self.args.outputdir +'/','').replace('\\','/')
+ exe_string = '%s --nonet --postvalid %s %s' % (self.args.xmllint,tests,redirx)
+ exe_string += ' %s more "%s/temp"' % (separ,docbook_output)
+
+ failed_docbook=False
+ xmllint_out = os.popen(exe_string).read()
+ xmllint_out = self.cleanup_xmllint_docbook(xmllint_out)
+ if xmllint_out:
+ msg += (xmllint_out,)
+ failed_docbook=True
+ elif not self.args.keep:
+ shutil.rmtree(docbook_output,ignore_errors=True)
+
if (self.args.xhtml):
html_output='%s/html' % self.test_out
if (sys.platform == 'win32'):
@@ -206,7 +282,7 @@ class Tester:
elif not self.args.keep:
shutil.rmtree(latex_output,ignore_errors=True)
- if failed_xml or failed_html or failed_latex:
+ if failed_xml or failed_html or failed_latex or failed_docbook or failed_rtf:
testmgr.ok(False,self.test_name,msg)
return
@@ -268,14 +344,18 @@ def main():
parser = argparse.ArgumentParser(description='run doxygen tests')
parser.add_argument('--updateref',help=
'update the reference files. Should be used in combination with -id to '
- 'update the reference file(s) for the given test',action="store_true")
+ 'update the reference file(s) for the given test',action="store_true")
parser.add_argument('--doxygen',nargs='?',default='doxygen',help=
'path/name of the doxygen executable')
parser.add_argument('--xmllint',nargs='?',default='xmllint',help=
'path/name of the xmllint executable')
parser.add_argument('--id',nargs='+',dest='ids',action='append',type=int,help=
- 'run test with number n only (the option may be specified run test with '
- 'number n only (the option may be specified')
+ 'run test with number n only (the option can be specified to run test with '
+ 'number n only (the option can be specified multiple times')
+ parser.add_argument('--start_id',dest='start_id',type=int,help=
+ 'run tests starting with number n')
+ parser.add_argument('--end_id',dest='end_id',type=int,help=
+ 'run tests ending with number n')
parser.add_argument('--all',help=
'can be used in combination with -updateref to update the reference files '
'for all tests.',action="store_true")
@@ -287,17 +367,26 @@ def main():
'disable redirection of doxygen warnings',action="store_true")
parser.add_argument('--xml',help='create xml output and check',
action="store_true")
+ parser.add_argument('--rtf',help=
+ 'create rtf output',action="store_true")
+ parser.add_argument('--docbook',help=
+ 'create docbook output and check with xmllint',action="store_true")
parser.add_argument('--xhtml',help=
'create xhtml output and check with xmllint',action="store_true")
parser.add_argument('--pdf',help='create LaTeX output and create pdf from it',
action="store_true")
+ parser.add_argument('--subdirs',help='use the configuration parameter CREATE_SUBDIRS=YES',
+ action="store_true")
parser.add_argument('--keep',help='keep result directories',
action="store_true")
+ parser.add_argument('--cfg',nargs='+',dest='cfgs',action='append',help=
+ 'run test with extra doxygen configuration settings '
+ '(the option may be specified multiple times')
test_flags = os.getenv('TEST_FLAGS', default='').split()
args = parser.parse_args(test_flags + sys.argv[1:])
# sanity check
- if (not args.xml) and (not args.pdf) and (not args.xhtml):
+ if (not args.xml) and (not args.pdf) and (not args.xhtml) and (not args.docbook and (not args.rtf)):
args.xml=True
if (not args.updateref is None) and (args.ids is None) and (args.all is None):
parser.error('--updateref requires either --id or --all')
@@ -305,15 +394,26 @@ def main():
starting_directory = os.getcwd()
os.chdir(args.inputdir)
# find the tests to run
- if args.ids: # test ids are given by user
- tests = []
+ tests = []
+ if args.start_id:
+ if args.end_id:
+ for id in range(args.start_id, args.end_id + 1):
+ tests.append(glob.glob('%s_*'%id))
+ tests.append(glob.glob('0%s_*'%id))
+ tests.append(glob.glob('00%s_*'%id))
+ else:
+ parser.error('--start_id requires --end_id')
+ elif args.end_id:
+ parser.error('--end_id requires --start_id')
+ if args.ids: # test ids are given by user
for id in list(itertools.chain.from_iterable(args.ids)):
tests.append(glob.glob('%s_*'%id))
tests.append(glob.glob('0%s_*'%id))
tests.append(glob.glob('00%s_*'%id))
- tests = list(itertools.chain.from_iterable(tests))
- else: # find all tests
+ if (not args.ids and not args.start_id): # find all tests
tests = glob.glob('[0-9][0-9][0-9]_*')
+ else:
+ tests = list(itertools.chain.from_iterable(tests))
os.chdir(starting_directory)
# create test manager to run the tests
diff --git a/vhdlparser/VhdlParser.cc b/vhdlparser/VhdlParser.cc
index a3de14a..4cf8ec0 100644
--- a/vhdlparser/VhdlParser.cc
+++ b/vhdlparser/VhdlParser.cc
@@ -10398,11 +10398,11 @@ s+=",";s+=s1;
jj_consume_token(SEMI_T);
}
-QStringList ql1=QStringList::split(",",s,FALSE);
+QCStringList ql1=QCStringList::split(",",s);
for (uint j=0;j<ql1.count();j++)
{
- QStringList ql=QStringList::split(".",ql1[j],FALSE);
- QCString it=ql[1].utf8();
+ QCStringList ql=QCStringList::split(".",ql1[j]);
+ QCString it=ql[1];
if ( parse_sec==0 && Config_getBool(SHOW_INCLUDE_FILES) )
{
VhdlParser::addVhdlType(it.data(),getLine(),Entry::VARIABLE_SEC,VhdlDocGen::USE,it.data(),"_use_",Public);
diff --git a/vhdlparser/vhdlparser.jj b/vhdlparser/vhdlparser.jj
index d21afe1..af1bd34 100644
--- a/vhdlparser/vhdlparser.jj
+++ b/vhdlparser/vhdlparser.jj
@@ -2412,11 +2412,11 @@ QCString unconstraint_array_definition() : {QCString s,s1,s2,s3;}
{
<USE_T> s=selected_name()(<COMMA_T> s1=selected_name(){s+=",";s+=s1;})* <SEMI_T>
{
- QStringList ql1=QStringList::split(",",s,FALSE);
+ QCStringList ql1=QCStringList::split(",",s);
for (uint j=0;j<ql1.count();j++)
{
- QStringList ql=QStringList::split(".",ql1[j],FALSE);
- QCString it=ql[1].utf8();
+ QCStringList ql=QCStringList::split(".",ql1[j]);
+ QCString it=ql[1];
if ( parse_sec==0 && Config_getBool(SHOW_INCLUDE_FILES) )
{
VhdlParser::addVhdlType(it.data(),getLine(),Entry::VARIABLE_SEC,VhdlDocGen::USE,it.data(),"_use_",Public);