summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rw-r--r--CMakeLists.txt15
-rw-r--r--Doxyfile32
-rw-r--r--addon/doxmlparser/src/basehandler.h2
-rw-r--r--addon/doxmlparser/src/compoundhandler.cpp11
-rw-r--r--addon/doxmlparser/src/dochandler.cpp14
-rw-r--r--addon/doxmlparser/src/linkedtexthandler.cpp6
-rw-r--r--addon/doxmlparser/src/loamhandler.cpp2
-rw-r--r--addon/doxmlparser/src/mainhandler.cpp6
-rw-r--r--addon/doxmlparser/src/memberhandler.cpp16
-rw-r--r--addon/doxmlparser/src/paramhandler.cpp8
-rw-r--r--addon/doxmlparser/src/sectionhandler.cpp8
-rw-r--r--addon/doxmlparser/test/main.cpp26
-rw-r--r--addon/doxyapp/CMakeLists.txt4
-rw-r--r--addon/doxyapp/doxyapp.cpp9
-rw-r--r--addon/doxyparse/CMakeLists.txt4
-rw-r--r--addon/doxyparse/README14
-rw-r--r--addon/doxyparse/doxyparse.cpp128
-rw-r--r--addon/doxysearch/doxysearch.cpp22
-rw-r--r--addon/doxywizard/CMakeLists.txt12
-rw-r--r--addon/doxywizard/config_doxyw.l20
-rwxr-xr-xaddon/doxywizard/doxywizard.cpp2
-rw-r--r--addon/doxywizard/expert.cpp2
-rw-r--r--cmake/doxygen_version.cmake96
-rw-r--r--cmake/git_watcher.cmake213
-rw-r--r--doc/commands.doc14
-rw-r--r--doc/doxygen_manual.tex37
-rw-r--r--doc/faq.doc7
-rw-r--r--doc/htmlcmds.doc4
-rw-r--r--doc/install.doc2
-rw-r--r--doc/preprocessing.doc4
-rw-r--r--doc/trouble.doc2
-rw-r--r--examples/memgrp.cpp4
-rw-r--r--jquery/README2
-rw-r--r--liblodepng/CMakeLists.txt3
-rw-r--r--liblodepng/lodepng.cpp (renamed from src/lodepng.cpp)4
-rw-r--r--liblodepng/lodepng.h (renamed from src/lodepng.h)8
-rw-r--r--libmd5/Makefile.in18
-rw-r--r--libmd5/libmd5.pro.in10
-rw-r--r--libmscgen/CMakeLists.txt38
-rw-r--r--libmscgen/COPYING287
-rw-r--r--libmscgen/README.txt20
-rw-r--r--libmscgen/gd.c4539
-rw-r--r--libmscgen/gd.h1620
-rw-r--r--libmscgen/gd_color.c35
-rw-r--r--libmscgen/gd_color.h14
-rw-r--r--libmscgen/gd_errors.h46
-rw-r--r--libmscgen/gd_intern.h78
-rw-r--r--libmscgen/gd_lodepng.c35
-rw-r--r--libmscgen/gd_security.c32
-rw-r--r--libmscgen/gdfonts.c3890
-rw-r--r--libmscgen/gdfonts.h27
-rw-r--r--libmscgen/gdfontt.c2613
-rw-r--r--libmscgen/gdfontt.h28
-rw-r--r--libmscgen/gdhelpers.c118
-rw-r--r--libmscgen/gdhelpers.h76
-rw-r--r--libmscgen/gdtables.c726
-rw-r--r--libmscgen/mscgen_adraw.c140
-rw-r--r--libmscgen/mscgen_adraw.h300
-rw-r--r--libmscgen/mscgen_adraw_int.h65
-rw-r--r--libmscgen/mscgen_api.c1874
-rw-r--r--libmscgen/mscgen_api.h41
-rw-r--r--libmscgen/mscgen_bool.h36
-rw-r--r--libmscgen/mscgen_config.h55
-rw-r--r--libmscgen/mscgen_gd_out.c606
-rw-r--r--libmscgen/mscgen_language.h186
-rw-r--r--libmscgen/mscgen_language.y430
-rw-r--r--libmscgen/mscgen_lexer.h62
-rw-r--r--libmscgen/mscgen_lexer.l236
-rw-r--r--libmscgen/mscgen_msc.c804
-rw-r--r--libmscgen/mscgen_msc.h299
-rw-r--r--libmscgen/mscgen_null_out.c170
-rw-r--r--libmscgen/mscgen_ps_out.c595
-rw-r--r--libmscgen/mscgen_safe.c119
-rw-r--r--libmscgen/mscgen_safe.h59
-rw-r--r--libmscgen/mscgen_svg_out.c585
-rw-r--r--libmscgen/mscgen_usage.c111
-rw-r--r--libmscgen/mscgen_usage.h49
-rw-r--r--libmscgen/mscgen_utf8.c103
-rw-r--r--libmscgen/mscgen_utf8.h48
-rw-r--r--libversion/CMakeLists.txt27
-rw-r--r--libversion/doxyversion.cpp.in7
-rw-r--r--libversion/gitversion.cpp.in16
-rw-r--r--libversion/version.h (renamed from addon/doxywizard/version.h)5
-rw-r--r--src/CMakeLists.txt29
-rw-r--r--src/classdef.cpp38
-rw-r--r--src/cmdmapper.cpp2
-rw-r--r--src/cmdmapper.h2
-rw-r--r--src/code.l153
-rw-r--r--src/commentcnv.l20
-rw-r--r--src/commentscan.h8
-rw-r--r--src/commentscan.l272
-rw-r--r--src/config.xml18
-rwxr-xr-xsrc/configgen.py4
-rw-r--r--src/configimpl.l250
-rw-r--r--src/constexp.l2
-rw-r--r--src/context.cpp12
-rw-r--r--src/declinfo.h3
-rw-r--r--src/declinfo.l31
-rw-r--r--src/defargs.l6
-rw-r--r--src/defgen.cpp13
-rw-r--r--src/definition.cpp12
-rw-r--r--src/dia.cpp2
-rw-r--r--src/diagram.cpp6
-rw-r--r--src/dirdef.cpp1
-rw-r--r--src/docbookgen.cpp25
-rw-r--r--src/docbookgen.h12
-rw-r--r--src/docbookvisitor.cpp93
-rw-r--r--src/docbookvisitor.h2
-rw-r--r--src/docgroup.cpp215
-rw-r--r--src/docgroup.h54
-rw-r--r--src/docparser.cpp552
-rw-r--r--src/docparser.h44
-rw-r--r--src/doctokenizer.l16
-rw-r--r--src/docvisitor.h3
-rw-r--r--src/dot.cpp4537
-rw-r--r--src/dot.h489
-rw-r--r--src/dotcallgraph.cpp217
-rw-r--r--src/dotcallgraph.h52
-rw-r--r--src/dotclassgraph.cpp548
-rw-r--r--src/dotclassgraph.h62
-rw-r--r--src/dotdirdeps.cpp220
-rw-r--r--src/dotdirdeps.h51
-rw-r--r--src/dotfilepatcher.cpp539
-rw-r--r--src/dotfilepatcher.h53
-rw-r--r--src/dotgfxhierarchytable.cpp302
-rw-r--r--src/dotgfxhierarchytable.h55
-rw-r--r--src/dotgraph.cpp400
-rw-r--r--src/dotgraph.h113
-rw-r--r--src/dotgroupcollaboration.cpp381
-rw-r--r--src/dotgroupcollaboration.h85
-rw-r--r--src/dotincldepgraph.cpp238
-rw-r--r--src/dotincldepgraph.h56
-rw-r--r--src/dotnode.cpp950
-rw-r--r--src/dotnode.h138
-rw-r--r--src/dotrunner.cpp294
-rw-r--r--src/dotrunner.h138
-rw-r--r--src/doxygen.cpp346
-rw-r--r--src/doxygen.h8
-rw-r--r--src/filedef.cpp3
-rw-r--r--src/filename.cpp2
-rw-r--r--src/fortrancode.l6
-rw-r--r--src/fortranscanner.l8
-rw-r--r--src/ftvhelp.h2
-rw-r--r--src/groupdef.cpp9
-rw-r--r--src/htags.cpp4
-rw-r--r--src/htmldocvisitor.cpp28
-rw-r--r--src/htmldocvisitor.h2
-rw-r--r--src/htmlgen.cpp71
-rw-r--r--src/htmlgen.h16
-rw-r--r--src/index.cpp7
-rw-r--r--src/latexdocvisitor.cpp26
-rw-r--r--src/latexdocvisitor.h2
-rw-r--r--src/latexgen.cpp44
-rw-r--r--src/latexgen.h12
-rw-r--r--src/layout.cpp9
-rw-r--r--src/layout.h2
-rw-r--r--src/mandocvisitor.cpp24
-rw-r--r--src/mandocvisitor.h2
-rw-r--r--src/mangen.h12
-rw-r--r--src/markdown.cpp12
-rw-r--r--src/memberdef.cpp66
-rw-r--r--src/memberdef.h9
-rw-r--r--src/membergroup.cpp2
-rw-r--r--src/memberlist.cpp6
-rw-r--r--src/msc.cpp78
-rw-r--r--src/namespacedef.cpp2
-rw-r--r--src/outputgen.h14
-rw-r--r--src/outputlist.cpp47
-rw-r--r--src/outputlist.h29
-rw-r--r--src/perlmodgen.cpp18
-rw-r--r--src/portable.cpp13
-rw-r--r--src/portable.h1
-rw-r--r--src/pre.l70
-rw-r--r--src/printdocvisitor.h38
-rw-r--r--src/pycode.l38
-rw-r--r--src/pyscanner.l75
-rw-r--r--src/resourcemgr.cpp2
-rw-r--r--src/rtfdocvisitor.cpp32
-rw-r--r--src/rtfdocvisitor.h2
-rw-r--r--src/rtfgen.cpp43
-rw-r--r--src/rtfgen.h18
-rw-r--r--src/scanner.l124
-rw-r--r--src/searchindex.cpp5
-rw-r--r--src/sqlite3gen.cpp8
-rw-r--r--src/tagreader.cpp116
-rw-r--r--src/tclscanner.l27
-rw-r--r--src/template.cpp2
-rw-r--r--src/textdocvisitor.h2
-rw-r--r--src/util.cpp317
-rw-r--r--src/util.h16
-rw-r--r--src/version.h23
-rw-r--r--src/vhdlcode.l2
-rw-r--r--src/vhdldocgen.cpp4
-rw-r--r--src/vhdljjparser.cpp4
-rw-r--r--src/xmldocvisitor.cpp37
-rw-r--r--src/xmldocvisitor.h2
-rw-r--r--src/xmlgen.cpp12
-rw-r--r--templates/latex/doxygen.sty55
-rwxr-xr-xtemplates/latex/longtable_doxygen.sty448
-rwxr-xr-xtemplates/latex/tabu_doxygen.sty2557
-rw-r--r--templates/xml/compound.xsd31
-rw-r--r--testing/019/group__g1.xml2
-rw-r--r--testing/019/group__g2.xml2
-rw-r--r--testing/019/group__g3.xml2
-rw-r--r--testing/021/indexpage.xml2
-rw-r--r--testing/071/namespace_a_namespace_1_1_0d0.xml (renamed from testing/071/namespace_a_namespace_1_1_0D0.xml)2
-rw-r--r--testing/071_enum_in_anon_ns.cpp2
-rw-r--r--testing/086/086__style__tags_8h.xml13
-rw-r--r--testing/086_style_tags.h17
-rwxr-xr-x[-rw-r--r--]testing/runtests.py0
211 files changed, 32114 insertions, 6840 deletions
diff --git a/.travis.yml b/.travis.yml
index 8b84cbe..48dcff4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -63,6 +63,7 @@ before_script:
libxml2/2.9.8@bincrafters/stable
libiconv/1.15@bincrafters/stable
qt/5.12.0@bincrafters/stable
+ bison/3.0.5@bincrafters/stable
[options]
qt:shared=True" >> conanfile.txt;
fi;
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6bf9246..2621844 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@
# Documents produced by Doxygen are derivative works derived from the
# input used in their production; they are not affected by this license.
-cmake_minimum_required(VERSION 3.1.3)
+cmake_minimum_required(VERSION 3.2)
project(doxygen)
option(build_wizard "Build the GUI frontend for doxygen." OFF)
@@ -26,6 +26,8 @@ option(win_static "Link with /MT in stead of /MD on windows" OFF)
option(english_only "Only compile in support for the English language" OFF)
option(force_qt4 "Forces doxywizard to build using Qt4 even if Qt5 is installed" OFF)
+SET(enlarge_lex_buffers "262144" CACHE INTERNAL "Sets the lex input and read buffere to the specified size")
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(TOP "${CMAKE_SOURCE_DIR}")
include(version)
@@ -46,6 +48,11 @@ if (use_libclang)
endif()
endif()
+# use C++11 standard for compiling (libclang option requires it)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS ON)
+
if (CMAKE_SYSTEM MATCHES "Darwin")
set(CMAKE_CXX_FLAGS "-Wno-deprecated-register -mmacosx-version-min=${MACOS_VERSION_MIN} ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "-Wno-deprecated-register -mmacosx-version-min=${MACOS_VERSION_MIN} ${CMAKE_C_FLAGS}")
@@ -83,6 +90,9 @@ find_program(DOT NAMES dot)
find_package(PythonInterp REQUIRED)
find_package(FLEX REQUIRED)
find_package(BISON REQUIRED)
+if (BISON_VERSION VERSION_LESS 2.7)
+ message(SEND_ERROR "Doxygen requires at least bison version 2.7 (installed: ${BISON_VERSION})")
+endif()
find_package(Threads)
if (sqlite3)
@@ -143,6 +153,9 @@ endif()
add_subdirectory(libmd5)
+add_subdirectory(liblodepng)
+add_subdirectory(libmscgen)
+add_subdirectory(libversion)
add_subdirectory(qtools)
add_subdirectory(vhdlparser)
add_subdirectory(src)
diff --git a/Doxyfile b/Doxyfile
index cc2aca7..aa0de73 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.7
+# Doxyfile 1.8.16
#---------------------------------------------------------------------------
# Project related configuration options
@@ -12,6 +12,7 @@ OUTPUT_DIRECTORY = doxygen_docs
CREATE_SUBDIRS = YES
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
+OUTPUT_TEXT_DIRECTION = None
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF =
@@ -22,6 +23,7 @@ STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
+JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
@@ -33,6 +35,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
+OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS =
@@ -42,6 +45,7 @@ CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
+GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
@@ -52,6 +56,7 @@ LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
+EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
@@ -64,6 +69,7 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
+HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
@@ -94,6 +100,7 @@ WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
+WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text "
WARN_LOGFILE =
#---------------------------------------------------------------------------
@@ -106,8 +113,7 @@ FILE_PATTERNS = *.h \
*.cpp \
*.md
RECURSIVE = NO
-EXCLUDE = src/logos.cpp \
- src/lodepng.cpp
+EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
@@ -153,6 +159,7 @@ HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
+HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = YES
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = YES
@@ -186,7 +193,7 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
-MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
+MATHJAX_RELPATH =
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
@@ -201,13 +208,15 @@ EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT =
-LATEX_CMD_NAME = latex
+LATEX_CMD_NAME =
MAKEINDEX_CMD_NAME = makeindex
+LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
-PAPER_TYPE = a4wide
+PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
+LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = NO
@@ -215,6 +224,8 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
+LATEX_TIMESTAMP = NO
+LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -224,6 +235,7 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
+RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
@@ -238,6 +250,7 @@ MAN_LINKS = NO
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
+XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@@ -263,7 +276,9 @@ MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH = qtools \
- libmd5
+ libmd5 \
+ liblodepng \
+ libmscgen
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
@@ -280,7 +295,6 @@ EXTERNAL_PAGES = YES
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
-MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
@@ -307,6 +321,8 @@ DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
+PLANTUML_CFG_FILE =
+PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
diff --git a/addon/doxmlparser/src/basehandler.h b/addon/doxmlparser/src/basehandler.h
index 5715dda..a82114d 100644
--- a/addon/doxmlparser/src/basehandler.h
+++ b/addon/doxmlparser/src/basehandler.h
@@ -175,7 +175,7 @@ template<class T> class BaseHandler : public QXmlDefaultHandler,
!m_fallBackHandler->handleStartElement(name,attrib)
)
{
- debug(1,"line %d, col %d: found unexpected tag `%s', skipping until matching end tag\n",
+ debug(1,"line %d, col %d: found unexpected tag '%s', skipping until matching end tag\n",
s_theLocator->lineNumber(),s_theLocator->columnNumber(),
name.data());
m_skipUntil = name;
diff --git a/addon/doxmlparser/src/compoundhandler.cpp b/addon/doxmlparser/src/compoundhandler.cpp
index 3e729e9..077c8fb 100644
--- a/addon/doxmlparser/src/compoundhandler.cpp
+++ b/addon/doxmlparser/src/compoundhandler.cpp
@@ -22,6 +22,7 @@
#include "paramhandler.h"
#include "loamhandler.h"
#include "memberhandler.h"
+#include "linkedtexthandler.h"
//----------------------------------------------------------------------------
@@ -152,7 +153,7 @@ class CompoundTypeMap
int *val = m_map.find(s.utf8());
if (val==0)
{
- debug(1,"Warning: `%s' is an invalid compound type\n",s.data());
+ debug(1,"Warning: '%s' is an invalid compound type\n",s.data());
return ICompound::Invalid;
}
else return (ICompound::CompoundKind)*val;
@@ -325,7 +326,7 @@ void CompoundHandler::startCompound(const QXmlAttributes& attrib)
m_kindString = attrib.value("kind");
m_kind = s_typeMap->map(m_kindString);
m_protection = attrib.value("prot");
- debug(2,"startCompound(id=`%s' type=`%s')\n",m_id.data(),m_kindString.data());
+ debug(2,"startCompound(id='%s' type='%s')\n",m_id.data(),m_kindString.data());
}
void CompoundHandler::endCompound()
@@ -345,7 +346,7 @@ void CompoundHandler::startLocation(const QXmlAttributes& attrib)
void CompoundHandler::endCompoundName()
{
m_name = m_curString.stripWhiteSpace();
- debug(2,"Compound name `%s'\n",m_name.data());
+ debug(2,"Compound name '%s'\n",m_name.data());
}
void CompoundHandler::startInnerClass(const QXmlAttributes& attrib)
@@ -412,7 +413,7 @@ void CompoundHandler::startSuperClass(const QXmlAttributes& attrib)
prot,
kind
);
- debug(2,"super class id=`%s' prot=`%s' virt=`%s'\n",
+ debug(2,"super class id='%s' prot='%s' virt='%s'\n",
attrib.value("refid").data(),
protString.data(),
kindString.data());
@@ -442,7 +443,7 @@ void CompoundHandler::startSubClass(const QXmlAttributes& attrib)
prot,
kind
);
- debug(2,"sub class id=`%s' prot=`%s' virt=`%s'\n",
+ debug(2,"sub class id='%s' prot='%s' virt='%s'\n",
attrib.value("refid").data(),
protString.data(),
kindString.data());
diff --git a/addon/doxmlparser/src/dochandler.cpp b/addon/doxmlparser/src/dochandler.cpp
index 4e25813..ea1abf5 100644
--- a/addon/doxmlparser/src/dochandler.cpp
+++ b/addon/doxmlparser/src/dochandler.cpp
@@ -842,7 +842,7 @@ void RefHandler::endRef()
{
m_linkText = m_curString;
m_parent->setDelegate(0);
- debug(2,"End ref: text=`%s'\n",m_linkText.data());
+ debug(2,"End ref: text='%s'\n",m_linkText.data());
}
@@ -1098,7 +1098,7 @@ void HighlightHandler::startHighlight(const QXmlAttributes& attrib)
void HighlightHandler::endHighlight()
{
addTextNode();
- debug(2,"end highlight class=`%s'\n",m_hlString.data());
+ debug(2,"end highlight class='%s'\n",m_hlString.data());
m_parent->setDelegate(0);
}
@@ -1297,7 +1297,7 @@ void FormulaHandler::startFormula(const QXmlAttributes& attrib)
void FormulaHandler::endFormula()
{
m_text = m_curString;
- debug(2,"formula id=`%s' text=`%s'\n",m_id.data(),m_text.data());
+ debug(2,"formula id='%s' text='%s'\n",m_id.data(),m_text.data());
m_parent->setDelegate(0);
}
@@ -1323,7 +1323,7 @@ void AnchorHandler::startAnchor(const QXmlAttributes& attrib)
void AnchorHandler::endAnchor()
{
- debug(2,"anchor id=`%s'\n",m_id.data());
+ debug(2,"anchor id='%s'\n",m_id.data());
m_parent->setDelegate(0);
}
@@ -1351,7 +1351,7 @@ void ImageHandler::startImage(const QXmlAttributes& attrib)
void ImageHandler::endImage()
{
m_caption = m_curString;
- debug(2,"image name=`%s' caption=`%s'\n",m_name.data(),m_caption.data());
+ debug(2,"image name='%s' caption='%s'\n",m_name.data(),m_caption.data());
m_parent->setDelegate(0);
}
@@ -1379,7 +1379,7 @@ void DotFileHandler::startDotFile(const QXmlAttributes& attrib)
void DotFileHandler::endDotFile()
{
m_caption = m_curString;
- debug(2,"image name=`%s' caption=`%s'\n",m_name.data(),m_caption.data());
+ debug(2,"image name='%s' caption='%s'\n",m_name.data(),m_caption.data());
m_parent->setDelegate(0);
}
@@ -1409,7 +1409,7 @@ void IndexEntryHandler::startIndexEntry(const QXmlAttributes& /*attrib*/)
void IndexEntryHandler::endIndexEntry()
{
- debug(2,"index entry primary=`%s' secondary=`%s'\n",
+ debug(2,"index entry primary='%s' secondary='%s'\n",
m_primary.data(),m_secondary.data());
m_parent->setDelegate(0);
}
diff --git a/addon/doxmlparser/src/linkedtexthandler.cpp b/addon/doxmlparser/src/linkedtexthandler.cpp
index 1164688..b774f0f 100644
--- a/addon/doxmlparser/src/linkedtexthandler.cpp
+++ b/addon/doxmlparser/src/linkedtexthandler.cpp
@@ -81,7 +81,7 @@ void LinkedTextHandler::end()
if (!m_curString.isEmpty())
{
m_children.append(new LT_Text(m_curString));
- debug(2,"LinkedTextHandler: add text `%s'\n",m_curString.data());
+ debug(2,"LinkedTextHandler: add text '%s'\n",m_curString.data());
m_curString="";
}
m_parent->setDelegate(0);
@@ -92,7 +92,7 @@ void LinkedTextHandler::startRef(const QXmlAttributes& attrib)
if (!m_curString.isEmpty())
{
m_children.append(new LT_Text(m_curString));
- debug(2,"LinkedTextHandler: add text `%s'\n",m_curString.data());
+ debug(2,"LinkedTextHandler: add text '%s'\n",m_curString.data());
m_curString="";
}
ASSERT(m_ref==0);
@@ -107,7 +107,7 @@ void LinkedTextHandler::endRef()
{
m_ref->setText(m_curString);
m_children.append(m_ref);
- debug(2,"LinkedTextHandler: add ref `%s'\n",m_ref->text()->latin1());
+ debug(2,"LinkedTextHandler: add ref '%s'\n",m_ref->text()->latin1());
m_ref=0;
}
diff --git a/addon/doxmlparser/src/loamhandler.cpp b/addon/doxmlparser/src/loamhandler.cpp
index a939b7b..52aa576 100644
--- a/addon/doxmlparser/src/loamhandler.cpp
+++ b/addon/doxmlparser/src/loamhandler.cpp
@@ -1,5 +1,7 @@
#include "loamhandler.h"
#include "memberhandler.h"
+#include "linkedtexthandler.h"
+#include "paramhandler.h"
ListOfAllMembersHandler::ListOfAllMembersHandler(IBaseHandler *parent) : m_parent(parent)
diff --git a/addon/doxmlparser/src/mainhandler.cpp b/addon/doxmlparser/src/mainhandler.cpp
index 93525f0..a1ba216 100644
--- a/addon/doxmlparser/src/mainhandler.cpp
+++ b/addon/doxmlparser/src/mainhandler.cpp
@@ -20,6 +20,8 @@
#include "graphhandler.h"
#include "dochandler.h"
#include "memberhandler.h"
+#include "linkedtexthandler.h"
+#include "paramhandler.h"
#include "debug.h"
@@ -170,12 +172,12 @@ void MainHandler::dump()
CompoundEntry *ce;
for (cli.toFirst();(ce=cli.current());++cli)
{
- debug(2,"compound id=`%s' name=`%s'\n",ce->id.data(),ce->name.data());
+ debug(2,"compound id='%s' name='%s'\n",ce->id.data(),ce->name.data());
QDictIterator<MemberEntry> mdi(ce->memberDict);
MemberEntry *me;
for (mdi.toFirst();(me=mdi.current());++mdi)
{
- debug(2," member id=`%s' name=`%s'\n",me->id.data(),me->name.data());
+ debug(2," member id='%s' name='%s'\n",me->id.data(),me->name.data());
}
}
}
diff --git a/addon/doxmlparser/src/memberhandler.cpp b/addon/doxmlparser/src/memberhandler.cpp
index 7a3f228..6042f91 100644
--- a/addon/doxmlparser/src/memberhandler.cpp
+++ b/addon/doxmlparser/src/memberhandler.cpp
@@ -48,7 +48,7 @@ class MemberTypeMap
int *val = m_map.find(s.utf8());
if (val==0)
{
- debug(1,"Warning: `%s' is an invalid member type\n",s.data());
+ debug(1,"Warning: '%s' is an invalid member type\n",s.data());
return IMember::Invalid;
}
else return (IMember::MemberKind)*val;
@@ -240,7 +240,7 @@ void MemberHandler::startMember(const QXmlAttributes& attrib)
{
m_parent->setDelegate(this);
m_kindString = attrib.value("kind");
- //printf("startMember kindString=`%s'\n",m_kindString.data());
+ //printf("startMember kindString='%s'\n",m_kindString.data());
m_kind = s_typeMap->map(m_kindString);
m_id = attrib.value("id");
m_protection = attrib.value("prot");
@@ -254,7 +254,7 @@ void MemberHandler::startMember(const QXmlAttributes& attrib)
m_isReadable = attrib.value("readable")=="yes";
m_isWritable = attrib.value("writable")=="yes";
- debug(2,"member kind=`%s' id=`%s' prot=`%s' virt=`%s'\n",
+ debug(2,"member kind='%s' id='%s' prot='%s' virt='%s'\n",
m_kindString.data(),m_id.data(),m_protection.data(),m_virtualness.data());
}
@@ -262,7 +262,7 @@ void MemberHandler::startEnumValue(const QXmlAttributes& attrib)
{
m_parent->setDelegate(this);
m_kindString = "enumvalue";
- //printf("startEnumValue kindString=`%s'\n",m_kindString.data());
+ //printf("startEnumValue kindString='%s'\n",m_kindString.data());
m_kind = s_typeMap->map(m_kindString);
m_id = attrib.value("id");
m_protection = attrib.value("prot");
@@ -275,7 +275,7 @@ void MemberHandler::startEnumValue(const QXmlAttributes& attrib)
m_isMutable = FALSE;
m_isReadable = FALSE;
m_isWritable = FALSE;
- debug(2,"member kind=`%s' id=`%s' prot=`%s' virt=`%s'\n",
+ debug(2,"member kind='%s' id='%s' prot='%s' virt='%s'\n",
m_kindString.data(),m_id.data(),m_protection.data(),m_virtualness.data());
}
@@ -409,7 +409,7 @@ void MemberHandler::startName(const QXmlAttributes &)
void MemberHandler::endName()
{
m_name = m_curString.stripWhiteSpace();
- debug(2,"member name=`%s'\n",m_name.data());
+ debug(2,"member name='%s'\n",m_name.data());
}
void MemberHandler::startRead(const QXmlAttributes &)
@@ -420,7 +420,7 @@ void MemberHandler::startRead(const QXmlAttributes &)
void MemberHandler::endRead()
{
m_read = m_curString.stripWhiteSpace();
- debug(2,"member read=`%s'\n",m_read.data());
+ debug(2,"member read='%s'\n",m_read.data());
}
void MemberHandler::startWrite(const QXmlAttributes &)
@@ -431,7 +431,7 @@ void MemberHandler::startWrite(const QXmlAttributes &)
void MemberHandler::endWrite()
{
m_write = m_curString.stripWhiteSpace();
- debug(2,"member write=`%s'\n",m_write.data());
+ debug(2,"member write='%s'\n",m_write.data());
}
void MemberHandler::startDefinition(const QXmlAttributes&)
diff --git a/addon/doxmlparser/src/paramhandler.cpp b/addon/doxmlparser/src/paramhandler.cpp
index 831d5e4..7a6f455 100644
--- a/addon/doxmlparser/src/paramhandler.cpp
+++ b/addon/doxmlparser/src/paramhandler.cpp
@@ -103,25 +103,25 @@ void ParamHandler::startType(const QXmlAttributes& /*attrib*/)
void ParamHandler::endDeclName()
{
m_declName = m_curString.stripWhiteSpace();
- debug(2,"member declName=`%s'\n",m_declName.data());
+ debug(2,"member declName='%s'\n",m_declName.data());
}
void ParamHandler::endDefName()
{
m_defName = m_curString.stripWhiteSpace();
- debug(2,"member defName=`%s'\n",m_defName.data());
+ debug(2,"member defName='%s'\n",m_defName.data());
}
void ParamHandler::endAttrib()
{
m_attrib = m_curString.stripWhiteSpace();
- debug(2,"member attrib=`%s'\n",m_attrib.data());
+ debug(2,"member attrib='%s'\n",m_attrib.data());
}
void ParamHandler::endArray()
{
m_array = m_curString.stripWhiteSpace();
- debug(2,"member array=`%s'\n",m_array.data());
+ debug(2,"member array='%s'\n",m_array.data());
}
void ParamHandler::startDefVal(const QXmlAttributes& /*attrib*/)
diff --git a/addon/doxmlparser/src/sectionhandler.cpp b/addon/doxmlparser/src/sectionhandler.cpp
index 1137901..b6cc31e 100644
--- a/addon/doxmlparser/src/sectionhandler.cpp
+++ b/addon/doxmlparser/src/sectionhandler.cpp
@@ -17,6 +17,8 @@
#include "compoundhandler.h"
#include "sectionhandler.h"
#include "memberhandler.h"
+#include "linkedtexthandler.h"
+#include "paramhandler.h"
#include "dochandler.h"
#include "debug.h"
@@ -68,7 +70,7 @@ class SectionTypeMap
int *val = m_map.find(s.utf8());
if (val==0)
{
- debug(1,"Warning: `%s' is an invalid section type\n",s.data());
+ debug(1,"Warning: '%s' is an invalid section type\n",s.data());
return ISection::Invalid;
}
else return (ISection::SectionKind)*val;
@@ -110,7 +112,7 @@ void SectionHandler::startSection(const QXmlAttributes& attrib)
m_parent->setDelegate(this);
m_kindString = attrib.value("kind");
m_kind = s_typeMap->map(m_kindString);
- debug(2,"section kind=`%s'\n",m_kindString.data());
+ debug(2,"section kind='%s'\n",m_kindString.data());
}
void SectionHandler::startDescription(const QXmlAttributes& attrib)
@@ -141,7 +143,7 @@ void SectionHandler::startHeader(const QXmlAttributes&)
void SectionHandler::endHeader()
{
m_header = m_curString.stripWhiteSpace();
- debug(2,"member header=`%s'\n",m_header.data());
+ debug(2,"member header='%s'\n",m_header.data());
}
void SectionHandler::initialize(CompoundHandler *ch)
diff --git a/addon/doxmlparser/test/main.cpp b/addon/doxmlparser/test/main.cpp
index 5f37c81..70c79da 100644
--- a/addon/doxmlparser/test/main.cpp
+++ b/addon/doxmlparser/test/main.cpp
@@ -51,7 +51,7 @@ void DumpDoc(IDoc *doc,int level)
if (doc==0) return;
QString indent;
indent.fill(' ',level);
- //printf(" doc node kind=`%d'\n",doc->kind());
+ //printf(" doc node kind='%d'\n",doc->kind());
switch (doc->kind())
{
case IDoc::Para:
@@ -73,7 +73,7 @@ void DumpDoc(IDoc *doc,int level)
{
IDocText *txt = dynamic_cast<IDocText*>(doc);
ASSERT(txt!=0);
- InPrint(("<text value=`%s' markup=%d headingLevel=%d/>\n",
+ InPrint(("<text value='%s' markup=%d headingLevel=%d/>\n",
txt->text()->latin1(),txt->markup(),txt->headingLevel()));
}
break;
@@ -244,21 +244,21 @@ void DumpDoc(IDoc *doc,int level)
{
IDocULink *ul = dynamic_cast<IDocULink*>(doc);
ASSERT(ul!=0);
- InPrint(("<ulink url=`%s' text=`%s'/>\n",ul->url()->latin1(),ul->text()->latin1()));
+ InPrint(("<ulink url='%s' text='%s'/>\n",ul->url()->latin1(),ul->text()->latin1()));
}
break;
case IDoc::EMail:
{
IDocEMail *em = dynamic_cast<IDocEMail*>(doc);
ASSERT(em!=0);
- InPrint(("<email address=`%s'/>\n",em->address()->latin1()));
+ InPrint(("<email address='%s'/>\n",em->address()->latin1()));
}
break;
case IDoc::Link:
{
IDocLink *lk = dynamic_cast<IDocLink*>(doc);
ASSERT(lk!=0);
- InPrint(("<link refid=`%s' text=`%s'/>\n",lk->refId()->latin1(),lk->text()->latin1()));
+ InPrint(("<link refid='%s' text='%s'/>\n",lk->refId()->latin1(),lk->text()->latin1()));
}
break;
case IDoc::ProgramListing:
@@ -280,7 +280,7 @@ void DumpDoc(IDoc *doc,int level)
{
IDocCodeLine *cl = dynamic_cast<IDocCodeLine*>(doc);
ASSERT(cl!=0);
- InPrint(("<codeline lineNumber=%d refId=`%s'>\n",cl->lineNumber(),cl->refId()->latin1()));
+ InPrint(("<codeline lineNumber=%d refId='%s'>\n",cl->lineNumber(),cl->refId()->latin1()));
IDocIterator *cei = cl->codeElements();
IDoc *ce;
for (cei->toFirst();(ce=cei->current());cei->toNext())
@@ -310,35 +310,35 @@ void DumpDoc(IDoc *doc,int level)
{
IDocFormula *fm = dynamic_cast<IDocFormula*>(doc);
ASSERT(fm!=0);
- InPrint(("<formula id=`%s' text=`%s'/>\n",fm->id()->latin1(),fm->text()->latin1()));
+ InPrint(("<formula id='%s' text='%s'/>\n",fm->id()->latin1(),fm->text()->latin1()));
}
break;
case IDoc::Image:
{
IDocImage *img = dynamic_cast<IDocImage*>(doc);
ASSERT(img!=0);
- InPrint(("<image name=`%s' caption=`%s'/>\n",img->name()->latin1(),img->caption()->latin1()));
+ InPrint(("<image name='%s' caption='%s'/>\n",img->name()->latin1(),img->caption()->latin1()));
}
break;
case IDoc::DotFile:
{
IDocDotFile *df = dynamic_cast<IDocDotFile*>(doc);
ASSERT(df!=0);
- InPrint(("<dotfile name=`%s' caption=`%s'/>\n",df->name()->latin1(),df->caption()->latin1()));
+ InPrint(("<dotfile name='%s' caption='%s'/>\n",df->name()->latin1(),df->caption()->latin1()));
}
break;
case IDoc::IndexEntry:
{
IDocIndexEntry *ie = dynamic_cast<IDocIndexEntry*>(doc);
ASSERT(ie!=0);
- InPrint(("<indexentry primary=`%s' secondary=`%s'/>\n",ie->primary()->latin1(),ie->secondary()->latin1()));
+ InPrint(("<indexentry primary='%s' secondary='%s'/>\n",ie->primary()->latin1(),ie->secondary()->latin1()));
}
break;
case IDoc::Table:
{
IDocTable *tbl = dynamic_cast<IDocTable*>(doc);
ASSERT(tbl!=0);
- InPrint(("<table numcols=%d caption=`%s'>\n",tbl->numColumns(),tbl->caption()->latin1()));
+ InPrint(("<table numcols=%d caption='%s'>\n",tbl->numColumns(),tbl->caption()->latin1()));
IDocIterator *ri = tbl->rows();
IDoc *row;
for (ri->toFirst();(row=ri->current());ri->toNext())
@@ -383,7 +383,7 @@ void DumpDoc(IDoc *doc,int level)
{
IDocSection *sec = dynamic_cast<IDocSection*>(doc);
ASSERT(sec!=0);
- InPrint(("<section id=`%s' level=%d>\n",
+ InPrint(("<section id='%s' level=%d>\n",
sec->id()->latin1(),sec->level()));
DumpDoc(sec->title(),level+1);
IDocIterator *di = sec->paragraphs();
@@ -653,7 +653,7 @@ int main(int argc,char **argv)
ILinkedTextIterator *lti = ev->initializer();
QString init = linkedTextToString(lti);
lti->release();
- printf(" Enum value `%s' init=`%s'\n",
+ printf(" Enum value '%s' init='%s'\n",
ev->name()->latin1(),init.latin1());
}
evi->release();
diff --git a/addon/doxyapp/CMakeLists.txt b/addon/doxyapp/CMakeLists.txt
index 0aaf465..f205664 100644
--- a/addon/doxyapp/CMakeLists.txt
+++ b/addon/doxyapp/CMakeLists.txt
@@ -2,6 +2,7 @@ find_package(Iconv)
include_directories(
${CMAKE_SOURCE_DIR}/src
+ ${CMAKE_SOURCE_DIR}/libversion
${GENERATED_SRC}
${CMAKE_SOURCE_DIR}/qtools
${ICONV_INCLUDE_DIR}
@@ -20,6 +21,9 @@ target_link_libraries(doxyapp
_doxygen
qtools
md5
+lodepng
+mscgen
+version
doxycfg
vhdlparser
${ICONV_LIBRARIES}
diff --git a/addon/doxyapp/doxyapp.cpp b/addon/doxyapp/doxyapp.cpp
index dd092ed..c18f907 100644
--- a/addon/doxyapp/doxyapp.cpp
+++ b/addon/doxyapp/doxyapp.cpp
@@ -261,6 +261,8 @@ int main(int argc,char **argv)
// setup the non-default configuration options
+ checkConfiguration();
+ adjustConfiguration();
// we need a place to put intermediate files
Config_getString(OUTPUT_DIRECTORY)="/tmp/doxygen";
// disable html output
@@ -281,14 +283,13 @@ int main(int argc,char **argv)
// Extract source browse information, needed
// to make doxygen gather the cross reference info
Config_getBool(SOURCE_BROWSER)=TRUE;
+ // In case of a directory take all files on directory and its subdirectories
+ Config_getBool(RECURSIVE)=TRUE;
// set the input
+ Config_getList(INPUT).clear();
Config_getList(INPUT).append(argv[1]);
- // check and finialize the configuration
- checkConfiguration();
- adjustConfiguration();
-
// parse the files
parseInput();
diff --git a/addon/doxyparse/CMakeLists.txt b/addon/doxyparse/CMakeLists.txt
index 1620c72..e76f031 100644
--- a/addon/doxyparse/CMakeLists.txt
+++ b/addon/doxyparse/CMakeLists.txt
@@ -2,6 +2,7 @@ find_package(Iconv)
include_directories(
${CMAKE_SOURCE_DIR}/src
+ ${CMAKE_SOURCE_DIR}/libversion
${GENERATED_SRC}
${CMAKE_SOURCE_DIR}/qtools
${ICONV_INCLUDE_DIR}
@@ -20,6 +21,9 @@ target_link_libraries(doxyparse
_doxygen
qtools
md5
+lodepng
+mscgen
+version
doxycfg
vhdlparser
${ICONV_LIBRARIES}
diff --git a/addon/doxyparse/README b/addon/doxyparse/README
index 288b31e..95cce8c 100644
--- a/addon/doxyparse/README
+++ b/addon/doxyparse/README
@@ -18,8 +18,20 @@ More info and source code repository: https://github.com/analizo/doxygen
sudo make install
+## release
+
+* ensure analizo testsuite passing on newer doxyparse version
+* update debian/changelog, commit, push
+* create git tag, push to github analizo/doxyparse
+* build on amd64 and i386 archs, upload tar.gz to github
+ * tar -zcf doxyparse_<VERSION>_amd64.tar.gz -C bin/ doxyparse
+ * tar -zcf doxyparse_<VERSION>_i386.tar.gz -C bin/ doxyparse
+* build debian packages for amd64 and i386, update analizo.org repository
+ * (see analizo.github.io/README.md file for updating repository instructions)
+ * upload the deb files to github release tag also
+* check if a alien-doxyparse release is necessary and do it on cpan
+
AUTHORS
-=======
Antonio Terceiro <terceiro@softwarelivre.org>
João M. Miranda <joaomm88@gmail.com>
diff --git a/addon/doxyparse/doxyparse.cpp b/addon/doxyparse/doxyparse.cpp
index 26ecea9..2f6e32d 100644
--- a/addon/doxyparse/doxyparse.cpp
+++ b/addon/doxyparse/doxyparse.cpp
@@ -24,6 +24,7 @@
#else
#include <windows.h>
#endif
+#include "version.h"
#include "doxygen.h"
#include "outputgen.h"
#include "parserintf.h"
@@ -40,6 +41,9 @@
#include <sstream>
#include <map>
#include <qdir.h>
+#include <qcstring.h>
+#include <qregexp.h>
+#include "namespacedef.h"
class Doxyparse : public CodeOutputInterface
{
@@ -81,8 +85,6 @@ class Doxyparse : public CodeOutputInterface
};
static bool is_c_code = true;
-static std::map<std::string, bool> modules;
-static std::string current_module;
static void findXRefSymbols(FileDef *fd)
{
@@ -107,7 +109,7 @@ static void findXRefSymbols(FileDef *fd)
static bool ignoreStaticExternalCall(MemberDef *context, MemberDef *md) {
if (md->isStatic()) {
- if(md->getFileDef()) {
+ if(md->getFileDef() && context->getFileDef()) {
if(md->getFileDef()->getOutputFileBase() == context->getFileDef()->getOutputFileBase())
// TODO ignore prefix of file
return false;
@@ -123,27 +125,29 @@ static bool ignoreStaticExternalCall(MemberDef *context, MemberDef *md) {
}
}
+static void startYamlDocument() {
+ printf("---\n");
+}
static void printFile(std::string file) {
printf("%s:\n", file.c_str());
}
static void printModule(std::string module) {
- current_module = module;
- printf(" %s:\n", module.c_str());
+ printf(" \"%s\":\n", unescapeCharsInString(module.c_str()).data());
}
static void printClassInformation(std::string information) {
printf(" information: %s\n", information.c_str());
}
+static void printInherits() {
+ printf(" inherits:\n");
+}
static void printInheritance(std::string base_class) {
- printf(" inherits: %s\n", base_class.c_str());
+ printf(" - %s\n", base_class.c_str());
}
static void printDefines() {
- if (! modules[current_module]) {
- printf(" defines:\n");
- }
- modules[current_module] = true;
+ printf(" defines:\n");
}
static void printDefinition(std::string type, std::string signature, int line) {
- printf(" - \"%s\":\n", signature.c_str());
+ printf(" - \"%s\":\n", signature.substr(0, 1022).c_str());
printf(" type: %s\n", type.c_str());
printf(" line: %d\n", line);
}
@@ -160,44 +164,47 @@ static void printUses() {
printf(" uses:\n");
}
static void printReferenceTo(std::string type, std::string signature, std::string defined_in) {
- printf(" - \"%s\":\n", signature.c_str());
+ printf(" - \"%s\":\n", signature.substr(0, 1022).c_str());
printf(" type: %s\n", type.c_str());
- printf(" defined_in: %s\n", defined_in.c_str());
+ printf(" defined_in: \"%s\"\n", unescapeCharsInString(defined_in.c_str()).data());
+}
+static void printNumberOfConditionalPaths(MemberDef* md) {
+ printf(" conditional_paths: %d\n", md->numberOfFlowKeyWords());
}
static int isPartOfCStruct(MemberDef * md) {
return is_c_code && md->getClassDef() != NULL;
}
-std::string removeDoubleQuotes(std::string data) {
- // remove surrounding double quotes
- if (data.front() == '"' && data.back() == '"') {
- data.erase(0, 1); // first double quote
- data.erase(data.size() - 1); // last double quote
- }
- return data;
+std::string sanitizeString(std::string data) {
+ QCString new_data = QCString(data.c_str());
+ new_data.replace(QRegExp("\""), "");
+ new_data.replace(QRegExp("\\"), ""); // https://github.com/analizo/analizo/issues/138
+ return !new_data.isEmpty() ? new_data.data() : "";
}
std::string argumentData(Argument *argument) {
std::string data = "";
- if (argument->type != NULL)
- data = removeDoubleQuotes(argument->type.data());
+ if (argument->type != NULL && argument->type.size() > 1)
+ data = sanitizeString(argument->type.data());
else if (argument->name != NULL)
- data = removeDoubleQuotes(argument->name.data());
+ data = sanitizeString(argument->name.data());
return data;
}
std::string functionSignature(MemberDef* md) {
- std::string signature = md->name().data();
+ std::string signature = sanitizeString(md->name().data());
if(md->isFunction()){
ArgumentList *argList = md->argumentList();
- ArgumentListIterator iterator(*argList);
signature += "(";
- Argument * argument = iterator.toFirst();
- if(argument != NULL) {
- signature += argumentData(argument);
- for(++iterator; (argument = iterator.current()); ++iterator){
- signature += std::string(",") + argumentData(argument);
+ if (argList) {
+ ArgumentListIterator iterator(*argList);
+ Argument * argument = iterator.toFirst();
+ if(argument != NULL) {
+ signature += argumentData(argument);
+ for(++iterator; (argument = iterator.current()); ++iterator) {
+ signature += std::string(",") + argumentData(argument);
+ }
}
}
signature += ")";
@@ -221,6 +228,9 @@ static void referenceTo(MemberDef* md) {
else if (md->getFileDef()) {
defined_in = md->getFileDef()->getOutputFileBase().data();
}
+ else if (md->getNamespaceDef()) {
+ defined_in = md->getNamespaceDef()->name().data();
+ }
}
printReferenceTo(type, signature, defined_in);
}
@@ -228,6 +238,12 @@ static void referenceTo(MemberDef* md) {
void cModule(ClassDef* cd) {
MemberList* ml = cd->getMemberList(MemberListType_variableMembers);
if (ml) {
+ FileDef *fd = cd->getFileDef();
+ MemberList *fd_ml = fd->getMemberList(MemberListType_allMembersList);
+ if (!fd_ml || fd_ml->count() == 0) {
+ printModule(fd->getOutputFileBase().data());
+ printDefines();
+ }
MemberListIterator mli(*ml);
MemberDef* md;
for (mli.toFirst(); (md=mli.current()); ++mli) {
@@ -239,18 +255,50 @@ void cModule(ClassDef* cd) {
}
}
+static bool checkOverrideArg(ArgumentList *argList, MemberDef *md) {
+ ArgumentListIterator iterator(*argList);
+ Argument * argument = iterator.toFirst();
+
+ if(!md->isFunction() || argList->count() == 0){
+ return false;
+ }
+
+ if(argument != NULL) {
+ for(; (argument = iterator.current()); ++iterator){
+ if(md->name() == argument->name) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
void functionInformation(MemberDef* md) {
+ std::string temp = "";
int size = md->getEndBodyLine() - md->getStartBodyLine() + 1;
printNumberOfLines(size);
ArgumentList *argList = md->argumentList();
- printNumberOfArguments(argList->count());
+ if (argList) {
+ ArgumentListIterator iterator(*argList);
+ Argument * argument = iterator.toFirst();
+ if(argument != NULL) {
+ temp = argumentData(argument);
+// TODO: This is a workaround; better not include "void" in argList, in the first place.
+ if(temp != "void") {
+ printNumberOfArguments(argList->count());
+ }
+ }
+ }
+
+ printNumberOfConditionalPaths(md);
MemberSDict *defDict = md->getReferencesMembers();
if (defDict) {
MemberSDict::Iterator msdi(*defDict);
MemberDef *rmd;
printUses();
for (msdi.toFirst(); (rmd=msdi.current()); ++msdi) {
- if (rmd->definitionType() == Definition::TypeMember && !ignoreStaticExternalCall(md, rmd)) {
+ if (rmd->definitionType() == Definition::TypeMember && !ignoreStaticExternalCall(md, rmd) && !checkOverrideArg(argList, rmd)) {
referenceTo(rmd);
}
}
@@ -276,7 +324,6 @@ void listMembers(MemberList *ml) {
if (ml) {
MemberListIterator mli(*ml);
MemberDef *md;
- printDefines();
for (mli.toFirst(); (md=mli.current()); ++mli) {
lookupSymbol((Definition*) md);
}
@@ -299,6 +346,7 @@ static void classInformation(ClassDef* cd) {
printModule(cd->name().data());
BaseClassList* baseClasses = cd->baseClasses();
if (baseClasses) {
+ printInherits();
BaseClassListIterator bci(*baseClasses);
BaseClassDef* bcd;
for (bci.toFirst(); (bcd = bci.current()); ++bci) {
@@ -308,6 +356,7 @@ static void classInformation(ClassDef* cd) {
if(cd->isAbstract()) {
printClassInformation("abstract class");
}
+ printDefines();
listAllMembers(cd);
}
}
@@ -356,6 +405,7 @@ static void listSymbols() {
MemberList *ml = fd->getMemberList(MemberListType_allMembersList);
if (ml && ml->count() > 0) {
printModule(fd->getOutputFileBase().data());
+ printDefines();
listMembers(ml);
}
@@ -364,7 +414,10 @@ static void listSymbols() {
ClassSDict::Iterator cli(*classes);
ClassDef *cd;
for (cli.toFirst(); (cd = cli.current()); ++cli) {
- classInformation(cd);
+ if (!cd->isVisited()) {
+ classInformation(cd);
+ cd->setVisited(TRUE);
+ }
}
}
}
@@ -377,6 +430,11 @@ int main(int argc,char **argv) {
printf("Usage: %s [source_file | source_dir]\n",argv[0]);
exit(1);
}
+ if (qstrcmp(&argv[1][2], "version") == 0) {
+ QCString versionString = getVersion();
+ printf("%s\n", versionString.data());
+ exit(0);
+ }
// initialize data structures
initDoxygen();
@@ -411,6 +469,7 @@ int main(int argc,char **argv) {
Config_getBool(EXTRACT_STATIC)=TRUE;
Config_getBool(EXTRACT_PRIVATE)=TRUE;
Config_getBool(EXTRACT_LOCAL_METHODS)=TRUE;
+ Config_getBool(EXTRACT_PACKAGE)=TRUE;
// Extract source browse information, needed
// to make doxygen gather the cross reference info
Config_getBool(SOURCE_BROWSER)=TRUE;
@@ -464,6 +523,7 @@ int main(int argc,char **argv) {
// clean up after us
thisDir.rmdir(Config_getString(OUTPUT_DIRECTORY));
+ startYamlDocument();
listSymbols();
std::string cleanup_command = "rm -rf ";
diff --git a/addon/doxysearch/doxysearch.cpp b/addon/doxysearch/doxysearch.cpp
index 1c4effd..98adab4 100644
--- a/addon/doxysearch/doxysearch.cpp
+++ b/addon/doxysearch/doxysearch.cpp
@@ -367,12 +367,24 @@ int main(int argc,char **argv)
// create query
Xapian::Database db(indexDir);
Xapian::Enquire enquire(db);
- Xapian::Query query;
+
std::vector<std::string> words = split(searchFor,' ');
- for (std::vector<std::string>::const_iterator it=words.begin();it!=words.end();++it)
- {
- query = Xapian::Query(Xapian::Query::OP_OR,query,Xapian::Query(*it));
- }
+ Xapian::QueryParser parser;
+ parser.set_database(db);
+ parser.set_default_op(Xapian::Query::OP_AND);
+ parser.set_stemming_strategy(Xapian::QueryParser::STEM_ALL);
+ Xapian::termcount max_expansion=100;
+#if (XAPIAN_MAJOR_VERSION==1) && (XAPIAN_MINOR_VERSION==2)
+ parser.set_max_wildcard_expansion(max_expansion);
+#else
+ parser.set_max_expansion(max_expansion,Xapian::Query::WILDCARD_LIMIT_MOST_FREQUENT);
+#endif
+ Xapian::Query query=parser.parse_query(searchFor,
+ Xapian::QueryParser::FLAG_DEFAULT |
+ Xapian::QueryParser::FLAG_WILDCARD |
+ Xapian::QueryParser::FLAG_PHRASE |
+ Xapian::QueryParser::FLAG_PARTIAL
+ );
enquire.set_query(query);
// get results
diff --git a/addon/doxywizard/CMakeLists.txt b/addon/doxywizard/CMakeLists.txt
index a89864d..9aba4e4 100644
--- a/addon/doxywizard/CMakeLists.txt
+++ b/addon/doxywizard/CMakeLists.txt
@@ -30,6 +30,7 @@ endif()
include_directories(
.
+ ${CMAKE_SOURCE_DIR}/libversion
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/qtools
${GENERATED_SRC}
@@ -57,8 +58,10 @@ CONTENT "#ifndef SETTINGS_H
set_source_files_properties(${GENERATED_SRC_WIZARD}/settings.h PROPERTIES GENERATED 1)
# generate version.cpp
-file(GENERATE OUTPUT ${GENERATED_SRC_WIZARD}/version.cpp
- CONTENT "char versionString[]=\"${VERSION}\";"
+add_custom_command(
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/version.py ${VERSION} > ${GENERATED_SRC_WIZARD}/version.cpp
+ DEPENDS ${CMAKE_SOURCE_DIR}/VERSION ${CMAKE_SOURCE_DIR}/src/version.py
+ OUTPUT ${GENERATED_SRC_WIZARD}/version.cpp
)
set_source_files_properties(${GENERATED_SRC_WIZARD}/version.cpp PROPERTIES GENERATED 1)
@@ -93,7 +96,6 @@ inputstring.cpp
inputint.cpp
inputstrlist.cpp
${GENERATED_SRC_WIZARD}/settings.h
-${GENERATED_SRC_WIZARD}/version.cpp
${GENERATED_SRC_WIZARD}/config_doxyw.cpp
${GENERATED_SRC_WIZARD}/configdoc.cpp
${doxywizard_MOC}
@@ -102,9 +104,9 @@ doxywizard.rc
)
if(Qt5Core_FOUND)
- target_link_libraries(doxywizard Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Xml)
+ target_link_libraries(doxywizard Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Xml version)
else()
- target_link_libraries(doxywizard ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY})
+ target_link_libraries(doxywizard ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY} version)
endif()
install(TARGETS doxywizard DESTINATION bin)
diff --git a/addon/doxywizard/config_doxyw.l b/addon/doxywizard/config_doxyw.l
index 960b7cb..8549e6b 100644
--- a/addon/doxywizard/config_doxyw.l
+++ b/addon/doxywizard/config_doxyw.l
@@ -230,7 +230,7 @@ static void readIncludeFile(const QString &incName)
g_curOption = g_options->value(cmd);
if (g_curOption==0) // oops not known
{
- config_warn("ignoring unsupported tag `%s' at line %d, file %s\n",
+ config_warn("ignoring unsupported tag '%s' at line %d, file %s\n",
qPrintable(cmd),yylineno,qPrintable(g_yyFileName));
BEGIN(SkipInvalid);
}
@@ -255,7 +255,7 @@ static void readIncludeFile(const QString &incName)
BEGIN(GetString);
break;
case Input::Obsolete:
- config_warn("Tag `%s' at line %d of file %s has become obsolete.\n"
+ config_warn("Tag '%s' at line %d of file %s has become obsolete.\n"
"To avoid this warning please update your configuration "
"file using \"doxygen -u\"\n", qPrintable(cmd),
yylineno,qPrintable(g_yyFileName));
@@ -269,7 +269,7 @@ static void readIncludeFile(const QString &incName)
g_curOption = g_options->value(cmd);
if (g_curOption==0) // oops not known
{
- config_warn("ignoring unsupported tag `%s' at line %d, file %s\n",
+ config_warn("ignoring unsupported tag '%s' at line %d, file %s\n",
yytext,yylineno,qPrintable(g_yyFileName));
BEGIN(SkipInvalid);
}
@@ -285,12 +285,12 @@ static void readIncludeFile(const QString &incName)
case Input::String:
case Input::Int:
case Input::Bool:
- config_warn("operator += not supported for `%s'. Ignoring line at line %d, file %s\n",
+ config_warn("operator += not supported for '%s'. Ignoring line at line %d, file %s\n",
yytext,yylineno,qPrintable(g_yyFileName));
BEGIN(SkipInvalid);
break;
case Input::Obsolete:
- config_warn("Tag `%s' at line %d of file %s has become obsolete.\n"
+ config_warn("Tag '%s' at line %d of file %s has become obsolete.\n"
"To avoid this warning please update your configuration "
"file using \"doxygen -u\"\n",
qPrintable(cmd),yylineno,qPrintable(g_yyFileName));
@@ -327,12 +327,12 @@ static void readIncludeFile(const QString &incName)
}
}
-<Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag `%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); }
+<Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag '%s' at line %d, file %s\n",yytext,yylineno,qPrintable(g_yyFileName)); }
<GetString,SkipInvalid>\n { BEGIN(Start); }
<GetStrList>\n {
if (!g_elemStr.isEmpty())
{
- //printf("elemStr1=`%s'\n",qPrintable(elemStr));
+ //printf("elemStr1='%s'\n",qPrintable(elemStr));
*g_arg = QVariant(g_arg->toStringList() << g_elemStr);
}
BEGIN(Start);
@@ -340,7 +340,7 @@ static void readIncludeFile(const QString &incName)
<GetStrList>[ \t]+ {
if (!g_elemStr.isEmpty())
{
- //printf("elemStr2=`%s'\n",qPrintable(elemStr));
+ //printf("elemStr2='%s'\n",qPrintable(elemStr));
*g_arg = QVariant(g_arg->toStringList() << g_elemStr);
}
g_elemStr = QString();
@@ -356,7 +356,7 @@ static void readIncludeFile(const QString &incName)
<GetQuotedString>"\""|"\n" {
// we add a bogus space to signal that the string was quoted. This space will be stripped later on.
g_tmpString+=" ";
- //printf("Quoted String = `%s'\n",qPrintable(tmpString));
+ //printf("Quoted String = '%s'\n",qPrintable(tmpString));
if (g_lastState==GetString)
{
*g_arg = g_codec->toUnicode(g_tmpString);
@@ -401,7 +401,7 @@ static void substEnvVarsInString(QString &s)
while ((i=re.indexIn(s,p))!=-1)
{
l = re.matchedLength();
- //printf("Found environment var s.mid(%d,%d)=`%s'\n",i+2,l-3,qPrintable(s.mid(i+2,l-3)));
+ //printf("Found environment var s.mid(%d,%d)='%s'\n",i+2,l-3,qPrintable(s.mid(i+2,l-3)));
QString env=g_codec->toUnicode(getenv(s.mid(i+2,l-3).toLatin1()));
substEnvVarsInString(env); // recursively expand variables if needed.
s = s.left(i)+env+s.right(s.length()-i-l);
diff --git a/addon/doxywizard/doxywizard.cpp b/addon/doxywizard/doxywizard.cpp
index 56378ed..02e8cd0 100755
--- a/addon/doxywizard/doxywizard.cpp
+++ b/addon/doxywizard/doxywizard.cpp
@@ -216,7 +216,7 @@ void MainWindow::about()
QString msg;
QTextStream t(&msg,QIODevice::WriteOnly);
t << QString::fromLatin1("<qt><center>A tool to configure and run doxygen version ")+
- QString::fromLatin1(versionString)+
+ QString::fromLatin1(getVersion())+
QString::fromLatin1(" on your source files.</center><p><br>"
"<center>Written by<br> Dimitri van Heesch<br>&copy; 2000-2015</center><p>"
"</qt>");
diff --git a/addon/doxywizard/expert.cpp b/addon/doxywizard/expert.cpp
index 44dea78..c875d8d 100644
--- a/addon/doxywizard/expert.cpp
+++ b/addon/doxywizard/expert.cpp
@@ -781,7 +781,7 @@ void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec,
bool Expert::writeConfig(QTextStream &t,bool brief)
{
// write global header
- t << "# Doxyfile " << versionString << endl << endl;
+ t << "# Doxyfile " << getVersion() << endl << endl;
if (!brief)
{
t << convertToComment(m_header);
diff --git a/cmake/doxygen_version.cmake b/cmake/doxygen_version.cmake
new file mode 100644
index 0000000..2433889
--- /dev/null
+++ b/cmake/doxygen_version.cmake
@@ -0,0 +1,96 @@
+# doxygen_version.cmake
+#
+
+# This file defines the functions and targets needed to monitor
+# doxygen VERSION file.
+#
+# The behavior of this script can be modified by defining any of these variables:
+#
+# PRE_CONFIGURE_DOXYGEN_VERSION_FILE (REQUIRED)
+# -- The path to the file that'll be configured.
+#
+# POST_CONFIGURE_DOXYGEN_VERSION_FILE (REQUIRED)
+# -- The path to the configured PRE_CONFIGURE_DOXYGEN_VERSION_FILE.
+#
+# DOXY_STATE_FILE (OPTIONAL)
+# -- The path to the file used to store the doxygen version information.
+#
+# This file is based on git_watcher.cmake
+
+# Short hand for converting paths to absolute.
+macro(PATH_TO_ABSOLUTE var_name)
+ get_filename_component(${var_name} "${${var_name}}" ABSOLUTE)
+endmacro()
+
+# Check that a required variable is set.
+macro(CHECK_REQUIRED_VARIABLE var_name)
+ if(NOT DEFINED ${var_name})
+ message(FATAL_ERROR "The \"${var_name}\" variable must be defined.")
+ endif()
+ PATH_TO_ABSOLUTE(${var_name})
+endmacro()
+
+# Check that an optional variable is set, or, set it to a default value.
+macro(CHECK_OPTIONAL_VARIABLE var_name default_value)
+ if(NOT DEFINED ${var_name})
+ set(${var_name} ${default_value})
+ endif()
+ PATH_TO_ABSOLUTE(${var_name})
+endmacro()
+
+CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_DOXYGEN_VERSION_FILE)
+CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_DOXYGEN_VERSION_FILE)
+CHECK_OPTIONAL_VARIABLE(DOXY_STATE_FILE "${CMAKE_SOURCE_DIR}/VERSION")
+
+# Function: DoxygenStateChangedAction
+# Description: this function is executed when the
+# doxygen version file has changed.
+function(DoxygenStateChangedAction _state_as_list)
+ # Set variables by index, then configure the file w/ these variables defined.
+ LIST(GET _state_as_list 0 DOXYGEN_VERSION)
+ configure_file("${PRE_CONFIGURE_DOXYGEN_VERSION_FILE}" "${POST_CONFIGURE_DOXYGEN_VERSION_FILE}" @ONLY)
+endfunction()
+
+
+
+# Function: SetupDoxyMonitoring
+# Description: this function sets up custom commands that make the build system
+# check the doxygen version file before every build. If it has
+# changed, then a file is configured.
+function(SetupDoxyMonitoring)
+ add_custom_target(check_doxygen_version
+ ALL
+ DEPENDS ${PRE_CONFIGURE_DOXYGEN_VERSION_FILE}
+ BYPRODUCTS ${POST_CONFIGURE_DOXYGEN_VERSION_FILE}
+ COMMENT "Checking the doxygen version for changes..."
+ COMMAND
+ ${CMAKE_COMMAND}
+ -D_BUILD_TIME_CHECK_DOXY=TRUE
+ -DDOXY_STATE_FILE=${DOXY_STATE_FILE}
+ -DPRE_CONFIGURE_DOXYGEN_VERSION_FILE=${PRE_CONFIGURE_DOXYGEN_VERSION_FILE}
+ -DPOST_CONFIGURE_DOXYGEN_VERSION_FILE=${POST_CONFIGURE_DOXYGEN_VERSION_FILE}
+ -P "${CMAKE_CURRENT_LIST_FILE}")
+endfunction()
+
+
+
+# Function: Main
+# Description: primary entry-point to the script. Functions are selected based
+# on whether it's configure or build time.
+function(Main)
+ file(STRINGS "${DOXY_STATE_FILE}" DOXYGEN_VERSION)
+ if(_BUILD_TIME_CHECK_DOXY)
+ # Check if the doxygen version file has changed.
+ # If so, run the change action.
+ if(${DOXY_STATE_FILE} IS_NEWER_THAN ${POST_CONFIGURE_DOXYGEN_VERSION_FILE})
+ DoxygenStateChangedAction("${DOXYGEN_VERSION}")
+ endif()
+ else()
+ # >> Executes at configure time.
+ SetupDoxyMonitoring()
+ DoxygenStateChangedAction("${DOXYGEN_VERSION}")
+ endif()
+endfunction()
+
+# And off we go...
+Main()
diff --git a/cmake/git_watcher.cmake b/cmake/git_watcher.cmake
new file mode 100644
index 0000000..6447b86
--- /dev/null
+++ b/cmake/git_watcher.cmake
@@ -0,0 +1,213 @@
+# git_watcher.cmake
+#
+# License: MIT
+# Source: https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git_watcher.cmake
+
+
+# This file defines the functions and targets needed to monitor
+# the state of a git repo. If the state changes (e.g. a commit is made),
+# then a file gets reconfigured.
+#
+# The behavior of this script can be modified by defining any of these variables:
+#
+# PRE_CONFIGURE_GIT_VERSION_FILE (REQUIRED)
+# -- The path to the file that'll be configured.
+#
+# POST_CONFIGURE_GIT_VERSION_FILE (REQUIRED)
+# -- The path to the configured PRE_CONFIGURE_GIT_VERSION_FILE.
+#
+# GIT_STATE_FILE (OPTIONAL)
+# -- The path to the file used to store the previous build's git state.
+# Defaults to the current binary directory.
+#
+# GIT_WORKING_DIR (OPTIONAL)
+# -- The directory from which git commands will be run.
+# Defaults to the directory with the top level CMakeLists.txt.
+#
+# GIT_EXECUTABLE (OPTIONAL)
+# -- The path to the git executable. It'll automatically be set if the
+# user doesn't supply a path.
+#
+# Script design:
+# - This script was designed similar to a Python application
+# with a Main() function. I wanted to keep it compact to
+# simplify "copy + paste" usage.
+#
+# - This script is made to operate in two CMake contexts:
+# 1. Configure time context (when build files are created).
+# 2. Build time context (called via CMake -P)
+# If you see something odd (e.g. the NOT DEFINED clauses),
+# consider that it can run in one of two contexts.
+
+# Short hand for converting paths to absolute.
+macro(PATH_TO_ABSOLUTE var_name)
+ get_filename_component(${var_name} "${${var_name}}" ABSOLUTE)
+endmacro()
+
+# Check that a required variable is set.
+macro(CHECK_REQUIRED_VARIABLE var_name)
+ if(NOT DEFINED ${var_name})
+ message(FATAL_ERROR "The \"${var_name}\" variable must be defined.")
+ endif()
+ PATH_TO_ABSOLUTE(${var_name})
+endmacro()
+
+# Check that an optional variable is set, or, set it to a default value.
+macro(CHECK_OPTIONAL_VARIABLE var_name default_value)
+ if(NOT DEFINED ${var_name})
+ set(${var_name} ${default_value})
+ endif()
+ PATH_TO_ABSOLUTE(${var_name})
+endmacro()
+
+CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_GIT_VERSION_FILE)
+CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_GIT_VERSION_FILE)
+CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${GENERATED_SRC}/git_state")
+#CHECK_REQUIRED_VARIABLE(GIT_STATE_FILE)
+CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}")
+
+# Check the optional git variable.
+# If it's not set, we'll try to find it using the CMake packaging system.
+if(NOT DEFINED GIT_EXECUTABLE)
+ find_package(Git QUIET REQUIRED)
+endif()
+CHECK_REQUIRED_VARIABLE(GIT_EXECUTABLE)
+
+
+
+# Function: GitStateChangedAction
+# Description: this function is executed when the state of the git
+# repo changes (e.g. a commit is made).
+function(GitStateChangedAction _state_as_list)
+ # Set variables by index, then configure the file w/ these variables defined.
+ LIST(GET _state_as_list 0 GIT_RETRIEVED_STATE)
+ LIST(GET _state_as_list 1 GIT_HEAD_SHA1)
+ LIST(GET _state_as_list 2 GIT_IS_DIRTY)
+ configure_file("${PRE_CONFIGURE_GIT_VERSION_FILE}" "${POST_CONFIGURE_GIT_VERSION_FILE}" @ONLY)
+endfunction()
+
+
+
+# Function: GetGitState
+# Description: gets the current state of the git repo.
+# Args:
+# _working_dir (in) string; the directory from which git commands will be executed.
+# _state (out) list; a collection of variables representing the state of the
+# repository (e.g. commit SHA).
+function(GetGitState _working_dir _state)
+
+ # Get the hash for HEAD.
+ set(_success "true")
+ execute_process(COMMAND
+ "${GIT_EXECUTABLE}" rev-parse --verify HEAD
+ WORKING_DIRECTORY "${_working_dir}"
+ RESULT_VARIABLE res
+ OUTPUT_VARIABLE _hashvar
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT res EQUAL 0)
+ set(_success "false")
+ set(_hashvar "GIT-NOTFOUND")
+ endif()
+
+ # Get whether or not the working tree is dirty.
+ execute_process(COMMAND
+ "${GIT_EXECUTABLE}" status --porcelain
+ WORKING_DIRECTORY "${_working_dir}"
+ RESULT_VARIABLE res
+ OUTPUT_VARIABLE out
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if(NOT res EQUAL 0)
+ set(_success "false")
+ set(_dirty "false")
+ else()
+ if(NOT "${out}" STREQUAL "")
+ set(_dirty "true")
+ else()
+ set(_dirty "false")
+ endif()
+ endif()
+
+ # Return a list of our variables to the parent scope.
+ set(${_state} ${_success} ${_hashvar} ${_dirty} PARENT_SCOPE)
+endfunction()
+
+
+
+# Function: CheckGit
+# Description: check if the git repo has changed. If so, update the state file.
+# Args:
+# _working_dir (in) string; the directory from which git commands will be ran.
+# _state_changed (out) bool; whether or no the state of the repo has changed.
+# _state (out) list; the repository state as a list (e.g. commit SHA).
+function(CheckGit _working_dir _state_changed _state)
+
+ # Get the current state of the repo.
+ GetGitState("${_working_dir}" state)
+
+ # Set the output _state variable.
+ # (Passing by reference in CMake is awkward...)
+ set(${_state} ${state} PARENT_SCOPE)
+
+ # Check if the state has changed compared to the backup on disk.
+ if(EXISTS "${GIT_STATE_FILE}")
+ file(READ "${GIT_STATE_FILE}" OLD_HEAD_CONTENTS)
+ if(OLD_HEAD_CONTENTS STREQUAL "${state}")
+ # State didn't change.
+ set(${_state_changed} "false" PARENT_SCOPE)
+ return()
+ endif()
+ endif()
+
+ # The state has changed.
+ # We need to update the state file on disk.
+ # Future builds will compare their state to this file.
+ file(WRITE "${GIT_STATE_FILE}" "${state}")
+ set(${_state_changed} "true" PARENT_SCOPE)
+endfunction()
+
+
+
+# Function: SetupGitMonitoring
+# Description: this function sets up custom commands that make the build system
+# check the state of git before every build. If the state has
+# changed, then a file is configured.
+function(SetupGitMonitoring)
+ add_custom_target(check_git_repository
+ ALL
+ DEPENDS ${PRE_CONFIGURE_GIT_VERSION_FILE}
+ BYPRODUCTS ${POST_CONFIGURE_GIT_VERSION_FILE}
+ COMMENT "Checking the git repository for changes..."
+ COMMAND
+ ${CMAKE_COMMAND}
+ -D_BUILD_TIME_CHECK_GIT=TRUE
+ -DGIT_WORKING_DIR=${GIT_WORKING_DIR}
+ -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
+ -DGIT_STATE_FILE=${GIT_STATE_FILE}
+ -DPRE_CONFIGURE_GIT_VERSION_FILE=${PRE_CONFIGURE_GIT_VERSION_FILE}
+ -DPOST_CONFIGURE_GIT_VERSION_FILE=${POST_CONFIGURE_GIT_VERSION_FILE}
+ -P "${CMAKE_CURRENT_LIST_FILE}")
+endfunction()
+
+
+
+# Function: Main
+# Description: primary entry-point to the script. Functions are selected based
+# on whether it's configure or build time.
+function(Main)
+ if(_BUILD_TIME_CHECK_GIT)
+ # Check if the repo has changed.
+ # If so, run the change action.
+ CheckGit("${GIT_WORKING_DIR}" did_change state)
+ if(did_change)
+ GitStateChangedAction("${state}")
+ endif()
+ else()
+ # >> Executes at configure time.
+ SetupGitMonitoring()
+ endif()
+endfunction()
+
+# And off we go...
+Main()
diff --git a/doc/commands.doc b/doc/commands.doc
index 8e91b9c..48991fb 100644
--- a/doc/commands.doc
+++ b/doc/commands.doc
@@ -849,7 +849,7 @@ Structural indicators
This command turns a comment block into a header
definition of a member group. The
comment block should be followed by a
- <code>//\@{ ... //\@}</code> block containing the
+ <code>///\@{ ... ///\@}</code> block containing the
members of the group.
See section \ref memgroup for an example.
@@ -2783,9 +2783,9 @@ See also the \ref emojisup "emoji support page" for details.
\note The text fragment should only include the part of the message
sequence chart that is
- within the <code>msc {...}</code> block.
- \note You need to install the <code>mscgen</code> tool, if you want to use this
- command.
+ within the <code>msc {...}</code> block (this is different from
+ \ref cmdmscfile "\\mscfile").
+ \note mscgen is now built in into doxygen
Here is an example of the use of the \c \\msc command.
\code
@@ -2923,7 +2923,7 @@ class Receiver
The first argument specifies the file name of the image.
doxygen will look for files in the paths (or files) that you specified
after the \ref cfg_mscfile_dirs "MSCFILE_DIRS" tag.
- If the msc file is found it will be used as an input file to the mscgen tool.
+ If the msc file is found it will be used as an input file to the built in mscgen tool.
The resulting image will be put into the correct output directory.
If the msc file name contains spaces you'll have to put quotes ("...") around it.
@@ -2938,6 +2938,10 @@ class Receiver
\ref image_sizeindicator "Size indication" with the
\ref cmdimage "\\image" command.
+ \note The text fragment should include the part message of the
+ sequence chart as well as the starting `msc {` and ending `}`
+ (this is different from \ref cmdmsc "\\msc").
+
\sa section \ref cmdmsc "\\msc".
<hr>
diff --git a/doc/doxygen_manual.tex b/doc/doxygen_manual.tex
index bf269d2..8ff3c66 100644
--- a/doc/doxygen_manual.tex
+++ b/doc/doxygen_manual.tex
@@ -14,6 +14,14 @@
\batchmode
\documentclass{book}
+%% moved from doxygen.sty due to workaround for LaTex 2019 version and unmaintained tabu package
+\usepackage{ifthen}
+\ifx\requestedLaTeXdate\undefined
+\usepackage{array}
+\else
+\usepackage{array}[=2016-10-06]
+\fi
+%%
\usepackage[a4paper,left=2.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm]{geometry}
\usepackage{makeidx}
\usepackage{natbib}
@@ -23,7 +31,7 @@
\usepackage{geometry}
\usepackage{listings}
\usepackage{color}
-\usepackage{ifthen}
+%%\usepackage{ifthen} %% moved to top due to workaround for LaTex 2019 version and unmaintained tabu package
\usepackage[table]{xcolor}
\PassOptionsToPackage{warn}{textcomp}
\usepackage{textcomp}
@@ -58,12 +66,31 @@
\usepackage{doxygen}
\usepackage{manual}
%%
+% unfortunately constructs like:
+% \renewcommand{\doxysection}[1]{\doxysubsection{##1}}
+% using values from book.cls (see also doxygen.sty) and redefining sections to correct level.
\makeatletter
\newenvironment{DoxygenSubAppendix}{%
- \renewcommand{\doxysection}{\@ifstar{\doxysubsection@star}{\doxysubsection@nostar}}%
- \renewcommand{\doxysubsection}{\@ifstar{\doxysubsubsection@star}{\doxysubsubsection@nostar}}
- \renewcommand{\doxysubsubsection}{\@ifstar{\doxyparagraph@star}{\doxyparagraph@nostar}}
- \renewcommand{\doxyparagraph}{\@ifstar{\doxysubparagraph@star}{\doxysubparagraph@nostar}}
+\renewcommand\doxysection{\@startsection{subsection}{2}{\z@}%
+ {-3.25ex\@plus -1ex \@minus -.2ex}%
+ {1.5ex \@plus .2ex}%
+ {\raggedright\normalfont\large\bfseries}}
+\renewcommand\doxysubsection{\@startsection{subsubsection}{3}{\z@}%
+ {-3.25ex\@plus -1ex \@minus -.2ex}%
+ {1.5ex \@plus .2ex}%
+ {\raggedright\normalfont\normalsize\bfseries}}
+\renewcommand\doxysubsubsection{\@startsection{paragraph}{4}{\z@}%
+ {3.25ex \@plus1ex \@minus.2ex}%
+ {-1em}%
+ {\raggedright\normalfont\normalsize\bfseries}}
+\renewcommand\doxyparagraph{\@startsection{subparagraph}{5}{\parindent}%
+ {3.25ex \@plus1ex \@minus .2ex}%
+ {-1em}%
+ {\raggedright\normalfont\normalsize\bfseries}}
+%%\renewcommand{\doxysection}[1]{\doxysubsection{##1}}
+%%\renewcommand{\doxysubsection}[1]{\doxysubsubsection{##1}}
+%%\renewcommand{\doxysubsubsection}[1]{\doxyparagraph{##1}}
+%%\renewcommand{\doxyparagraph}[1]{\doxysubparagraph{##1}}
}{}
\makeatother
%%
diff --git a/doc/faq.doc b/doc/faq.doc
index 88a1275..0ba9450 100644
--- a/doc/faq.doc
+++ b/doc/faq.doc
@@ -235,6 +235,13 @@ should send me a code fragment that triggers the message. To work around
the problem, put some line-breaks into your file, split it up into smaller
parts, or exclude it from the input using EXCLUDE.
+Another way to work around this problem is to use the cmake command with the option:
+```
+-Denlarge_lex_buffers=<size>
+```
+where `<size>` is the new size of the input (`YY_BUF_SIZE`) and read (`YY_READ_BUF_SIZE`) buffer.
+In case this option is not given the default value of 262144 (i.e. 256K) will be used.
+
\section faq_latex When running make in the latex directory I get "TeX capacity exceeded". Now what?
You can edit the texmf.cfg file to increase the default values of the
diff --git a/doc/htmlcmds.doc b/doc/htmlcmds.doc
index d483237..12347ab 100644
--- a/doc/htmlcmds.doc
+++ b/doc/htmlcmds.doc
@@ -45,6 +45,8 @@ of a HTML tag are passed on to the HTML output only
\ref cmdendcode "\\endcode".
<li><tt>\<DD\></tt> Starts an item description.
<li><tt>\</DD\></tt> Ends an item description.
+<li><tt>\<DEL\></tt> Starts a section of deleted text, typically shown strike through text.
+<li><tt>\</DEL\></tt> Ends a section of deleted text.
<li><tt>\<DFN\></tt> Starts a piece of text displayed in a typewriter font.
<li><tt>\</DFN\></tt> Ends a <tt>\<DFN\></tt> section.
<li><tt>\<DIV></tt> Starts a section with a specific style (HTML only)
@@ -71,6 +73,8 @@ of a HTML tag are passed on to the HTML output only
<li><tt>\<I\></tt> Starts a piece of text displayed in an italic font.
<li><tt>\</I\></tt> Ends a <tt>\<I\></tt> section.
<li><tt>\<IMG SRC="..." ...\></tt> This command is written with its attributes to the HTML output only. The SRC attribute is mandatory.
+<li><tt>\<INS\></tt> Starts a section of inserted text, typically shown as underlined text.
+<li><tt>\</INS\></tt> Ends a section of inserted text.
<li><tt>\<LI\></tt> Starts a new list item.
<li><tt>\</LI\></tt> Ends a list item.
<li><tt>\<OL\></tt> Starts a numbered item list.
diff --git a/doc/install.doc b/doc/install.doc
index 18ea44e..b711cd4 100644
--- a/doc/install.doc
+++ b/doc/install.doc
@@ -201,7 +201,7 @@ 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 https://www.7-zip.org/)
-or use the build in unpack feature of modern Windows systems).
+or use the built-in unpack feature of modern Windows systems).
Now your environment is setup to generate the required project files for \c doxygen.
diff --git a/doc/preprocessing.doc b/doc/preprocessing.doc
index 882e60d..a49b889 100644
--- a/doc/preprocessing.doc
+++ b/doc/preprocessing.doc
@@ -264,6 +264,10 @@ preprocessing has been done (Hint: set <code>QUIET = YES</code> and
<code>WARNINGS = NO</code> in the configuration file to disable any other
output).
+Note preprocessing is not done for all languages. Preprocesing is enabled for files
+that use the "C" scanner (with the exception of 'java', 'd' and 'php'), Fortran files
+(only in case the extension contains at least one upper case character) and vhdl files.
+
\htmlonly
Go to the <a href="autolink.html">next</a> section or return to the
<a href="index.html">index</a>.
diff --git a/doc/trouble.doc b/doc/trouble.doc
index c490ae1..cb50399 100644
--- a/doc/trouble.doc
+++ b/doc/trouble.doc
@@ -20,7 +20,7 @@
<ul>
<li>Doxygen is <em>not</em> a real compiler, it is only a lexical scanner.
This means that it can and will not detect errors in your source code.
-<li>Doxygen has a build in preprocessor, but this works slightly different than
+<li>Doxygen has a built-in preprocessor, but this works slightly different than
the C preprocessor. Doxygen assumes a header file is properly guarded against
multiple inclusion, and that each include file is standalone (i.e. it could be placed
at the top of a source file without causing compiler errors). As long as this is
diff --git a/examples/memgrp.cpp b/examples/memgrp.cpp
index 9a24774..fdcf028 100644
--- a/examples/memgrp.cpp
+++ b/examples/memgrp.cpp
@@ -2,11 +2,11 @@
class Memgrp_Test
{
public:
- //@{
+ ///@{
/** Same documentation for both members. Details */
void func1InGroup1();
void func2InGroup1();
- //@}
+ ///@}
/** Function without group. Details. */
void ungroupedFunction();
diff --git a/jquery/README b/jquery/README
index b2b8259..6f39c34 100644
--- a/jquery/README
+++ b/jquery/README
@@ -1,6 +1,6 @@
Doxygen's jquery.js script is composed of minified versions of the following
packages:
-- jquery 3.3.1: https://jquery.com/download/
+- jquery 3.4.1: https://jquery.com/download/
- jquery.ui 1.12.1: https://github.com/jquery/jquery-ui
modules required:
- jquery.ui.core all
diff --git a/liblodepng/CMakeLists.txt b/liblodepng/CMakeLists.txt
new file mode 100644
index 0000000..e62835f
--- /dev/null
+++ b/liblodepng/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_library(lodepng STATIC
+lodepng.cpp
+)
diff --git a/src/lodepng.cpp b/liblodepng/lodepng.cpp
index 1906f09..6e28587 100644
--- a/src/lodepng.cpp
+++ b/liblodepng/lodepng.cpp
@@ -29,7 +29,6 @@ You are free to name this file lodepng.cpp or lodepng.c depending on your usage.
*/
#include "lodepng.h"
-#include "portable.h"
#define USE_BRUTE_FORCE_ENCODING 1
@@ -2435,8 +2434,7 @@ void LodePNG_Encoder_copy(LodePNG_Encoder* dest, const LodePNG_Encoder* source)
/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
unsigned LodePNG_saveFile(const unsigned char* buffer, size_t buffersize, const char* filename)
{
- FILE* file;
- file = portable_fopen(filename, "wb" );
+ FILE* file = fopen(filename,"wb");
if(!file) return 79;
fwrite((char*)buffer , 1 , buffersize, file);
fclose(file);
diff --git a/src/lodepng.h b/liblodepng/lodepng.h
index fb079cc..36d0e68 100644
--- a/src/lodepng.h
+++ b/liblodepng/lodepng.h
@@ -32,6 +32,10 @@ freely, subject to the following restrictions:
#include <stdlib.h>
#include <string.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* ////////////////////////////////////////////////////////////////////////// */
/* LodeFlate & LodeZlib Setting structs */
/* ////////////////////////////////////////////////////////////////////////// */
@@ -115,5 +119,9 @@ void LodePNG_encode(LodePNG_Encoder* encoder, unsigned char** out, size_t* outsi
//unsigned LodePNG_loadFile(unsigned char** out, size_t* outsize, const char* filename);
unsigned LodePNG_saveFile(const unsigned char* buffer, size_t buffersize, const char* filename);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/libmd5/Makefile.in b/libmd5/Makefile.in
deleted file mode 100644
index 08c03b8..0000000
--- a/libmd5/Makefile.in
+++ /dev/null
@@ -1,18 +0,0 @@
-all: Makefile.libmd5
- $(MAKE) -f Makefile.libmd5
-
-clean: Makefile.libmd5
- $(MAKE) -f Makefile.libmd5 clean
-
-distclean: clean
- $(RM) -f Makefile.libmd5 libmd5.pro Makefile
-
-realclean: distclean
-
-tmake:
- $(ENV) $(PERL) "$(TMAKE)" libmd5.pro >Makefile.libmd5
-
-Makefile.libmd5: libmd5.pro
- $(ENV) $(PERL) "$(TMAKE)" libmd5.pro >Makefile.libmd5
-
-install:
diff --git a/libmd5/libmd5.pro.in b/libmd5/libmd5.pro.in
deleted file mode 100644
index 5516174..0000000
--- a/libmd5/libmd5.pro.in
+++ /dev/null
@@ -1,10 +0,0 @@
-TEMPLATE = lib
-CONFIG = warn_on staticlib $extraopts
-HEADERS = md5.h md5_loc.h
-SOURCES = md5.c
-win32:INCLUDEPATH += .
-win32-g++:TMAKE_CFLAGS += -D__CYGWIN__ -DALL_STATIC
-DESTDIR = ../lib
-TARGET = md5
-OBJECTS_DIR = ../objects/md5
-
diff --git a/libmscgen/CMakeLists.txt b/libmscgen/CMakeLists.txt
new file mode 100644
index 0000000..3d67ed3
--- /dev/null
+++ b/libmscgen/CMakeLists.txt
@@ -0,0 +1,38 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}/liblodepng
+ ${CMAKE_SOURCE_DIR}/libmscgen
+ ${GENERATED_SRC}
+)
+
+add_library(mscgen
+gd.c
+gd_security.c
+gdfontt.c
+gdtables.c
+gd_color.c
+gdfonts.c
+gdhelpers.c
+gd_lodepng.c
+mscgen_adraw.c
+mscgen_gd_out.c
+mscgen_ps_out.c
+mscgen_null_out.c
+${GENERATED_SRC}/mscgen_language.cpp
+${GENERATED_SRC}/mscgen_lexer.cpp
+mscgen_api.c
+mscgen_msc.c
+mscgen_safe.c
+mscgen_svg_out.c
+mscgen_usage.c
+mscgen_utf8.c
+)
+
+
+FLEX_TARGET(mscgen_lexer
+ mscgen_lexer.l
+ ${GENERATED_SRC}/mscgen_lexer.cpp
+ COMPILE_FLAGS "${LEX_FLAGS}")
+BISON_TARGET(mscgen_language
+ mscgen_language.y
+ ${GENERATED_SRC}/mscgen_language.cpp
+ COMPILE_FLAGS "${YACC_FLAGS}")
diff --git a/libmscgen/COPYING b/libmscgen/COPYING
new file mode 100644
index 0000000..7d122e1
--- /dev/null
+++ b/libmscgen/COPYING
@@ -0,0 +1,287 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
+TTPCom Ltd., hereby disclaims all copyright interest in the program `mscgen'
+(which renders message sequence charts) written by Michael McTernan.
+
+Rob Meades of TTPCom Ltd, 1 August 2005
+Rob Meades, director of Software
diff --git a/libmscgen/README.txt b/libmscgen/README.txt
new file mode 100644
index 0000000..06b3902
--- /dev/null
+++ b/libmscgen/README.txt
@@ -0,0 +1,20 @@
+Issue 6880 (https://github.com/doxygen/doxygen/issues/6880) required fixes to the mscgen tool.
+Since this tool is no longer maintained, it was decided to build mscgen as part of doxygen.
+This directory contains the mscgen code.
+
+Since mscgen depends on libgd for PNG output, a part of the gd library is included as well.
+Instead of using libpng as PNG generator, the lodepng library is used. This PNG library was
+already part of doxygen. Module gd_lodepng.c was added to make libgd use lodepng.
+
+Original copyright statement follows:
+
+LICENCE
+=======
+
+Mscgen, Copyright (C) 2010 Michael C McTernan,
+ Michael.McTernan.2001@cs.bris.ac.uk
+Mscgen comes with ABSOLUTELY NO WARRANTY. Mscgen is free software, and you
+are welcome to redistribute it under certain conditions; see the COPYING
+file for details.
+
+
diff --git a/libmscgen/gd.c b/libmscgen/gd.c
new file mode 100644
index 0000000..7f0a258
--- /dev/null
+++ b/libmscgen/gd.c
@@ -0,0 +1,4539 @@
+/* $Id$ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gd_intern.h"
+
+/* 2.03: don't include zlib here or we can't build without PNG */
+#include "gd.h"
+#include "gdhelpers.h"
+#include "gd_color.h"
+#include "gd_errors.h"
+
+/* 2.0.12: this now checks the clipping rectangle */
+#define gdImageBoundsSafeMacro(im, x, y) (!((((y) < (im)->cy1) || ((y) > (im)->cy2)) || (((x) < (im)->cx1) || ((x) > (im)->cx2))))
+
+#ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */
+#define CHARSET_EBCDIC
+#define __attribute__(any) /*nothing */
+#endif
+/*_OSD_POSIX*/
+
+#ifndef CHARSET_EBCDIC
+#define ASC(ch) ch
+#else /*CHARSET_EBCDIC */
+#define ASC(ch) gd_toascii[(unsigned char)ch]
+static const unsigned char gd_toascii[256] = {
+ /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
+ 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ */
+ /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
+ 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ */
+ /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ */
+ /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
+ 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ */
+ /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
+ 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */
+ /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
+ 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. */
+ /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
+ 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
+ /*-/........^,%_>?*/
+ /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
+ 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" */
+ /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... */
+ /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+ 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... */
+ /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... */
+ /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
+ 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. */
+ /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... */
+ /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... */
+ /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... */
+ /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */
+};
+#endif /*CHARSET_EBCDIC */
+
+extern const int gdCosT[];
+extern const int gdSinT[];
+
+/**
+ * Group: Error Handling
+ */
+
+void gd_stderr_error(int priority, const char *format, va_list args)
+{
+ switch (priority) {
+ case GD_ERROR:
+ fputs("GD Error: ", stderr);
+ break;
+ case GD_WARNING:
+ fputs("GD Warning: ", stderr);
+ break;
+ case GD_NOTICE:
+ fputs("GD Notice: ", stderr);
+ break;
+ case GD_INFO:
+ fputs("GD Info: ", stderr);
+ break;
+ case GD_DEBUG:
+ fputs("GD Debug: ", stderr);
+ break;
+ }
+ vfprintf(stderr, format, args);
+ fflush(stderr);
+}
+
+static gdErrorMethod gd_error_method = gd_stderr_error;
+
+static void _gd_error_ex(int priority, const char *format, va_list args)
+{
+ if (gd_error_method) {
+ gd_error_method(priority, format, args);
+ }
+}
+
+void gd_error(const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ _gd_error_ex(GD_WARNING, format, args);
+ va_end(args);
+}
+void gd_error_ex(int priority, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ _gd_error_ex(priority, format, args);
+ va_end(args);
+}
+
+/*
+ Function: gdSetErrorMethod
+*/
+BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod error_method)
+{
+ gd_error_method = error_method;
+}
+
+/*
+ Function: gdClearErrorMethod
+*/
+BGD_DECLARE(void) gdClearErrorMethod(void)
+{
+ gd_error_method = gd_stderr_error;
+}
+
+static void gdImageBrushApply (gdImagePtr im, int x, int y);
+static void gdImageTileApply (gdImagePtr im, int x, int y);
+
+BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
+
+/**
+ * Group: Creation and Destruction
+ */
+
+/*
+ Function: gdImageCreate
+
+ gdImageCreate is called to create palette-based images, with no
+ more than 256 colors. The image must eventually be destroyed using
+ gdImageDestroy().
+
+ Parameters:
+
+ sx - The image width.
+ sy - The image height.
+
+ Returns:
+
+ A pointer to the new image or NULL if an error occurred.
+
+ Example:
+ (start code)
+
+ gdImagePtr im;
+ im = gdImageCreate(64, 64);
+ // ... Use the image ...
+ gdImageDestroy(im);
+
+ (end code)
+
+ See Also:
+
+ <gdImageCreateTrueColor>
+
+ */
+BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
+{
+ int i;
+ gdImagePtr im;
+
+ if (overflow2(sx, sy)) {
+ return NULL;
+ }
+
+ if (overflow2(sizeof (unsigned char *), sy)) {
+ return NULL;
+ }
+ if (overflow2(sizeof (unsigned char *), sx)) {
+ return NULL;
+ }
+
+ im = (gdImage *) gdCalloc(1, sizeof(gdImage));
+ if (!im) {
+ return NULL;
+ }
+
+ /* Row-major ever since gd 1.3 */
+ im->pixels = (unsigned char **) gdMalloc (sizeof (unsigned char *) * sy);
+ if (!im->pixels) {
+ gdFree(im);
+ return NULL;
+ }
+
+ im->polyInts = 0;
+ im->polyAllocated = 0;
+ im->brush = 0;
+ im->tile = 0;
+ im->style = 0;
+ for (i = 0; (i < sy); i++) {
+ /* Row-major ever since gd 1.3 */
+ im->pixels[i] = (unsigned char *) gdCalloc (sx, sizeof (unsigned char));
+ if (!im->pixels[i]) {
+ for (--i ; i >= 0; i--) {
+ gdFree(im->pixels[i]);
+ }
+ gdFree(im->pixels);
+ gdFree(im);
+ return NULL;
+ }
+
+ }
+ im->sx = sx;
+ im->sy = sy;
+ im->colorsTotal = 0;
+ im->transparent = (-1);
+ im->interlace = 0;
+ im->thick = 1;
+ im->AA = 0;
+ for (i = 0; (i < gdMaxColors); i++) {
+ im->open[i] = 1;
+ };
+ im->trueColor = 0;
+ im->tpixels = 0;
+ im->cx1 = 0;
+ im->cy1 = 0;
+ im->cx2 = im->sx - 1;
+ im->cy2 = im->sy - 1;
+ im->res_x = GD_RESOLUTION;
+ im->res_y = GD_RESOLUTION;
+ im->interpolation = NULL;
+ im->interpolation_id = GD_BILINEAR_FIXED;
+ return im;
+}
+
+
+
+/*
+ Function: gdImageCreateTrueColor
+
+ <gdImageCreateTrueColor> is called to create truecolor images,
+ with an essentially unlimited number of colors. Invoke
+ <gdImageCreateTrueColor> with the x and y dimensions of the
+ desired image. <gdImageCreateTrueColor> returns a <gdImagePtr>
+ to the new image, or NULL if unable to allocate the image. The
+ image must eventually be destroyed using <gdImageDestroy>().
+
+ Truecolor images are always filled with black at creation
+ time. There is no concept of a "background" color index.
+
+ Parameters:
+
+ sx - The image width.
+ sy - The image height.
+
+ Returns:
+
+ A pointer to the new image or NULL if an error occurred.
+
+ Example:
+ (start code)
+
+ gdImagePtr im;
+ im = gdImageCreateTrueColor(64, 64);
+ // ... Use the image ...
+ gdImageDestroy(im);
+
+ (end code)
+
+ See Also:
+
+ <gdImageCreateTrueColor>
+
+*/
+BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy)
+{
+ int i;
+ gdImagePtr im;
+
+ if (overflow2(sx, sy)) {
+ return NULL;
+ }
+
+ if (overflow2(sizeof (int *), sy)) {
+ return 0;
+ }
+
+ if (overflow2(sizeof(int *), sx)) {
+ return NULL;
+ }
+
+ im = (gdImage *) gdMalloc (sizeof (gdImage));
+ if (!im) {
+ return 0;
+ }
+ memset (im, 0, sizeof (gdImage));
+
+ im->tpixels = (int **) gdMalloc (sizeof (int *) * sy);
+ if (!im->tpixels) {
+ gdFree(im);
+ return 0;
+ }
+ im->polyInts = 0;
+ im->polyAllocated = 0;
+ im->brush = 0;
+ im->tile = 0;
+ im->style = 0;
+ for (i = 0; (i < sy); i++) {
+ im->tpixels[i] = (int *) gdCalloc (sx, sizeof (int));
+ if (!im->tpixels[i]) {
+ /* 2.0.34 */
+ i--;
+ while (i >= 0) {
+ gdFree(im->tpixels[i]);
+ i--;
+ }
+ gdFree(im->tpixels);
+ gdFree(im);
+ return 0;
+ }
+ }
+ im->sx = sx;
+ im->sy = sy;
+ im->transparent = (-1);
+ im->interlace = 0;
+ im->trueColor = 1;
+ /* 2.0.2: alpha blending is now on by default, and saving of alpha is
+ off by default. This allows font antialiasing to work as expected
+ on the first try in JPEGs -- quite important -- and also allows
+ for smaller PNGs when saving of alpha channel is not really
+ desired, which it usually isn't! */
+ im->saveAlphaFlag = 0;
+ im->alphaBlendingFlag = 1;
+ im->thick = 1;
+ im->AA = 0;
+ im->cx1 = 0;
+ im->cy1 = 0;
+ im->cx2 = im->sx - 1;
+ im->cy2 = im->sy - 1;
+ im->res_x = GD_RESOLUTION;
+ im->res_y = GD_RESOLUTION;
+ im->interpolation = NULL;
+ im->interpolation_id = GD_BILINEAR_FIXED;
+ return im;
+}
+
+/*
+ Function: gdImageDestroy
+
+ <gdImageDestroy> is used to free the memory associated with an
+ image. It is important to invoke <gdImageDestroy> before exiting
+ your program or assigning a new image to a <gdImagePtr> variable.
+
+ Parameters:
+
+ im - Pointer to the gdImage to delete.
+
+ Returns:
+
+ Nothing.
+
+ Example:
+ (start code)
+
+ gdImagePtr im;
+ im = gdImageCreate(10, 10);
+ // ... Use the image ...
+ // Now destroy it
+ gdImageDestroy(im);
+
+ (end code)
+
+*/
+
+BGD_DECLARE(void) gdImageDestroy (gdImagePtr im)
+{
+ int i;
+ if (im->pixels) {
+ for (i = 0; (i < im->sy); i++) {
+ gdFree (im->pixels[i]);
+ }
+ gdFree (im->pixels);
+ }
+ if (im->tpixels) {
+ for (i = 0; (i < im->sy); i++) {
+ gdFree (im->tpixels[i]);
+ }
+ gdFree (im->tpixels);
+ }
+ if (im->polyInts) {
+ gdFree (im->polyInts);
+ }
+ if (im->style) {
+ gdFree (im->style);
+ }
+ gdFree (im);
+}
+
+/**
+ * Group: Color
+ */
+
+/**
+ * Function: gdImageColorClosest
+ *
+ * Gets the closest color of the image
+ *
+ * This is a simplified variant of <gdImageColorClosestAlpha> where the alpha
+ * channel is always opaque.
+ *
+ * Parameters:
+ * im - The image.
+ * r - The value of the red component.
+ * g - The value of the green component.
+ * b - The value of the blue component.
+ *
+ * Returns:
+ * The closest color already available in the palette for palette images;
+ * the color value of the given components for truecolor images.
+ *
+ * See also:
+ * - <gdImageColorExact>
+ */
+BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b)
+{
+ return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
+}
+
+/**
+ * Function: gdImageColorClosestAlpha
+ *
+ * Gets the closest color of the image
+ *
+ * Parameters:
+ * im - The image.
+ * r - The value of the red component.
+ * g - The value of the green component.
+ * b - The value of the blue component.
+ * a - The value of the alpha component.
+ *
+ * Returns:
+ * The closest color already available in the palette for palette images;
+ * the color value of the given components for truecolor images.
+ *
+ * See also:
+ * - <gdImageColorExactAlpha>
+ */
+BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
+{
+ int i;
+ long rd, gd, bd, ad;
+ int ct = (-1);
+ int first = 1;
+ long mindist = 0;
+ if (im->trueColor) {
+ return gdTrueColorAlpha (r, g, b, a);
+ }
+ for (i = 0; (i < (im->colorsTotal)); i++) {
+ long dist;
+ if (im->open[i]) {
+ continue;
+ }
+ rd = (im->red[i] - r);
+ gd = (im->green[i] - g);
+ bd = (im->blue[i] - b);
+ /* gd 2.02: whoops, was - b (thanks to David Marwood) */
+ /* gd 2.16: was blue rather than alpha! Geez! Thanks to
+ Artur Jakub Jerzak */
+ ad = (im->alpha[i] - a);
+ dist = rd * rd + gd * gd + bd * bd + ad * ad;
+ if (first || (dist < mindist)) {
+ mindist = dist;
+ ct = i;
+ first = 0;
+ }
+ }
+ return ct;
+}
+
+/* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
+ * on colour conversion to/from RBG and HWB colour systems.
+ * It has been modified to return the converted value as a * parameter.
+ */
+
+#define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
+#define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
+#define HWB_UNDEFINED -1
+#define SETUP_RGB(s, r, g, b) {s.R = r/255.0; s.G = g/255.0; s.B = b/255.0;}
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
+#define MAX(a,b) ((a)<(b)?(b):(a))
+#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
+
+
+/*
+ * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
+ * red always maps to 6 in this implementation. Therefore UNDEFINED can be
+ * defined as 0 in situations where only unsigned numbers are desired.
+ */
+typedef struct {
+ float R, G, B;
+}
+RGBType;
+typedef struct {
+ float H, W, B;
+}
+HWBType;
+
+static HWBType *
+RGB_to_HWB (RGBType RGB, HWBType * HWB)
+{
+
+ /*
+ * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
+ * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
+ */
+
+ float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
+ int i;
+
+ w = MIN3 (R, G, B);
+ v = MAX3 (R, G, B);
+ b = 1 - v;
+ if (v == w)
+ RETURN_HWB (HWB_UNDEFINED, w, b);
+ f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
+ i = (R == w) ? 3 : ((G == w) ? 5 : 1);
+ RETURN_HWB (i - f / (v - w), w, b);
+
+}
+
+static float
+HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
+{
+ RGBType RGB1, RGB2;
+ HWBType HWB1, HWB2;
+ float diff;
+
+ SETUP_RGB (RGB1, r1, g1, b1);
+ SETUP_RGB (RGB2, r2, g2, b2);
+
+ RGB_to_HWB (RGB1, &HWB1);
+ RGB_to_HWB (RGB2, &HWB2);
+
+ /*
+ * I made this bit up; it seems to produce OK results, and it is certainly
+ * more visually correct than the current RGB metric. (PJW)
+ */
+
+ if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
+ diff = 0; /* Undefined hues always match... */
+ } else {
+ diff = fabs (HWB1.H - HWB2.H);
+ if (diff > 3) {
+ diff = 6 - diff; /* Remember, it's a colour circle */
+ }
+ }
+
+ diff =
+ diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B -
+ HWB2.B) * (HWB1.B -
+ HWB2.B);
+
+ return diff;
+}
+
+
+#if 0
+/*
+ * This is not actually used, but is here for completeness, in case someone wants to
+ * use the HWB stuff for anything else...
+ */
+static RGBType *
+HWB_to_RGB (HWBType HWB, RGBType * RGB)
+{
+
+ /*
+ * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
+ * RGB are each returned on [0, 1].
+ */
+
+ float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
+ int i;
+
+ v = 1 - b;
+ if (h == HWB_UNDEFINED)
+ RETURN_RGB (v, v, v);
+ i = floor (h);
+ f = h - i;
+ if (i & 1)
+ f = 1 - f; /* if i is odd */
+ n = w + f * (v - w); /* linear interpolation between w and v */
+ switch (i) {
+ case 6:
+ case 0:
+ RETURN_RGB (v, n, w);
+ case 1:
+ RETURN_RGB (n, v, w);
+ case 2:
+ RETURN_RGB (w, v, n);
+ case 3:
+ RETURN_RGB (w, n, v);
+ case 4:
+ RETURN_RGB (n, w, v);
+ case 5:
+ RETURN_RGB (v, w, n);
+ }
+
+ return RGB;
+
+}
+#endif
+
+/*
+ Function: gdImageColorClosestHWB
+*/
+BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
+{
+ int i;
+ /* long rd, gd, bd; */
+ int ct = (-1);
+ int first = 1;
+ float mindist = 0;
+ if (im->trueColor) {
+ return gdTrueColor (r, g, b);
+ }
+ for (i = 0; (i < (im->colorsTotal)); i++) {
+ float dist;
+ if (im->open[i]) {
+ continue;
+ }
+ dist = HWB_Diff (im->red[i], im->green[i], im->blue[i], r, g, b);
+ if (first || (dist < mindist)) {
+ mindist = dist;
+ ct = i;
+ first = 0;
+ }
+ }
+ return ct;
+}
+
+/**
+ * Function: gdImageColorExact
+ *
+ * Gets the exact color of the image
+ *
+ * This is a simplified variant of <gdImageColorExactAlpha> where the alpha
+ * channel is always opaque.
+ *
+ * Parameters:
+ * im - The image.
+ * r - The value of the red component.
+ * g - The value of the green component.
+ * b - The value of the blue component.
+ *
+ * Returns:
+ * The exact color already available in the palette for palette images; if
+ * there is no exact color, -1 is returned.
+ * For truecolor images the color value of the given components is returned.
+ *
+ * See also:
+ * - <gdImageColorClosest>
+ */
+BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b)
+{
+ return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
+}
+
+/**
+ * Function: gdImageColorExactAlpha
+ *
+ * Gets the exact color of the image
+ *
+ * Parameters:
+ * im - The image.
+ * r - The value of the red component.
+ * g - The value of the green component.
+ * b - The value of the blue component.
+ * a - The value of the alpha component.
+ *
+ * Returns:
+ * The exact color already available in the palette for palette images; if
+ * there is no exact color, -1 is returned.
+ * For truecolor images the color value of the given components is returned.
+ *
+ * See also:
+ * - <gdImageColorClosestAlpha>
+ * - <gdTrueColorAlpha>
+ */
+BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
+{
+ int i;
+ if (im->trueColor) {
+ return gdTrueColorAlpha (r, g, b, a);
+ }
+ for (i = 0; (i < (im->colorsTotal)); i++) {
+ if (im->open[i]) {
+ continue;
+ }
+ if ((im->red[i] == r) &&
+ (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Function: gdImageColorAllocate
+ *
+ * Allocates a color
+ *
+ * This is a simplified variant of <gdImageColorAllocateAlpha> where the alpha
+ * channel is always opaque.
+ *
+ * Parameters:
+ * im - The image.
+ * r - The value of the red component.
+ * g - The value of the green component.
+ * b - The value of the blue component.
+ *
+ * Returns:
+ * The color value.
+ *
+ * See also:
+ * - <gdImageColorDeallocate>
+ */
+BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
+{
+ return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
+}
+
+/**
+ * Function: gdImageColorAllocateAlpha
+ *
+ * Allocates a color
+ *
+ * This is typically used for palette images, but can be used for truecolor
+ * images as well.
+ *
+ * Parameters:
+ * im - The image.
+ * r - The value of the red component.
+ * g - The value of the green component.
+ * b - The value of the blue component.
+ *
+ * Returns:
+ * The color value.
+ *
+ * See also:
+ * - <gdImageColorDeallocate>
+ */
+BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
+{
+ int i;
+ int ct = (-1);
+ if (im->trueColor) {
+ return gdTrueColorAlpha (r, g, b, a);
+ }
+ for (i = 0; (i < (im->colorsTotal)); i++) {
+ if (im->open[i]) {
+ ct = i;
+ break;
+ }
+ }
+ if (ct == (-1)) {
+ ct = im->colorsTotal;
+ if (ct == gdMaxColors) {
+ return -1;
+ }
+ im->colorsTotal++;
+ }
+ im->red[ct] = r;
+ im->green[ct] = g;
+ im->blue[ct] = b;
+ im->alpha[ct] = a;
+ im->open[ct] = 0;
+ return ct;
+}
+
+/*
+ Function: gdImageColorResolve
+
+ gdImageColorResolve is an alternative for the code fragment
+ (start code)
+ if ((color=gdImageColorExact(im,R,G,B)) < 0)
+ if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
+ color=gdImageColorClosest(im,R,G,B);
+ (end code)
+ in a single function. Its advantage is that it is guaranteed to
+ return a color index in one search over the color table.
+*/
+
+BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b)
+{
+ return gdImageColorResolveAlpha (im, r, g, b, gdAlphaOpaque);
+}
+
+/*
+ Function: gdImageColorResolveAlpha
+*/
+BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
+{
+ int c;
+ int ct = -1;
+ int op = -1;
+ long rd, gd, bd, ad, dist;
+ long mindist = 4 * 255 * 255; /* init to max poss dist */
+ if (im->trueColor) {
+ return gdTrueColorAlpha (r, g, b, a);
+ }
+
+ for (c = 0; c < im->colorsTotal; c++) {
+ if (im->open[c]) {
+ op = c; /* Save open slot */
+ continue; /* Color not in use */
+ }
+ if (c == im->transparent) {
+ /* don't ever resolve to the color that has
+ * been designated as the transparent color */
+ continue;
+ }
+ rd = (long) (im->red[c] - r);
+ gd = (long) (im->green[c] - g);
+ bd = (long) (im->blue[c] - b);
+ ad = (long) (im->alpha[c] - a);
+ dist = rd * rd + gd * gd + bd * bd + ad * ad;
+ if (dist < mindist) {
+ if (dist == 0) {
+ return c; /* Return exact match color */
+ }
+ mindist = dist;
+ ct = c;
+ }
+ }
+ /* no exact match. We now know closest, but first try to allocate exact */
+ if (op == -1) {
+ op = im->colorsTotal;
+ if (op == gdMaxColors) {
+ /* No room for more colors */
+ return ct; /* Return closest available color */
+ }
+ im->colorsTotal++;
+ }
+ im->red[op] = r;
+ im->green[op] = g;
+ im->blue[op] = b;
+ im->alpha[op] = a;
+ im->open[op] = 0;
+ return op; /* Return newly allocated color */
+}
+
+/**
+ * Function: gdImageColorDeallocate
+ *
+ * Removes a palette entry
+ *
+ * This is a no-op for truecolor images.
+ *
+ * Parameters:
+ * im - The image.
+ * color - The palette index.
+ *
+ * See also:
+ * - <gdImageColorAllocate>
+ * - <gdImageColorAllocateAlpha>
+ */
+BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color)
+{
+ if (im->trueColor || (color >= gdMaxColors) || (color < 0)) {
+ return;
+ }
+ /* Mark it open. */
+ im->open[color] = 1;
+}
+
+/**
+ * Function: gdImageColorTransparent
+ *
+ * Sets the transparent color of the image
+ *
+ * Parameter:
+ * im - The image.
+ * color - The color.
+ *
+ * See also:
+ * - <gdImageGetTransparent>
+ */
+BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color)
+{
+ if (color < 0) {
+ return;
+ }
+
+ if (!im->trueColor) {
+ if((color < -1) || (color >= gdMaxColors)) {
+ return;
+ }
+ if (im->transparent != -1) {
+ im->alpha[im->transparent] = gdAlphaOpaque;
+ }
+ if (color != -1) {
+ im->alpha[color] = gdAlphaTransparent;
+ }
+ }
+ im->transparent = color;
+}
+
+/*
+ Function: gdImagePaletteCopy
+*/
+BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
+{
+ int i;
+ int x, y, p;
+ int xlate[256];
+ if (to->trueColor) {
+ return;
+ }
+ if (from->trueColor) {
+ return;
+ }
+
+ for (i = 0; i < 256; i++) {
+ xlate[i] = -1;
+ };
+
+ for (y = 0; y < (to->sy); y++) {
+ for (x = 0; x < (to->sx); x++) {
+ /* Optimization: no gdImageGetPixel */
+ p = to->pixels[y][x];
+ if (xlate[p] == -1) {
+ /* This ought to use HWB, but we don't have an alpha-aware
+ version of that yet. */
+ xlate[p] =
+ gdImageColorClosestAlpha (from, to->red[p], to->green[p],
+ to->blue[p], to->alpha[p]);
+ /*printf("Mapping %d (%d, %d, %d, %d) to %d (%d, %d, %d, %d)\n", */
+ /* p, to->red[p], to->green[p], to->blue[p], to->alpha[p], */
+ /* xlate[p], from->red[xlate[p]], from->green[xlate[p]], from->blue[xlate[p]], from->alpha[xlate[p]]); */
+ };
+ /* Optimization: no gdImageSetPixel */
+ to->pixels[y][x] = xlate[p];
+ };
+ };
+
+ for (i = 0; (i < (from->colorsTotal)); i++) {
+ /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[i]); */
+ to->red[i] = from->red[i];
+ to->blue[i] = from->blue[i];
+ to->green[i] = from->green[i];
+ to->alpha[i] = from->alpha[i];
+ to->open[i] = 0;
+ };
+
+ for (i = from->colorsTotal; (i < to->colorsTotal); i++) {
+ to->open[i] = 1;
+ };
+
+ to->colorsTotal = from->colorsTotal;
+
+}
+
+/*
+ Function: gdImageColorReplace
+*/
+BGD_DECLARE(int) gdImageColorReplace (gdImagePtr im, int src, int dst)
+{
+ register int x, y;
+ int n = 0;
+
+ if (src == dst) {
+ return 0;
+ }
+
+#define REPLACING_LOOP(pixel) do { \
+ for (y = im->cy1; y <= im->cy2; y++) { \
+ for (x = im->cx1; x <= im->cx2; x++) { \
+ if (pixel(im, x, y) == src) { \
+ gdImageSetPixel(im, x, y, dst); \
+ n++; \
+ } \
+ } \
+ } \
+ } while (0)
+
+ if (im->trueColor) {
+ REPLACING_LOOP(gdImageTrueColorPixel);
+ } else {
+ REPLACING_LOOP(gdImagePalettePixel);
+ }
+
+#undef REPLACING_LOOP
+
+ return n;
+}
+
+/*
+ Function: gdImageColorReplaceThreshold
+*/
+BGD_DECLARE(int) gdImageColorReplaceThreshold (gdImagePtr im, int src, int dst, float threshold)
+{
+ register int x, y;
+ int n = 0;
+
+ if (src == dst) {
+ return 0;
+ }
+
+#define REPLACING_LOOP(pixel) do { \
+ for (y = im->cy1; y <= im->cy2; y++) { \
+ for (x = im->cx1; x <= im->cx2; x++) { \
+ if (gdColorMatch(im, src, pixel(im, x, y), threshold)) { \
+ gdImageSetPixel(im, x, y, dst); \
+ n++; \
+ } \
+ } \
+ } \
+ } while (0)
+
+ if (im->trueColor) {
+ REPLACING_LOOP(gdImageTrueColorPixel);
+ } else {
+ REPLACING_LOOP(gdImagePalettePixel);
+ }
+
+#undef REPLACING_LOOP
+
+ return n;
+}
+
+static int colorCmp (const void *x, const void *y)
+{
+ int a = *(int const *)x;
+ int b = *(int const *)y;
+ return (a > b) - (a < b);
+}
+
+/*
+ Function: gdImageColorReplaceArray
+*/
+BGD_DECLARE(int) gdImageColorReplaceArray (gdImagePtr im, int len, int *src, int *dst)
+{
+ register int x, y;
+ int c, *d, *base;
+ int i, n = 0;
+
+ if (len <= 0 || src == dst) {
+ return 0;
+ }
+ if (len == 1) {
+ return gdImageColorReplace(im, src[0], dst[0]);
+ }
+ if (overflow2(len, sizeof(int)<<1)) {
+ return -1;
+ }
+ base = (int *)gdMalloc(len * (sizeof(int)<<1));
+ if (!base) {
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ base[(i<<1)] = src[i];
+ base[(i<<1)+1] = dst[i];
+ }
+ qsort(base, len, sizeof(int)<<1, colorCmp);
+
+#define REPLACING_LOOP(pixel) do { \
+ for (y = im->cy1; y <= im->cy2; y++) { \
+ for (x = im->cx1; x <= im->cx2; x++) { \
+ c = pixel(im, x, y); \
+ if ( (d = (int *)bsearch(&c, base, len, sizeof(int)<<1, colorCmp)) ) { \
+ gdImageSetPixel(im, x, y, d[1]); \
+ n++; \
+ } \
+ } \
+ } \
+ } while (0)
+
+ if (im->trueColor) {
+ REPLACING_LOOP(gdImageTrueColorPixel);
+ } else {
+ REPLACING_LOOP(gdImagePalettePixel);
+ }
+
+#undef REPLACING_LOOP
+
+ gdFree(base);
+ return n;
+}
+
+/*
+ Function: gdImageColorReplaceCallback
+*/
+BGD_DECLARE(int) gdImageColorReplaceCallback (gdImagePtr im, gdCallbackImageColor callback)
+{
+ int c, d, n = 0;
+
+ if (!callback) {
+ return 0;
+ }
+ if (im->trueColor) {
+ register int x, y;
+
+ for (y = im->cy1; y <= im->cy2; y++) {
+ for (x = im->cx1; x <= im->cx2; x++) {
+ c = gdImageTrueColorPixel(im, x, y);
+ if ( (d = callback(im, c)) != c) {
+ gdImageSetPixel(im, x, y, d);
+ n++;
+ }
+ }
+ }
+ } else { /* palette */
+ int *sarr, *darr;
+ int k, len = 0;
+
+ sarr = (int *)gdCalloc(im->colorsTotal, sizeof(int));
+ if (!sarr) {
+ return -1;
+ }
+ for (c = 0; c < im->colorsTotal; c++) {
+ if (!im->open[c]) {
+ sarr[len++] = c;
+ }
+ }
+ darr = (int *)gdCalloc(len, sizeof(int));
+ if (!darr) {
+ gdFree(sarr);
+ return -1;
+ }
+ for (k = 0; k < len; k++) {
+ darr[k] = callback(im, sarr[k]);
+ }
+ n = gdImageColorReplaceArray(im, k, sarr, darr);
+ gdFree(darr);
+ gdFree(sarr);
+ }
+ return n;
+}
+
+/* 2.0.10: before the drawing routines, some code to clip points that are
+ * outside the drawing window. Nick Atty (nick@canalplan.org.uk)
+ *
+ * This is the Sutherland Hodgman Algorithm, as implemented by
+ * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's
+ * Journal, January 1996, pp107-110 and 116-117
+ *
+ * Given the end points of a line, and a bounding rectangle (which we
+ * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
+ * the edges of the rectangle if the line should be drawn at all,
+ * otherwise return a failure code */
+
+/* this does "one-dimensional" clipping: note that the second time it
+ is called, all the x parameters refer to height and the y to width
+ - the comments ignore this (if you can understand it when it's
+ looking at the X parameters, it should become clear what happens on
+ the second call!) The code is simplified from that in the article,
+ as we know that gd images always start at (0,0) */
+
+/* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't
+ necessarily start at 0. */
+
+static int
+clip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim)
+{
+ double m; /* gradient of line */
+ if (*x0 < mindim) {
+ /* start of line is left of window */
+ if (*x1 < mindim) /* as is the end, so the line never cuts the window */
+ return 0;
+ m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
+ /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
+ *y0 -= (int)(m * (*x0 - mindim));
+ *x0 = mindim;
+ /* now, perhaps, adjust the far end of the line as well */
+ if (*x1 > maxdim) {
+ *y1 += m * (maxdim - *x1);
+ *x1 = maxdim;
+ }
+ return 1;
+ }
+ if (*x0 > maxdim) {
+ /* start of line is right of window -
+ complement of above */
+ if (*x1 > maxdim) /* as is the end, so the line misses the window */
+ return 0;
+ m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
+ *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right
+ boundary */
+ *x0 = maxdim;
+ /* now, perhaps, adjust the end of the line */
+ if (*x1 < mindim) {
+ *y1 -= (int)(m * (*x1 - mindim));
+ *x1 = mindim;
+ }
+ return 1;
+ }
+ /* the final case - the start of the line is inside the window */
+ if (*x1 > maxdim) {
+ /* other end is outside to the right */
+ m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
+ *y1 += (int)(m * (maxdim - *x1));
+ *x1 = maxdim;
+ return 1;
+ }
+ if (*x1 < mindim) {
+ /* other end is outside to the left */
+ m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */
+ *y1 -= (int)(m * (*x1 - mindim));
+ *x1 = mindim;
+ return 1;
+ }
+ /* only get here if both points are inside the window */
+ return 1;
+}
+
+/* end of line clipping code */
+
+/**
+ * Group: Pixels
+ */
+
+/*
+ Function: gdImageSetPixel
+*/
+BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color)
+{
+ int p;
+ switch (color) {
+ case gdStyled:
+ if (!im->style) {
+ /* Refuse to draw if no style is set. */
+ return;
+ } else {
+ p = im->style[im->stylePos++];
+ }
+ if (p != (gdTransparent)) {
+ gdImageSetPixel (im, x, y, p);
+ }
+ im->stylePos = im->stylePos % im->styleLength;
+ break;
+ case gdStyledBrushed:
+ if (!im->style) {
+ /* Refuse to draw if no style is set. */
+ return;
+ }
+ p = im->style[im->stylePos++];
+ if ((p != gdTransparent) && (p != 0)) {
+ gdImageSetPixel (im, x, y, gdBrushed);
+ }
+ im->stylePos = im->stylePos % im->styleLength;
+ break;
+ case gdBrushed:
+ gdImageBrushApply (im, x, y);
+ break;
+ case gdTiled:
+ gdImageTileApply (im, x, y);
+ break;
+ case gdAntiAliased:
+ /* This shouldn't happen (2.0.26) because we just call
+ gdImageAALine now, but do something sane. */
+ gdImageSetPixel(im, x, y, im->AA_color);
+ break;
+ default:
+ if (gdImageBoundsSafeMacro (im, x, y)) {
+ if (im->trueColor) {
+ switch (im->alphaBlendingFlag) {
+ default:
+ case gdEffectReplace:
+ im->tpixels[y][x] = color;
+ break;
+ case gdEffectAlphaBlend:
+ case gdEffectNormal:
+ im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
+ break;
+ case gdEffectOverlay :
+ im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
+ break;
+ case gdEffectMultiply :
+ im->tpixels[y][x] = gdLayerMultiply(im->tpixels[y][x], color);
+ break;
+ }
+ } else {
+ im->pixels[y][x] = color;
+ }
+ }
+ break;
+ }
+}
+
+static void
+gdImageBrushApply (gdImagePtr im, int x, int y)
+{
+ int lx, ly;
+ int hy;
+ int hx;
+ int x1, y1, x2, y2;
+ int srcx, srcy;
+ if (!im->brush) {
+ return;
+ }
+ hy = gdImageSY (im->brush) / 2;
+ y1 = y - hy;
+ y2 = y1 + gdImageSY (im->brush);
+ hx = gdImageSX (im->brush) / 2;
+ x1 = x - hx;
+ x2 = x1 + gdImageSX (im->brush);
+ srcy = 0;
+ if (im->trueColor) {
+ if (im->brush->trueColor) {
+ for (ly = y1; (ly < y2); ly++) {
+ srcx = 0;
+ for (lx = x1; (lx < x2); lx++) {
+ int p;
+ p = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
+ /* 2.0.9, Thomas Winzig: apply simple full transparency */
+ if (p != gdImageGetTransparent (im->brush)) {
+ gdImageSetPixel (im, lx, ly, p);
+ }
+ srcx++;
+ }
+ srcy++;
+ }
+ } else {
+ /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger
+ for pointing out the issue) */
+ for (ly = y1; (ly < y2); ly++) {
+ srcx = 0;
+ for (lx = x1; (lx < x2); lx++) {
+ int p, tc;
+ p = gdImageGetPixel (im->brush, srcx, srcy);
+ tc = gdImageGetTrueColorPixel (im->brush, srcx, srcy);
+ /* 2.0.9, Thomas Winzig: apply simple full transparency */
+ if (p != gdImageGetTransparent (im->brush)) {
+ gdImageSetPixel (im, lx, ly, tc);
+ }
+ srcx++;
+ }
+ srcy++;
+ }
+ }
+ } else {
+ for (ly = y1; (ly < y2); ly++) {
+ srcx = 0;
+ for (lx = x1; (lx < x2); lx++) {
+ int p;
+ p = gdImageGetPixel (im->brush, srcx, srcy);
+ /* Allow for non-square brushes! */
+ if (p != gdImageGetTransparent (im->brush)) {
+ /* Truecolor brush. Very slow
+ on a palette destination. */
+ if (im->brush->trueColor) {
+ gdImageSetPixel (im, lx, ly,
+ gdImageColorResolveAlpha (im,
+ gdTrueColorGetRed
+ (p),
+ gdTrueColorGetGreen
+ (p),
+ gdTrueColorGetBlue
+ (p),
+ gdTrueColorGetAlpha
+ (p)));
+ } else {
+ gdImageSetPixel (im, lx, ly, im->brushColorMap[p]);
+ }
+ }
+ srcx++;
+ }
+ srcy++;
+ }
+ }
+}
+
+static void
+gdImageTileApply (gdImagePtr im, int x, int y)
+{
+ gdImagePtr tile = im->tile;
+ int srcx, srcy;
+ int p;
+ if (!tile) {
+ return;
+ }
+ srcx = x % gdImageSX (tile);
+ srcy = y % gdImageSY (tile);
+ if (im->trueColor) {
+ p = gdImageGetPixel (tile, srcx, srcy);
+ if (p != gdImageGetTransparent (tile)) {
+ if (!tile->trueColor) {
+ p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
+ }
+ gdImageSetPixel (im, x, y, p);
+ }
+ } else {
+ p = gdImageGetPixel (tile, srcx, srcy);
+ /* Allow for transparency */
+ if (p != gdImageGetTransparent (tile)) {
+ if (tile->trueColor) {
+ /* Truecolor tile. Very slow
+ on a palette destination. */
+ gdImageSetPixel (im, x, y,
+ gdImageColorResolveAlpha (im,
+ gdTrueColorGetRed
+ (p),
+ gdTrueColorGetGreen
+ (p),
+ gdTrueColorGetBlue
+ (p),
+ gdTrueColorGetAlpha
+ (p)));
+ } else {
+ gdImageSetPixel (im, x, y, im->tileColorMap[p]);
+ }
+ }
+ }
+}
+
+/**
+ * Function: gdImageGetPixel
+ *
+ * Gets a pixel color as stored in the image.
+ *
+ * Parameters:
+ * im - The image.
+ * x - The x-coordinate.
+ * y - The y-coordinate.
+ *
+ * See also:
+ * - <gdImageGetTrueColorPixel>
+ * - <gdImagePalettePixel>
+ * - <gdImageTrueColorPixel>
+ */
+BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y)
+{
+ if (gdImageBoundsSafeMacro (im, x, y)) {
+ if (im->trueColor) {
+ return im->tpixels[y][x];
+ } else {
+ return im->pixels[y][x];
+ }
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Function: gdImageGetTrueColorPixel
+ *
+ * Gets a pixel color always as truecolor value.
+ *
+ * Parameters:
+ * im - The image.
+ * x - The x-coordinate.
+ * y - The y-coordinate.
+ *
+ * See also:
+ * - <gdImageGetPixel>
+ * - <gdImageTrueColorPixel>
+ */
+BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
+{
+ int p = gdImageGetPixel (im, x, y);
+ if (!im->trueColor) {
+ return gdTrueColorAlpha (im->red[p], im->green[p], im->blue[p],
+ (im->transparent == p) ? gdAlphaTransparent :
+ im->alpha[p]);
+ } else {
+ return p;
+ }
+}
+
+/**
+ * Group: Primitives
+ */
+
+/*
+ Function: gdImageAABlend
+
+ NO-OP, kept for library compatibility.
+*/
+BGD_DECLARE(void) gdImageAABlend (gdImagePtr im)
+{
+ (void)im;
+}
+
+static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col);
+
+static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color);
+
+static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
+{
+ if (im->thick > 1) {
+ int thickhalf = im->thick >> 1;
+ _gdImageFilledHRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
+ } else {
+ if (x2 < x1) {
+ int t = x2;
+ x2 = x1;
+ x1 = t;
+ }
+
+ for (; x1 <= x2; x1++) {
+ gdImageSetPixel(im, x1, y, col);
+ }
+ }
+ return;
+}
+
+static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
+{
+ if (im->thick > 1) {
+ int thickhalf = im->thick >> 1;
+ gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
+ } else {
+ if (y2 < y1) {
+ int t = y1;
+ y1 = y2;
+ y2 = t;
+ }
+
+ for (; y1 <= y2; y1++) {
+ gdImageSetPixel(im, x, y1, col);
+ }
+ }
+ return;
+}
+
+/*
+ Function: gdImageLine
+
+ Bresenham as presented in Foley & Van Dam.
+*/
+BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
+ int wid;
+ int w, wstart;
+ int thick;
+
+ if (color == gdAntiAliased) {
+ /*
+ gdAntiAliased passed as color: use the much faster, much cheaper
+ and equally attractive gdImageAALine implementation. That
+ clips too, so don't clip twice.
+ */
+ gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
+ return;
+ }
+ /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no
+ points need to be drawn. 2.0.26, TBB: clip to edges of clipping
+ rectangle. We were getting away with this because gdImageSetPixel
+ is used for actual drawing, but this is still more efficient and opens
+ the way to skip per-pixel bounds checking in the future. */
+
+ if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
+ return;
+ if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
+ return;
+ thick = im->thick;
+
+ dx = abs (x2 - x1);
+ dy = abs (y2 - y1);
+
+ if (dx == 0) {
+ gdImageVLine(im, x1, y1, y2, color);
+ return;
+ } else if (dy == 0) {
+ gdImageHLine(im, y1, x1, x2, color);
+ return;
+ }
+
+ if (dy <= dx) {
+ /* More-or-less horizontal. use wid for vertical stroke */
+ /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
+
+ /* 2.0.12: Michael Schwartz: divide rather than multiply;
+ TBB: but watch out for /0! */
+ double ac = cos (atan2 (dy, dx));
+ if (ac != 0) {
+ wid = thick / ac;
+ } else {
+ wid = 1;
+ }
+ if (wid == 0) {
+ wid = 1;
+ }
+ d = 2 * dy - dx;
+ incr1 = 2 * dy;
+ incr2 = 2 * (dy - dx);
+ if (x1 > x2) {
+ x = x2;
+ y = y2;
+ ydirflag = (-1);
+ xend = x1;
+ } else {
+ x = x1;
+ y = y1;
+ ydirflag = 1;
+ xend = x2;
+ }
+
+ /* Set up line thickness */
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, x, w, color);
+
+ if (((y2 - y1) * ydirflag) > 0) {
+ while (x < xend) {
+ x++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ y++;
+ d += incr2;
+ }
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, x, w, color);
+ }
+ } else {
+ while (x < xend) {
+ x++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ y--;
+ d += incr2;
+ }
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, x, w, color);
+ }
+ }
+ } else {
+ /* More-or-less vertical. use wid for horizontal stroke */
+ /* 2.0.12: Michael Schwartz: divide rather than multiply;
+ TBB: but watch out for /0! */
+ double as = sin (atan2 (dy, dx));
+ if (as != 0) {
+ wid = thick / as;
+ } else {
+ wid = 1;
+ }
+ if (wid == 0)
+ wid = 1;
+
+ d = 2 * dx - dy;
+ incr1 = 2 * dx;
+ incr2 = 2 * (dx - dy);
+ if (y1 > y2) {
+ y = y2;
+ x = x2;
+ yend = y1;
+ xdirflag = (-1);
+ } else {
+ y = y1;
+ x = x1;
+ yend = y2;
+ xdirflag = 1;
+ }
+
+ /* Set up line thickness */
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, w, y, color);
+
+ if (((x2 - x1) * xdirflag) > 0) {
+ while (y < yend) {
+ y++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ x++;
+ d += incr2;
+ }
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, w, y, color);
+ }
+ } else {
+ while (y < yend) {
+ y++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ x--;
+ d += incr2;
+ }
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, w, y, color);
+ }
+ }
+ }
+
+}
+static void dashedSet (gdImagePtr im, int x, int y, int color,
+ int *onP, int *dashStepP, int wid, int vert);
+
+/*
+ Function: gdImageDashedLine
+*/
+BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
+ int dashStep = 0;
+ int on = 1;
+ int wid;
+ int vert;
+ int thick = im->thick;
+
+ dx = abs (x2 - x1);
+ dy = abs (y2 - y1);
+ if (dy <= dx) {
+ /* More-or-less horizontal. use wid for vertical stroke */
+ /* 2.0.12: Michael Schwartz: divide rather than multiply;
+ TBB: but watch out for /0! */
+ double as = sin (atan2 (dy, dx));
+ if (as != 0) {
+ wid = thick / as;
+ } else {
+ wid = 1;
+ }
+ vert = 1;
+
+ d = 2 * dy - dx;
+ incr1 = 2 * dy;
+ incr2 = 2 * (dy - dx);
+ if (x1 > x2) {
+ x = x2;
+ y = y2;
+ ydirflag = (-1);
+ xend = x1;
+ } else {
+ x = x1;
+ y = y1;
+ ydirflag = 1;
+ xend = x2;
+ }
+ dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
+ if (((y2 - y1) * ydirflag) > 0) {
+ while (x < xend) {
+ x++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ y++;
+ d += incr2;
+ }
+ dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
+ }
+ } else {
+ while (x < xend) {
+ x++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ y--;
+ d += incr2;
+ }
+ dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
+ }
+ }
+ } else {
+ /* 2.0.12: Michael Schwartz: divide rather than multiply;
+ TBB: but watch out for /0! */
+ double as = sin (atan2 (dy, dx));
+ if (as != 0) {
+ wid = thick / as;
+ } else {
+ wid = 1;
+ }
+ vert = 0;
+
+ d = 2 * dx - dy;
+ incr1 = 2 * dx;
+ incr2 = 2 * (dx - dy);
+ if (y1 > y2) {
+ y = y2;
+ x = x2;
+ yend = y1;
+ xdirflag = (-1);
+ } else {
+ y = y1;
+ x = x1;
+ yend = y2;
+ xdirflag = 1;
+ }
+ dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
+ if (((x2 - x1) * xdirflag) > 0) {
+ while (y < yend) {
+ y++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ x++;
+ d += incr2;
+ }
+ dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
+ }
+ } else {
+ while (y < yend) {
+ y++;
+ if (d < 0) {
+ d += incr1;
+ } else {
+ x--;
+ d += incr2;
+ }
+ dashedSet (im, x, y, color, &on, &dashStep, wid, vert);
+ }
+ }
+ }
+}
+
+static void
+dashedSet (gdImagePtr im, int x, int y, int color,
+ int *onP, int *dashStepP, int wid, int vert)
+{
+ int dashStep = *dashStepP;
+ int on = *onP;
+ int w, wstart;
+
+ dashStep++;
+ if (dashStep == gdDashSize) {
+ dashStep = 0;
+ on = !on;
+ }
+ if (on) {
+ if (vert) {
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, x, w, color);
+ } else {
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++)
+ gdImageSetPixel (im, w, y, color);
+ }
+ }
+ *dashStepP = dashStep;
+ *onP = on;
+}
+
+/*
+ Function: gdImageBoundsSafe
+*/
+BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y)
+{
+ return gdImageBoundsSafeMacro (im, x, y);
+}
+
+/**
+ * Function: gdImageChar
+ *
+ * Draws a single character.
+ *
+ * Parameters:
+ * im - The image to draw onto.
+ * f - The raster font.
+ * x - The x coordinate of the upper left pixel.
+ * y - The y coordinate of the upper left pixel.
+ * c - The character.
+ * color - The color.
+ *
+ * Variants:
+ * - <gdImageCharUp>
+ *
+ * See also:
+ * - <gdFontPtr>
+ */
+BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
+{
+ int cx, cy;
+ int px, py;
+ int fline;
+ cx = 0;
+ cy = 0;
+#ifdef CHARSET_EBCDIC
+ c = ASC (c);
+#endif /*CHARSET_EBCDIC */
+ if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
+ return;
+ }
+ fline = (c - f->offset) * f->h * f->w;
+ for (py = y; (py < (y + f->h)); py++) {
+ for (px = x; (px < (x + f->w)); px++) {
+ if (f->data[fline + cy * f->w + cx]) {
+ gdImageSetPixel (im, px, py, color);
+ }
+ cx++;
+ }
+ cx = 0;
+ cy++;
+ }
+}
+
+/**
+ * Function: gdImageCharUp
+ */
+BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
+{
+ int cx, cy;
+ int px, py;
+ int fline;
+ cx = 0;
+ cy = 0;
+#ifdef CHARSET_EBCDIC
+ c = ASC (c);
+#endif /*CHARSET_EBCDIC */
+ if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
+ return;
+ }
+ fline = (c - f->offset) * f->h * f->w;
+ for (py = y; (py > (y - f->w)); py--) {
+ for (px = x; (px < (x + f->h)); px++) {
+ if (f->data[fline + cy * f->w + cx]) {
+ gdImageSetPixel (im, px, py, color);
+ }
+ cy++;
+ }
+ cy = 0;
+ cx++;
+ }
+}
+
+/**
+ * Function: gdImageString
+ *
+ * Draws a character string.
+ *
+ * Parameters:
+ * im - The image to draw onto.
+ * f - The raster font.
+ * x - The x coordinate of the upper left pixel.
+ * y - The y coordinate of the upper left pixel.
+ * c - The character string.
+ * color - The color.
+ *
+ * Variants:
+ * - <gdImageStringUp>
+ * - <gdImageString16>
+ * - <gdImageStringUp16>
+ *
+ * See also:
+ * - <gdFontPtr>
+ * - <gdImageStringTTF>
+ */
+BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned char *s, int color)
+{
+ int i;
+ int l;
+ l = strlen ((char *) s);
+ for (i = 0; (i < l); i++) {
+ gdImageChar (im, f, x, y, s[i], color);
+ x += f->w;
+ }
+}
+
+/**
+ * Function: gdImageStringUp
+ */
+BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned char *s, int color)
+{
+ int i;
+ int l;
+ l = strlen ((char *) s);
+ for (i = 0; (i < l); i++) {
+ gdImageCharUp (im, f, x, y, s[i], color);
+ y -= f->w;
+ }
+}
+
+static int strlen16 (unsigned short *s);
+
+/**
+ * Function: gdImageString16
+ */
+BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned short *s, int color)
+{
+ int i;
+ int l;
+ l = strlen16 (s);
+ for (i = 0; (i < l); i++) {
+ gdImageChar (im, f, x, y, s[i], color);
+ x += f->w;
+ }
+}
+
+/**
+ * Function: gdImageStringUp16
+ */
+BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f,
+ int x, int y, unsigned short *s, int color)
+{
+ int i;
+ int l;
+ l = strlen16 (s);
+ for (i = 0; (i < l); i++) {
+ gdImageCharUp (im, f, x, y, s[i], color);
+ y -= f->w;
+ }
+}
+
+static int
+strlen16 (unsigned short *s)
+{
+ int len = 0;
+ while (*s) {
+ s++;
+ len++;
+ }
+ return len;
+}
+
+#ifndef HAVE_LSQRT
+/* If you don't have a nice square root function for longs, you can use
+ ** this hack
+ */
+long
+lsqrt (long n)
+{
+ long result = (long) sqrt ((double) n);
+ return result;
+}
+#endif
+
+/* s and e are integers modulo 360 (degrees), with 0 degrees
+ being the rightmost extreme and degrees changing clockwise.
+ cx and cy are the center in pixels; w and h are the horizontal
+ and vertical diameter in pixels. */
+
+/*
+ Function: gdImageArc
+*/
+BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
+ int color)
+{
+ gdImageFilledArc (im, cx, cy, w, h, s, e, color, gdNoFill);
+}
+
+/*
+ Function: gdImageFilledArc
+*/
+BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
+ int color, int style)
+{
+ gdPoint pts[363];
+ int i, pti;
+ int lx = 0, ly = 0;
+ int fx = 0, fy = 0;
+
+ if ((s % 360) == (e % 360)) {
+ s = 0;
+ e = 360;
+ } else {
+ if (s > 360) {
+ s = s % 360;
+ }
+
+ if (e > 360) {
+ e = e % 360;
+ }
+
+ while (s < 0) {
+ s += 360;
+ }
+
+ while (e < s) {
+ e += 360;
+ }
+
+ if (s == e) {
+ s = 0;
+ e = 360;
+ }
+ }
+
+ for (i = s, pti = 1; (i <= e); i++, pti++) {
+ int x, y;
+ x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
+ y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
+ if (i != s) {
+ if (!(style & gdChord)) {
+ if (style & gdNoFill) {
+ gdImageLine (im, lx, ly, x, y, color);
+ } else {
+ if (y == ly) {
+ pti--; /* don't add this point */
+ if (((i > 270 || i < 90) && x > lx) || ((i > 90 && i < 270) && x < lx)) {
+ /* replace the old x coord, if increasing on the
+ right side or decreasing on the left side */
+ pts[pti].x = x;
+ }
+ } else {
+ pts[pti].x = x;
+ pts[pti].y = y;
+ }
+ }
+ }
+ } else {
+ fx = x;
+ fy = y;
+
+ if (!(style & (gdChord | gdNoFill))) {
+ pts[0].x = cx;
+ pts[0].y = cy;
+ pts[pti].x = x;
+ pts[pti].y = y;
+ }
+ }
+ lx = x;
+ ly = y;
+ }
+ if (style & gdChord) {
+ if (style & gdNoFill) {
+ if (style & gdEdged) {
+ gdImageLine (im, cx, cy, lx, ly, color);
+ gdImageLine (im, cx, cy, fx, fy, color);
+ }
+ gdImageLine (im, fx, fy, lx, ly, color);
+ } else {
+ pts[0].x = fx;
+ pts[0].y = fy;
+ pts[1].x = lx;
+ pts[1].y = ly;
+ pts[2].x = cx;
+ pts[2].y = cy;
+ gdImageFilledPolygon (im, pts, 3, color);
+ }
+ } else {
+ if (style & gdNoFill) {
+ if (style & gdEdged) {
+ gdImageLine (im, cx, cy, lx, ly, color);
+ gdImageLine (im, cx, cy, fx, fy, color);
+ }
+ } else {
+ pts[pti].x = cx;
+ pts[pti].y = cy;
+ gdImageFilledPolygon(im, pts, pti+1, color);
+ }
+ }
+}
+
+/*
+ Function: gdImageEllipse
+*/
+BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int mx, int my, int w, int h, int c)
+{
+ int x=0,mx1=0,mx2=0,my1=0,my2=0;
+ long aq,bq,dx,dy,r,rx,ry,a,b;
+
+ a=w>>1;
+ b=h>>1;
+ gdImageSetPixel(im,mx+a, my, c);
+ gdImageSetPixel(im,mx-a, my, c);
+ mx1 = mx-a;
+ my1 = my;
+ mx2 = mx+a;
+ my2 = my;
+
+ aq = a * a;
+ bq = b * b;
+ dx = aq << 1;
+ dy = bq << 1;
+ r = a * bq;
+ rx = r << 1;
+ ry = 0;
+ x = a;
+ while (x > 0) {
+ if (r > 0) {
+ my1++;
+ my2--;
+ ry +=dx;
+ r -=ry;
+ }
+ if (r <= 0) {
+ x--;
+ mx1++;
+ mx2--;
+ rx -=dy;
+ r +=rx;
+ }
+ gdImageSetPixel(im,mx1, my1, c);
+ gdImageSetPixel(im,mx1, my2, c);
+ gdImageSetPixel(im,mx2, my1, c);
+ gdImageSetPixel(im,mx2, my2, c);
+ }
+}
+
+
+/*
+ Function: gdImageFilledEllipse
+*/
+BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c)
+{
+ int x=0,mx1=0,mx2=0,my1=0,my2=0;
+ long aq,bq,dx,dy,r,rx,ry,a,b;
+ int i;
+ int old_y2;
+
+ a=w>>1;
+ b=h>>1;
+
+ for (x = mx-a; x <= mx+a; x++) {
+ gdImageSetPixel(im, x, my, c);
+ }
+
+ mx1 = mx-a;
+ my1 = my;
+ mx2 = mx+a;
+ my2 = my;
+
+ aq = a * a;
+ bq = b * b;
+ dx = aq << 1;
+ dy = bq << 1;
+ r = a * bq;
+ rx = r << 1;
+ ry = 0;
+ x = a;
+ old_y2=-2;
+ while (x > 0) {
+ if (r > 0) {
+ my1++;
+ my2--;
+ ry +=dx;
+ r -=ry;
+ }
+ if (r <= 0) {
+ x--;
+ mx1++;
+ mx2--;
+ rx -=dy;
+ r +=rx;
+ }
+
+ if(old_y2!=my2) {
+ for(i=mx1; i<=mx2; i++) {
+ gdImageSetPixel(im,i,my2,c);
+ gdImageSetPixel(im,i,my1,c);
+ }
+ }
+ old_y2 = my2;
+ }
+}
+
+/*
+ Function: gdImageFillToBorder
+*/
+BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
+{
+ int lastBorder;
+ /* Seek left */
+ int leftLimit, rightLimit;
+ int i;
+ int restoreAlphaBleding;
+
+ if (border < 0 || color < 0) {
+ /* Refuse to fill to a non-solid border */
+ return;
+ }
+
+ if (!im->trueColor) {
+ if ((color > (im->colorsTotal - 1)) || (border > (im->colorsTotal - 1)) || (color < 0)) {
+ return;
+ }
+ }
+
+ leftLimit = (-1);
+
+ restoreAlphaBleding = im->alphaBlendingFlag;
+ im->alphaBlendingFlag = 0;
+
+ if (x >= im->sx) {
+ x = im->sx - 1;
+ } else if (x < 0) {
+ x = 0;
+ }
+ if (y >= im->sy) {
+ y = im->sy - 1;
+ } else if (y < 0) {
+ y = 0;
+ }
+
+ for (i = x; (i >= 0); i--) {
+ if (gdImageGetPixel (im, i, y) == border) {
+ break;
+ }
+ gdImageSetPixel (im, i, y, color);
+ leftLimit = i;
+ }
+ if (leftLimit == (-1)) {
+ im->alphaBlendingFlag = restoreAlphaBleding;
+ return;
+ }
+ /* Seek right */
+ rightLimit = x;
+ for (i = (x + 1); (i < im->sx); i++) {
+ if (gdImageGetPixel (im, i, y) == border) {
+ break;
+ }
+ gdImageSetPixel (im, i, y, color);
+ rightLimit = i;
+ }
+ /* Look at lines above and below and start paints */
+ /* Above */
+ if (y > 0) {
+ lastBorder = 1;
+ for (i = leftLimit; (i <= rightLimit); i++) {
+ int c;
+ c = gdImageGetPixel (im, i, y - 1);
+ if (lastBorder) {
+ if ((c != border) && (c != color)) {
+ gdImageFillToBorder (im, i, y - 1, border, color);
+ lastBorder = 0;
+ }
+ } else if ((c == border) || (c == color)) {
+ lastBorder = 1;
+ }
+ }
+ }
+ /* Below */
+ if (y < ((im->sy) - 1)) {
+ lastBorder = 1;
+ for (i = leftLimit; (i <= rightLimit); i++) {
+ int c = gdImageGetPixel (im, i, y + 1);
+ if (lastBorder) {
+ if ((c != border) && (c != color)) {
+ gdImageFillToBorder (im, i, y + 1, border, color);
+ lastBorder = 0;
+ }
+ } else if ((c == border) || (c == color)) {
+ lastBorder = 1;
+ }
+ }
+ }
+ im->alphaBlendingFlag = restoreAlphaBleding;
+}
+
+/*
+ * set the pixel at (x,y) and its 4-connected neighbors
+ * with the same pixel value to the new pixel value nc (new color).
+ * A 4-connected neighbor: pixel above, below, left, or right of a pixel.
+ * ideas from comp.graphics discussions.
+ * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
+ * contain the same color as the color to fill. To do not bloat normal filling
+ * code I added a 2nd private function.
+ */
+
+static int gdImageTileGet (gdImagePtr im, int x, int y)
+{
+ int srcx, srcy;
+ int tileColor,p;
+ if (!im->tile) {
+ return -1;
+ }
+ srcx = x % gdImageSX(im->tile);
+ srcy = y % gdImageSY(im->tile);
+ p = gdImageGetPixel(im->tile, srcx, srcy);
+ if (p == im->tile->transparent) {
+ tileColor = im->transparent;
+ } else if (im->trueColor) {
+ if (im->tile->trueColor) {
+ tileColor = p;
+ } else {
+ tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
+ }
+ } else {
+ if (im->tile->trueColor) {
+ tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
+ } else {
+ tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
+ }
+ }
+ return tileColor;
+}
+
+
+
+/* horizontal segment of scan line y */
+struct seg {
+ int y, xl, xr, dy;
+};
+
+/* max depth of stack */
+#define FILL_MAX ((int)(im->sy*im->sx)/4)
+#define FILL_PUSH(Y, XL, XR, DY) \
+ if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
+ {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
+
+#define FILL_POP(Y, XL, XR, DY) \
+ {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
+
+static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
+
+/*
+ Function: gdImageFill
+*/
+BGD_DECLARE(void) gdImageFill(gdImagePtr im, int x, int y, int nc)
+{
+ int l, x1, x2, dy;
+ int oc; /* old pixel value */
+ int wx2,wy2;
+
+ int alphablending_bak;
+
+ /* stack of filled segments */
+ /* struct seg stack[FILL_MAX],*sp = stack; */
+ struct seg *stack;
+ struct seg *sp;
+
+ if (!im->trueColor && nc > (im->colorsTotal - 1)) {
+ return;
+ }
+
+ alphablending_bak = im->alphaBlendingFlag;
+ im->alphaBlendingFlag = 0;
+
+ if (nc==gdTiled) {
+ _gdImageFillTiled(im,x,y,nc);
+ im->alphaBlendingFlag = alphablending_bak;
+ return;
+ }
+
+ wx2=im->sx;
+ wy2=im->sy;
+ oc = gdImageGetPixel(im, x, y);
+ if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
+ im->alphaBlendingFlag = alphablending_bak;
+ return;
+ }
+
+ /* Do not use the 4 neighbors implementation with
+ * small images
+ */
+ if (im->sx < 4) {
+ int ix = x, iy = y, c;
+ do {
+ do {
+ c = gdImageGetPixel(im, ix, iy);
+ if (c != oc) {
+ goto done;
+ }
+ gdImageSetPixel(im, ix, iy, nc);
+ } while(ix++ < (im->sx -1));
+ ix = x;
+ } while(iy++ < (im->sy -1));
+ goto done;
+ }
+
+ if(overflow2(im->sy, im->sx)) {
+ return;
+ }
+
+ if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
+ return;
+ }
+
+ stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
+ if (!stack) {
+ return;
+ }
+ sp = stack;
+
+ /* required! */
+ FILL_PUSH(y,x,x,1);
+ /* seed segment (popped 1st) */
+ FILL_PUSH(y+1, x, x, -1);
+ while (sp>stack) {
+ FILL_POP(y, x1, x2, dy);
+
+ for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
+ gdImageSetPixel(im,x, y, nc);
+ }
+ if (x>=x1) {
+ goto skip;
+ }
+ l = x+1;
+
+ /* leak on left? */
+ if (l<x1) {
+ FILL_PUSH(y, l, x1-1, -dy);
+ }
+ x = x1+1;
+ do {
+ for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
+ gdImageSetPixel(im, x, y, nc);
+ }
+ FILL_PUSH(y, l, x-1, dy);
+ /* leak on right? */
+ if (x>x2+1) {
+ FILL_PUSH(y, x2+1, x-1, -dy);
+ }
+skip:
+ for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
+
+ l = x;
+ } while (x<=x2);
+ }
+
+ gdFree(stack);
+
+done:
+ im->alphaBlendingFlag = alphablending_bak;
+}
+
+static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
+{
+ int l, x1, x2, dy;
+ int oc; /* old pixel value */
+ int wx2,wy2;
+ /* stack of filled segments */
+ struct seg *stack;
+ struct seg *sp;
+ char *pts;
+
+ if (!im->tile) {
+ return;
+ }
+
+ wx2=im->sx;
+ wy2=im->sy;
+
+ if(overflow2(im->sy, im->sx)) {
+ return;
+ }
+
+ if(overflow2(sizeof(struct seg), ((im->sy * im->sx) / 4))) {
+ return;
+ }
+
+ pts = (char *) gdCalloc(im->sy * im->sx, sizeof(char));
+ if (!pts) {
+ return;
+ }
+
+ stack = (struct seg *)gdMalloc(sizeof(struct seg) * ((int)(im->sy*im->sx)/4));
+ if (!stack) {
+ gdFree(pts);
+ return;
+ }
+ sp = stack;
+
+ oc = gdImageGetPixel(im, x, y);
+
+ /* required! */
+ FILL_PUSH(y,x,x,1);
+ /* seed segment (popped 1st) */
+ FILL_PUSH(y+1, x, x, -1);
+ while (sp>stack) {
+ FILL_POP(y, x1, x2, dy);
+ for (x=x1; x>=0 && (!pts[y + x*wy2] && gdImageGetPixel(im,x,y)==oc); x--) {
+ nc = gdImageTileGet(im,x,y);
+ pts[y + x*wy2]=1;
+ gdImageSetPixel(im,x, y, nc);
+ }
+ if (x>=x1) {
+ goto skip;
+ }
+ l = x+1;
+
+ /* leak on left? */
+ if (l<x1) {
+ FILL_PUSH(y, l, x1-1, -dy);
+ }
+ x = x1+1;
+ do {
+ for (; x<wx2 && (!pts[y + x*wy2] && gdImageGetPixel(im,x, y)==oc) ; x++) {
+ if (pts[y + x*wy2]) {
+ /* we should never be here */
+ break;
+ }
+ nc = gdImageTileGet(im,x,y);
+ pts[y + x*wy2]=1;
+ gdImageSetPixel(im, x, y, nc);
+ }
+ FILL_PUSH(y, l, x-1, dy);
+ /* leak on right? */
+ if (x>x2+1) {
+ FILL_PUSH(y, x2+1, x-1, -dy);
+ }
+skip:
+ for (x++; x<=x2 && (pts[y + x*wy2] || gdImageGetPixel(im,x, y)!=oc); x++);
+ l = x;
+ } while (x<=x2);
+ }
+
+ gdFree(pts);
+ gdFree(stack);
+}
+
+/**
+ * Function: gdImageRectangle
+ *
+ * Draws a rectangle.
+ *
+ * Parameters:
+ * im - The image.
+ * x1 - The x-coordinate of the upper left corner.
+ * y1 - The y-coordinate of the upper left corner.
+ * x2 - The x-coordinate of the lower right corner.
+ * y2 - The y-coordinate of the lower right corner.
+ * color - The color.
+ *
+ * Note that x1,y1 and x2,y2 may be swapped, i.e. the former may designate the
+ * lower right corner and the latter the upper left corner. The behavior for
+ * specifying other corners is undefined.
+ *
+ * See also:
+ * - <gdImageFilledRectangle>
+ */
+BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
+{
+ int thick = im->thick;
+
+ if (x1 == x2 && y1 == y2 && thick == 1) {
+ gdImageSetPixel(im, x1, y1, color);
+ return;
+ }
+
+ if (y2 < y1) {
+ int t;
+ t = y1;
+ y1 = y2;
+ y2 = t;
+
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ }
+
+ if (thick > 1) {
+ int cx, cy, x1ul, y1ul, x2lr, y2lr;
+ int half = thick >> 1;
+ x1ul = x1 - half;
+ y1ul = y1 - half;
+
+ x2lr = x2 + half;
+ y2lr = y2 + half;
+
+ cy = y1ul + thick;
+ while (cy-- > y1ul) {
+ cx = x1ul - 1;
+ while (cx++ < x2lr) {
+ gdImageSetPixel(im, cx, cy, color);
+ }
+ }
+
+ cy = y2lr - thick;
+ while (cy++ < y2lr) {
+ cx = x1ul - 1;
+ while (cx++ < x2lr) {
+ gdImageSetPixel(im, cx, cy, color);
+ }
+ }
+
+ cy = y1ul + thick - 1;
+ while (cy++ < y2lr -thick) {
+ cx = x1ul - 1;
+ while (cx++ < x1ul + thick) {
+ gdImageSetPixel(im, cx, cy, color);
+ }
+ }
+
+ cy = y1ul + thick - 1;
+ while (cy++ < y2lr -thick) {
+ cx = x2lr - thick - 1;
+ while (cx++ < x2lr) {
+ gdImageSetPixel(im, cx, cy, color);
+ }
+ }
+
+ return;
+ } else {
+ if (x1 == x2 || y1 == y2) {
+ gdImageLine(im, x1, y1, x2, y2, color);
+ } else {
+ gdImageLine(im, x1, y1, x2, y1, color);
+ gdImageLine(im, x1, y2, x2, y2, color);
+ gdImageLine(im, x1, y1 + 1, x1, y2 - 1, color);
+ gdImageLine(im, x2, y1 + 1, x2, y2 - 1, color);
+ }
+ }
+}
+
+static void _gdImageFilledHRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color)
+{
+ int x, y;
+
+ if (x1 == x2 && y1 == y2) {
+ gdImageSetPixel(im, x1, y1, color);
+ return;
+ }
+
+ if (x1 > x2) {
+ x = x1;
+ x1 = x2;
+ x2 = x;
+ }
+
+ if (y1 > y2) {
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+
+ if (x1 < 0) {
+ x1 = 0;
+ }
+
+ if (x2 >= gdImageSX(im)) {
+ x2 = gdImageSX(im) - 1;
+ }
+
+ if (y1 < 0) {
+ y1 = 0;
+ }
+
+ if (y2 >= gdImageSY(im)) {
+ y2 = gdImageSY(im) - 1;
+ }
+
+ for (x = x1; (x <= x2); x++) {
+ for (y = y1; (y <= y2); y++) {
+ gdImageSetPixel (im, x, y, color);
+ }
+ }
+}
+
+static void _gdImageFilledVRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color)
+{
+ int x, y;
+
+ if (x1 == x2 && y1 == y2) {
+ gdImageSetPixel(im, x1, y1, color);
+ return;
+ }
+
+ if (x1 > x2) {
+ x = x1;
+ x1 = x2;
+ x2 = x;
+ }
+
+ if (y1 > y2) {
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+
+ if (x1 < 0) {
+ x1 = 0;
+ }
+
+ if (x2 >= gdImageSX(im)) {
+ x2 = gdImageSX(im) - 1;
+ }
+
+ if (y1 < 0) {
+ y1 = 0;
+ }
+
+ if (y2 >= gdImageSY(im)) {
+ y2 = gdImageSY(im) - 1;
+ }
+
+ for (y = y1; (y <= y2); y++) {
+ for (x = x1; (x <= x2); x++) {
+ gdImageSetPixel (im, x, y, color);
+ }
+ }
+}
+
+/*
+ Function: gdImageFilledRectangle
+*/
+BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color)
+{
+ _gdImageFilledVRectangle(im, x1, y1, x2, y2, color);
+}
+
+/**
+ * Group: Cloning and Copying
+ */
+
+/**
+ * Function: gdImageClone
+ *
+ * Clones an image
+ *
+ * Creates an exact duplicate of the given image.
+ *
+ * Parameters:
+ * src - The source image.
+ *
+ * Returns:
+ * The cloned image on success, NULL on failure.
+ */
+BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src) {
+ gdImagePtr dst;
+ register int i, x;
+
+ if (src->trueColor) {
+ dst = gdImageCreateTrueColor(src->sx , src->sy);
+ } else {
+ dst = gdImageCreate(src->sx , src->sy);
+ }
+
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ if (src->trueColor == 0) {
+ dst->colorsTotal = src->colorsTotal;
+ for (i = 0; i < gdMaxColors; i++) {
+ dst->red[i] = src->red[i];
+ dst->green[i] = src->green[i];
+ dst->blue[i] = src->blue[i];
+ dst->alpha[i] = src->alpha[i];
+ dst->open[i] = src->open[i];
+ }
+ for (i = 0; i < src->sy; i++) {
+ for (x = 0; x < src->sx; x++) {
+ dst->pixels[i][x] = src->pixels[i][x];
+ }
+ }
+ } else {
+ for (i = 0; i < src->sy; i++) {
+ for (x = 0; x < src->sx; x++) {
+ dst->tpixels[i][x] = src->tpixels[i][x];
+ }
+ }
+ }
+
+ if (src->styleLength > 0) {
+ dst->styleLength = src->styleLength;
+ dst->stylePos = src->stylePos;
+ for (i = 0; i < src->styleLength; i++) {
+ dst->style[i] = src->style[i];
+ }
+ }
+
+ dst->interlace = src->interlace;
+
+ dst->alphaBlendingFlag = src->alphaBlendingFlag;
+ dst->saveAlphaFlag = src->saveAlphaFlag;
+ dst->AA = src->AA;
+ dst->AA_color = src->AA_color;
+ dst->AA_dont_blend = src->AA_dont_blend;
+
+ dst->cx1 = src->cx1;
+ dst->cy1 = src->cy1;
+ dst->cx2 = src->cx2;
+ dst->cy2 = src->cy2;
+
+ dst->res_x = src->res_x;
+ dst->res_y = src->res_y;
+
+ dst->paletteQuantizationMethod = src->paletteQuantizationMethod;
+ dst->paletteQuantizationSpeed = src->paletteQuantizationSpeed;
+ dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
+ dst->paletteQuantizationMinQuality = src->paletteQuantizationMinQuality;
+
+ dst->interpolation_id = src->interpolation_id;
+ dst->interpolation = src->interpolation;
+
+ if (src->brush) {
+ dst->brush = gdImageClone(src->brush);
+ }
+
+ if (src->tile) {
+ dst->tile = gdImageClone(src->tile);
+ }
+
+ if (src->style) {
+ gdImageSetStyle(dst, src->style, src->styleLength);
+ }
+
+ for (i = 0; i < gdMaxColors; i++) {
+ dst->brushColorMap[i] = src->brushColorMap[i];
+ dst->tileColorMap[i] = src->tileColorMap[i];
+ }
+
+ if (src->polyAllocated > 0) {
+ dst->polyAllocated = src->polyAllocated;
+ for (i = 0; i < src->polyAllocated; i++) {
+ dst->polyInts[i] = src->polyInts[i];
+ }
+ }
+
+ return dst;
+}
+
+/**
+ * Function: gdImageCopy
+ *
+ * Copy an area of an image to another image
+ *
+ * Parameters:
+ * dst - The destination image.
+ * src - The source image.
+ * dstX - The x-coordinate of the upper left corner to copy to.
+ * dstY - The y-coordinate of the upper left corner to copy to.
+ * srcX - The x-coordinate of the upper left corner to copy from.
+ * srcY - The y-coordinate of the upper left corner to copy from.
+ * w - The width of the area to copy.
+ * h - The height of the area to copy.
+ *
+ * See also:
+ * - <gdImageCopyMerge>
+ * - <gdImageCopyMergeGray>
+ */
+BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX,
+ int srcY, int w, int h)
+{
+ int c;
+ int x, y;
+ int tox, toy;
+ int i;
+ int colorMap[gdMaxColors];
+
+ if (dst->trueColor) {
+ /* 2.0: much easier when the destination is truecolor. */
+ /* 2.0.10: needs a transparent-index check that is still valid if
+ * * the source is not truecolor. Thanks to Frank Warmerdam.
+ */
+
+ if (src->trueColor) {
+ for (y = 0; (y < h); y++) {
+ for (x = 0; (x < w); x++) {
+ int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
+ if (c != src->transparent) {
+ gdImageSetPixel (dst, dstX + x, dstY + y, c);
+ }
+ }
+ }
+ } else {
+ /* source is palette based */
+ for (y = 0; (y < h); y++) {
+ for (x = 0; (x < w); x++) {
+ int c = gdImageGetPixel (src, srcX + x, srcY + y);
+ if (c != src->transparent) {
+ gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ for (i = 0; (i < gdMaxColors); i++) {
+ colorMap[i] = (-1);
+ }
+ toy = dstY;
+ for (y = srcY; (y < (srcY + h)); y++) {
+ tox = dstX;
+ for (x = srcX; (x < (srcX + w)); x++) {
+ int nc;
+ int mapTo;
+ c = gdImageGetPixel (src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent (src) == c) {
+ tox++;
+ continue;
+ }
+ /* Have we established a mapping for this color? */
+ if (src->trueColor) {
+ /* 2.05: remap to the palette available in the
+ destination image. This is slow and
+ works badly, but it beats crashing! Thanks
+ to Padhrig McCarthy. */
+ mapTo = gdImageColorResolveAlpha (dst,
+ gdTrueColorGetRed (c),
+ gdTrueColorGetGreen (c),
+ gdTrueColorGetBlue (c),
+ gdTrueColorGetAlpha (c));
+ } else if (colorMap[c] == (-1)) {
+ /* If it's the same image, mapping is trivial */
+ if (dst == src) {
+ nc = c;
+ } else {
+ /* Get best match possible. This
+ function never returns error. */
+ nc = gdImageColorResolveAlpha (dst,
+ src->red[c], src->green[c],
+ src->blue[c], src->alpha[c]);
+ }
+ colorMap[c] = nc;
+ mapTo = colorMap[c];
+ } else {
+ mapTo = colorMap[c];
+ }
+ gdImageSetPixel (dst, tox, toy, mapTo);
+ tox++;
+ }
+ toy++;
+ }
+}
+
+/**
+ * Function: gdImageCopyMerge
+ *
+ * Copy an area of an image to another image ignoring alpha
+ *
+ * The source area will be copied to the destination are by merging the pixels.
+ *
+ * Note:
+ * This function is a substitute for real alpha channel operations,
+ * so it doesn't pay attention to the alpha channel.
+ *
+ * Parameters:
+ * dst - The destination image.
+ * src - The source image.
+ * dstX - The x-coordinate of the upper left corner to copy to.
+ * dstY - The y-coordinate of the upper left corner to copy to.
+ * srcX - The x-coordinate of the upper left corner to copy from.
+ * srcY - The y-coordinate of the upper left corner to copy from.
+ * w - The width of the area to copy.
+ * h - The height of the area to copy.
+ * pct - The percentage in range 0..100.
+ *
+ * See also:
+ * - <gdImageCopy>
+ * - <gdImageCopyMergeGray>
+ */
+BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
+ int srcX, int srcY, int w, int h, int pct)
+{
+
+ int c, dc;
+ int x, y;
+ int tox, toy;
+ int ncR, ncG, ncB;
+ toy = dstY;
+ for (y = srcY; (y < (srcY + h)); y++) {
+ tox = dstX;
+ for (x = srcX; (x < (srcX + w)); x++) {
+ int nc;
+ c = gdImageGetPixel (src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent (src) == c) {
+ tox++;
+ continue;
+ }
+ /* If it's the same image, mapping is trivial */
+ if (dst == src) {
+ nc = c;
+ } else {
+ dc = gdImageGetPixel (dst, tox, toy);
+
+ ncR = gdImageRed (src, c) * (pct / 100.0)
+ + gdImageRed (dst, dc) * ((100 - pct) / 100.0);
+ ncG = gdImageGreen (src, c) * (pct / 100.0)
+ + gdImageGreen (dst, dc) * ((100 - pct) / 100.0);
+ ncB = gdImageBlue (src, c) * (pct / 100.0)
+ + gdImageBlue (dst, dc) * ((100 - pct) / 100.0);
+
+ /* Find a reasonable color */
+ nc = gdImageColorResolve (dst, ncR, ncG, ncB);
+ }
+ gdImageSetPixel (dst, tox, toy, nc);
+ tox++;
+ }
+ toy++;
+ }
+}
+
+/**
+ * Function: gdImageCopyMergeGray
+ *
+ * Copy an area of an image to another image ignoring alpha
+ *
+ * The source area will be copied to the grayscaled destination area by merging
+ * the pixels.
+ *
+ * Note:
+ * This function is a substitute for real alpha channel operations,
+ * so it doesn't pay attention to the alpha channel.
+ *
+ * Parameters:
+ * dst - The destination image.
+ * src - The source image.
+ * dstX - The x-coordinate of the upper left corner to copy to.
+ * dstY - The y-coordinate of the upper left corner to copy to.
+ * srcX - The x-coordinate of the upper left corner to copy from.
+ * srcY - The y-coordinate of the upper left corner to copy from.
+ * w - The width of the area to copy.
+ * h - The height of the area to copy.
+ * pct - The percentage of the source color intensity in range 0..100.
+ *
+ * See also:
+ * - <gdImageCopy>
+ * - <gdImageCopyMerge>
+ */
+BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
+ int srcX, int srcY, int w, int h, int pct)
+{
+
+ int c, dc;
+ int x, y;
+ int tox, toy;
+ int ncR, ncG, ncB;
+ float g;
+ toy = dstY;
+ for (y = srcY; (y < (srcY + h)); y++) {
+ tox = dstX;
+ for (x = srcX; (x < (srcX + w)); x++) {
+ int nc;
+ c = gdImageGetPixel (src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent (src) == c) {
+ tox++;
+ continue;
+ }
+ /*
+ * If it's the same image, mapping is NOT trivial since we
+ * merge with greyscale target, but if pct is 100, the grey
+ * value is not used, so it becomes trivial. pjw 2.0.12.
+ */
+ if (dst == src && pct == 100) {
+ nc = c;
+ } else {
+ dc = gdImageGetPixel (dst, tox, toy);
+ g = 0.29900 * gdImageRed(dst, dc)
+ + 0.58700 * gdImageGreen(dst, dc) + 0.11400 * gdImageBlue(dst, dc);
+
+ ncR = gdImageRed (src, c) * (pct / 100.0)
+ + g * ((100 - pct) / 100.0);
+ ncG = gdImageGreen (src, c) * (pct / 100.0)
+ + g * ((100 - pct) / 100.0);
+ ncB = gdImageBlue (src, c) * (pct / 100.0)
+ + g * ((100 - pct) / 100.0);
+
+ /* First look for an exact match */
+ nc = gdImageColorExact (dst, ncR, ncG, ncB);
+ if (nc == (-1)) {
+ /* No, so try to allocate it */
+ nc = gdImageColorAllocate (dst, ncR, ncG, ncB);
+ /* If we're out of colors, go for the
+ closest color */
+ if (nc == (-1)) {
+ nc = gdImageColorClosest (dst, ncR, ncG, ncB);
+ }
+ }
+ }
+ gdImageSetPixel (dst, tox, toy, nc);
+ tox++;
+ }
+ toy++;
+ }
+}
+
+/**
+ * Function: gdImageCopyResized
+ *
+ * Copy a resized area from an image to another image
+ *
+ * If the source and destination area differ in size, the area will be resized
+ * using nearest-neighbor interpolation.
+ *
+ * Parameters:
+ * dst - The destination image.
+ * src - The source image.
+ * dstX - The x-coordinate of the upper left corner to copy to.
+ * dstY - The y-coordinate of the upper left corner to copy to.
+ * srcX - The x-coordinate of the upper left corner to copy from.
+ * srcY - The y-coordinate of the upper left corner to copy from.
+ * dstW - The width of the area to copy to.
+ * dstH - The height of the area to copy to.
+ * srcW - The width of the area to copy from.
+ * srcH - The height of the area to copy from.
+ *
+ * See also:
+ * - <gdImageCopyResampled>
+ * - <gdImageScale>
+ */
+BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
+ int srcX, int srcY, int dstW, int dstH, int srcW,
+ int srcH)
+{
+ int c;
+ int x, y;
+ int tox, toy;
+ int ydest;
+ int i;
+ int colorMap[gdMaxColors];
+ /* Stretch vectors */
+ int *stx;
+ int *sty;
+ /* We only need to use floating point to determine the correct
+ stretch vector for one line's worth. */
+ if (overflow2(sizeof (int), srcW)) {
+ return;
+ }
+ if (overflow2(sizeof (int), srcH)) {
+ return;
+ }
+ stx = (int *) gdMalloc (sizeof (int) * srcW);
+ if (!stx) {
+ return;
+ }
+
+ sty = (int *) gdMalloc (sizeof (int) * srcH);
+ if (!sty) {
+ gdFree(stx);
+ return;
+ }
+
+ /* Fixed by Mao Morimoto 2.0.16 */
+ for (i = 0; (i < srcW); i++) {
+ stx[i] = dstW * (i + 1) / srcW - dstW * i / srcW;
+ }
+ for (i = 0; (i < srcH); i++) {
+ sty[i] = dstH * (i + 1) / srcH - dstH * i / srcH;
+ }
+ for (i = 0; (i < gdMaxColors); i++) {
+ colorMap[i] = (-1);
+ }
+ toy = dstY;
+ for (y = srcY; (y < (srcY + srcH)); y++) {
+ for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
+ tox = dstX;
+ for (x = srcX; (x < (srcX + srcW)); x++) {
+ int nc = 0;
+ int mapTo;
+ if (!stx[x - srcX]) {
+ continue;
+ }
+ if (dst->trueColor) {
+ /* 2.0.9: Thorben Kundinger: Maybe the source image is not
+ a truecolor image */
+ if (!src->trueColor) {
+ int tmp = gdImageGetPixel (src, x, y);
+ mapTo = gdImageGetTrueColorPixel (src, x, y);
+ if (gdImageGetTransparent (src) == tmp) {
+ /* 2.0.21, TK: not tox++ */
+ tox += stx[x - srcX];
+ continue;
+ }
+ } else {
+ /* TK: old code follows */
+ mapTo = gdImageGetTrueColorPixel (src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent (src) == mapTo) {
+ /* 2.0.21, TK: not tox++ */
+ tox += stx[x - srcX];
+ continue;
+ }
+ }
+ } else {
+ c = gdImageGetPixel (src, x, y);
+ /* Added 7/24/95: support transparent copies */
+ if (gdImageGetTransparent (src) == c) {
+ tox += stx[x - srcX];
+ continue;
+ }
+ if (src->trueColor) {
+ /* Remap to the palette available in the
+ destination image. This is slow and
+ works badly. */
+ mapTo = gdImageColorResolveAlpha (dst,
+ gdTrueColorGetRed (c),
+ gdTrueColorGetGreen
+ (c),
+ gdTrueColorGetBlue
+ (c),
+ gdTrueColorGetAlpha
+ (c));
+ } else {
+ /* Have we established a mapping for this color? */
+ if (colorMap[c] == (-1)) {
+ /* If it's the same image, mapping is trivial */
+ if (dst == src) {
+ nc = c;
+ } else {
+ /* Find or create the best match */
+ /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
+ nc = gdImageColorResolveAlpha (dst,
+ gdImageRed (src,
+ c),
+ gdImageGreen
+ (src, c),
+ gdImageBlue (src,
+ c),
+ gdImageAlpha
+ (src, c));
+ }
+ colorMap[c] = nc;
+ }
+ mapTo = colorMap[c];
+ }
+ }
+ for (i = 0; (i < stx[x - srcX]); i++) {
+ gdImageSetPixel (dst, tox, toy, mapTo);
+ tox++;
+ }
+ }
+ toy++;
+ }
+ }
+ gdFree (stx);
+ gdFree (sty);
+}
+
+/**
+ * Function: gdImageCopyRotated
+ *
+ * Copy a rotated area from an image to another image
+ *
+ * The area is counter-clockwise rotated using nearest-neighbor interpolation.
+ *
+ * Parameters:
+ * dst - The destination image.
+ * src - The source image.
+ * dstX - The x-coordinate of the center of the area to copy to.
+ * dstY - The y-coordinate of the center of the area to copy to.
+ * srcX - The x-coordinate of the upper left corner to copy from.
+ * srcY - The y-coordinate of the upper left corner to copy from.
+ * srcW - The width of the area to copy from.
+ * srcH - The height of the area to copy from.
+ * angle - The angle in degrees.
+ *
+ * See also:
+ * - <gdImageRotateInterpolated>
+ */
+BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst,
+ gdImagePtr src,
+ double dstX, double dstY,
+ int srcX, int srcY,
+ int srcWidth, int srcHeight, int angle)
+{
+ double dx, dy;
+ double radius = sqrt (srcWidth * srcWidth + srcHeight * srcHeight);
+ double aCos = cos (angle * .0174532925);
+ double aSin = sin (angle * .0174532925);
+ double scX = srcX + ((double) srcWidth) / 2;
+ double scY = srcY + ((double) srcHeight) / 2;
+ int cmap[gdMaxColors];
+ int i;
+
+ /*
+ 2.0.34: transparency preservation. The transparentness of
+ the transparent color is more important than its hue.
+ */
+ if (src->transparent != -1) {
+ if (dst->transparent == -1) {
+ dst->transparent = src->transparent;
+ }
+ }
+
+ for (i = 0; (i < gdMaxColors); i++) {
+ cmap[i] = (-1);
+ }
+ for (dy = dstY - radius; (dy <= dstY + radius); dy++) {
+ for (dx = dstX - radius; (dx <= dstX + radius); dx++) {
+ double sxd = (dx - dstX) * aCos - (dy - dstY) * aSin;
+ double syd = (dy - dstY) * aCos + (dx - dstX) * aSin;
+ int sx = sxd + scX;
+ int sy = syd + scY;
+ if ((sx >= srcX) && (sx < srcX + srcWidth) &&
+ (sy >= srcY) && (sy < srcY + srcHeight)) {
+ int c = gdImageGetPixel (src, sx, sy);
+ /* 2.0.34: transparency wins */
+ if (c == src->transparent) {
+ gdImageSetPixel (dst, dx, dy, dst->transparent);
+ } else if (!src->trueColor) {
+ /* Use a table to avoid an expensive
+ lookup on every single pixel */
+ if (cmap[c] == -1) {
+ cmap[c] = gdImageColorResolveAlpha (dst,
+ gdImageRed (src, c),
+ gdImageGreen (src,
+ c),
+ gdImageBlue (src,
+ c),
+ gdImageAlpha (src,
+ c));
+ }
+ gdImageSetPixel (dst, dx, dy, cmap[c]);
+ } else {
+ gdImageSetPixel (dst,
+ dx, dy,
+ gdImageColorResolveAlpha (dst,
+ gdImageRed (src,
+ c),
+ gdImageGreen
+ (src, c),
+ gdImageBlue (src,
+ c),
+ gdImageAlpha
+ (src, c)));
+ }
+ }
+ }
+ }
+}
+
+/* When gd 1.x was first created, floating point was to be avoided.
+ These days it is often faster than table lookups or integer
+ arithmetic. The routine below is shamelessly, gloriously
+ floating point. TBB */
+
+/* 2.0.10: cast instead of floor() yields 35% performance improvement.
+ Thanks to John Buckman. */
+
+#define floor2(exp) ((long) exp)
+/*#define floor2(exp) floor(exp)*/
+
+/**
+ * Function: gdImageCopyResampled
+ *
+ * Copy a resampled area from an image to another image
+ *
+ * If the source and destination area differ in size, the area will be resized
+ * using bilinear interpolation for truecolor images, and nearest-neighbor
+ * interpolation for palette images.
+ *
+ * Parameters:
+ * dst - The destination image.
+ * src - The source image.
+ * dstX - The x-coordinate of the upper left corner to copy to.
+ * dstY - The y-coordinate of the upper left corner to copy to.
+ * srcX - The x-coordinate of the upper left corner to copy from.
+ * srcY - The y-coordinate of the upper left corner to copy from.
+ * dstW - The width of the area to copy to.
+ * dstH - The height of the area to copy to.
+ * srcW - The width of the area to copy from.
+ * srcH - The height of the area to copy from.
+ *
+ * See also:
+ * - <gdImageCopyResized>
+ * - <gdImageScale>
+ */
+BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst,
+ gdImagePtr src,
+ int dstX, int dstY,
+ int srcX, int srcY,
+ int dstW, int dstH, int srcW, int srcH)
+{
+ int x, y;
+ if (!dst->trueColor) {
+ gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
+ return;
+ }
+ for (y = dstY; (y < dstY + dstH); y++) {
+ for (x = dstX; (x < dstX + dstW); x++) {
+ float sy1, sy2, sx1, sx2;
+ float sx, sy;
+ float spixels = 0.0;
+ float red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
+ float alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
+ sy1 = ((float)(y - dstY)) * (float)srcH / (float)dstH;
+ sy2 = ((float)(y + 1 - dstY)) * (float) srcH / (float) dstH;
+ sy = sy1;
+ do {
+ float yportion;
+ if (floorf(sy) == floorf(sy1)) {
+ yportion = 1.0 - (sy - floorf(sy));
+ if (yportion > sy2 - sy1) {
+ yportion = sy2 - sy1;
+ }
+ sy = floorf(sy);
+ } else if (sy == floorf(sy2)) {
+ yportion = sy2 - floorf(sy2);
+ } else {
+ yportion = 1.0;
+ }
+ sx1 = ((float)(x - dstX)) * (float) srcW / dstW;
+ sx2 = ((float)(x + 1 - dstX)) * (float) srcW / dstW;
+ sx = sx1;
+ do {
+ float xportion;
+ float pcontribution;
+ int p;
+ if (floorf(sx) == floorf(sx1)) {
+ xportion = 1.0 - (sx - floorf(sx));
+ if (xportion > sx2 - sx1) {
+ xportion = sx2 - sx1;
+ }
+ sx = floorf(sx);
+ } else if (sx == floorf(sx2)) {
+ xportion = sx2 - floorf(sx2);
+ } else {
+ xportion = 1.0;
+ }
+ pcontribution = xportion * yportion;
+ p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
+
+ alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
+ red += gdTrueColorGetRed (p) * alpha_factor;
+ green += gdTrueColorGetGreen (p) * alpha_factor;
+ blue += gdTrueColorGetBlue (p) * alpha_factor;
+ alpha += gdTrueColorGetAlpha (p) * pcontribution;
+ alpha_sum += alpha_factor;
+ contrib_sum += pcontribution;
+ spixels += xportion * yportion;
+ sx += 1.0;
+ }
+ while (sx < sx2);
+ sy += 1.0f;
+ }
+ while (sy < sy2);
+
+ if (spixels != 0.0) {
+ red /= spixels;
+ green /= spixels;
+ blue /= spixels;
+ alpha /= spixels;
+ }
+ if ( alpha_sum != 0.0) {
+ if( contrib_sum != 0.0) {
+ alpha_sum /= contrib_sum;
+ }
+ red /= alpha_sum;
+ green /= alpha_sum;
+ blue /= alpha_sum;
+ }
+ /* Clamping to allow for rounding errors above */
+ if (red > 255.0) {
+ red = 255.0;
+ }
+ if (green > 255.0) {
+ green = 255.0;
+ }
+ if (blue > 255.0f) {
+ blue = 255.0;
+ }
+ if (alpha > gdAlphaMax) {
+ alpha = gdAlphaMax;
+ }
+ gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
+ }
+ }
+}
+
+/**
+ * Group: Polygons
+ */
+
+/**
+ * Function: gdImagePolygon
+ *
+ * Draws a closed polygon
+ *
+ * Parameters:
+ * im - The image.
+ * p - The vertices as array of <gdPoint>s.
+ * n - The number of vertices.
+ * c - The color.
+ *
+ * See also:
+ * - <gdImageOpenPolygon>
+ * - <gdImageFilledPolygon>
+ */
+BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
+{
+ if (n <= 0) {
+ return;
+ }
+
+
+ gdImageLine (im, p->x, p->y, p[n - 1].x, p[n - 1].y, c);
+ gdImageOpenPolygon (im, p, n, c);
+}
+
+/**
+ * Function: gdImageOpenPolygon
+ *
+ * Draws an open polygon
+ *
+ * Parameters:
+ * im - The image.
+ * p - The vertices as array of <gdPoint>s.
+ * n - The number of vertices.
+ * c - The color
+ *
+ * See also:
+ * - <gdImagePolygon>
+ */
+BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
+{
+ int i;
+ int lx, ly;
+ if (n <= 0) {
+ return;
+ }
+
+
+ lx = p->x;
+ ly = p->y;
+ for (i = 1; (i < n); i++) {
+ p++;
+ gdImageLine (im, lx, ly, p->x, p->y, c);
+ lx = p->x;
+ ly = p->y;
+ }
+
+}
+
+/* THANKS to Kirsten Schulz for the polygon fixes! */
+
+/* The intersection finding technique of this code could be improved */
+/* by remembering the previous intertersection, and by using the slope. */
+/* That could help to adjust intersections to produce a nice */
+/* interior_extrema. */
+
+/**
+ * Function: gdImageFilledPolygon
+ *
+ * Draws a filled polygon
+ *
+ * The polygon is filled using the even-odd fillrule what can leave unfilled
+ * regions inside of self-intersecting polygons. This behavior might change in
+ * a future version.
+ *
+ * Parameters:
+ * im - The image.
+ * p - The vertices as array of <gdPoint>s.
+ * n - The number of vertices.
+ * c - The color
+ *
+ * See also:
+ * - <gdImagePolygon>
+ */
+BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
+{
+ int i;
+ int j;
+ int index;
+ int y;
+ int miny, maxy, pmaxy;
+ int x1, y1;
+ int x2, y2;
+ int ind1, ind2;
+ int ints;
+ int fill_color;
+ if (n <= 0) {
+ return;
+ }
+
+ if (c == gdAntiAliased) {
+ fill_color = im->AA_color;
+ } else {
+ fill_color = c;
+ }
+ if (!im->polyAllocated) {
+ if (overflow2(sizeof (int), n)) {
+ return;
+ }
+ im->polyInts = (int *) gdMalloc (sizeof (int) * n);
+ if (!im->polyInts) {
+ return;
+ }
+ im->polyAllocated = n;
+ }
+ if (im->polyAllocated < n) {
+ while (im->polyAllocated < n) {
+ im->polyAllocated *= 2;
+ }
+ if (overflow2(sizeof (int), im->polyAllocated)) {
+ return;
+ }
+ im->polyInts = (int *) gdReallocEx (im->polyInts,
+ sizeof (int) * im->polyAllocated);
+ if (!im->polyInts) {
+ return;
+ }
+ }
+ miny = p[0].y;
+ maxy = p[0].y;
+ for (i = 1; (i < n); i++) {
+ if (p[i].y < miny) {
+ miny = p[i].y;
+ }
+ if (p[i].y > maxy) {
+ maxy = p[i].y;
+ }
+ }
+ /* necessary special case: horizontal line */
+ if (n > 1 && miny == maxy) {
+ x1 = x2 = p[0].x;
+ for (i = 1; (i < n); i++) {
+ if (p[i].x < x1) {
+ x1 = p[i].x;
+ } else if (p[i].x > x2) {
+ x2 = p[i].x;
+ }
+ }
+ gdImageLine(im, x1, miny, x2, miny, c);
+ return;
+ }
+ pmaxy = maxy;
+ /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
+ /* 2.0.26: clipping rectangle is even better */
+ if (miny < im->cy1) {
+ miny = im->cy1;
+ }
+ if (maxy > im->cy2) {
+ maxy = im->cy2;
+ }
+ /* Fix in 1.3: count a vertex only once */
+ for (y = miny; (y <= maxy); y++) {
+ ints = 0;
+ for (i = 0; (i < n); i++) {
+ if (!i) {
+ ind1 = n - 1;
+ ind2 = 0;
+ } else {
+ ind1 = i - 1;
+ ind2 = i;
+ }
+ y1 = p[ind1].y;
+ y2 = p[ind2].y;
+ if (y1 < y2) {
+ x1 = p[ind1].x;
+ x2 = p[ind2].x;
+ } else if (y1 > y2) {
+ y2 = p[ind1].y;
+ y1 = p[ind2].y;
+ x2 = p[ind1].x;
+ x1 = p[ind2].x;
+ } else {
+ continue;
+ }
+
+ /* Do the following math as float intermediately, and round to ensure
+ * that Polygon and FilledPolygon for the same set of points have the
+ * same footprint. */
+
+ if ((y >= y1) && (y < y2)) {
+ im->polyInts[ints++] = (int) ((float) ((y - y1) * (x2 - x1)) /
+ (float) (y2 - y1) + 0.5 + x1);
+ } else if ((y == pmaxy) && (y == y2)) {
+ im->polyInts[ints++] = x2;
+ }
+ }
+ /*
+ 2.0.26: polygons pretty much always have less than 100 points,
+ and most of the time they have considerably less. For such trivial
+ cases, insertion sort is a good choice. Also a good choice for
+ future implementations that may wish to indirect through a table.
+ */
+ for (i = 1; (i < ints); i++) {
+ index = im->polyInts[i];
+ j = i;
+ while ((j > 0) && (im->polyInts[j - 1] > index)) {
+ im->polyInts[j] = im->polyInts[j - 1];
+ j--;
+ }
+ im->polyInts[j] = index;
+ }
+ for (i = 0; (i < (ints-1)); i += 2) {
+ /* 2.0.29: back to gdImageLine to prevent segfaults when
+ performing a pattern fill */
+ gdImageLine (im, im->polyInts[i], y, im->polyInts[i + 1], y,
+ fill_color);
+ }
+ }
+ /* If we are drawing this AA, then redraw the border with AA lines. */
+ /* This doesn't work as well as I'd like, but it doesn't clash either. */
+ if (c == gdAntiAliased) {
+ gdImagePolygon (im, p, n, c);
+ }
+}
+
+/**
+ * Group: other
+ */
+
+static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t);
+
+/**
+ * Function: gdImageSetStyle
+ *
+ * Sets the style for following drawing operations
+ *
+ * Parameters:
+ * im - The image.
+ * style - An array of color values.
+ * noOfPixel - The number of color values.
+ */
+BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
+{
+ if (im->style) {
+ gdFree (im->style);
+ }
+ if (overflow2(sizeof (int), noOfPixels)) {
+ return;
+ }
+ im->style = (int *) gdMalloc (sizeof (int) * noOfPixels);
+ if (!im->style) {
+ return;
+ }
+ memcpy (im->style, style, sizeof (int) * noOfPixels);
+ im->styleLength = noOfPixels;
+ im->stylePos = 0;
+}
+
+/**
+ * Function: gdImageSetThickness
+ *
+ * Sets the thickness for following drawing operations
+ *
+ * Parameters:
+ * im - The image.
+ * thickness - The thickness in pixels.
+ */
+BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness)
+{
+ im->thick = thickness;
+}
+
+/**
+ * Function: gdImageSetBrush
+ *
+ * Sets the brush for following drawing operations
+ *
+ * Parameters:
+ * im - The image.
+ * brush - The brush image.
+ */
+BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
+{
+ int i;
+ im->brush = brush;
+ if ((!im->trueColor) && (!im->brush->trueColor)) {
+ for (i = 0; (i < gdImageColorsTotal (brush)); i++) {
+ int index;
+ index = gdImageColorResolveAlpha (im,
+ gdImageRed (brush, i),
+ gdImageGreen (brush, i),
+ gdImageBlue (brush, i),
+ gdImageAlpha (brush, i));
+ im->brushColorMap[i] = index;
+ }
+ }
+}
+
+/*
+ Function: gdImageSetTile
+*/
+BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile)
+{
+ int i;
+ im->tile = tile;
+ if ((!im->trueColor) && (!im->tile->trueColor)) {
+ for (i = 0; (i < gdImageColorsTotal (tile)); i++) {
+ int index;
+ index = gdImageColorResolveAlpha (im,
+ gdImageRed (tile, i),
+ gdImageGreen (tile, i),
+ gdImageBlue (tile, i),
+ gdImageAlpha (tile, i));
+ im->tileColorMap[i] = index;
+ }
+ }
+}
+
+/**
+ * Function: gdImageSetAntiAliased
+ *
+ * Set the color for subsequent anti-aliased drawing
+ *
+ * If <gdAntiAliased> is passed as color to drawing operations that support
+ * anti-aliased drawing (such as <gdImageLine> and <gdImagePolygon>), the actual
+ * color to be used can be set with this function.
+ *
+ * Example: draw an anti-aliased blue line:
+ * | gdImageSetAntiAliased(im, gdTrueColorAlpha(0, 0, gdBlueMax, gdAlphaOpaque));
+ * | gdImageLine(im, 10,10, 20,20, gdAntiAliased);
+ *
+ * Parameters:
+ * im - The image.
+ * c - The color.
+ *
+ * See also:
+ * - <gdImageSetAntiAliasedDontBlend>
+ */
+BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c)
+{
+ im->AA = 1;
+ im->AA_color = c;
+ im->AA_dont_blend = -1;
+}
+
+/**
+ * Function: gdImageSetAntiAliasedDontBlend
+ *
+ * Set the color and "dont_blend" color for subsequent anti-aliased drawing
+ *
+ * This extended variant of <gdImageSetAntiAliased> allows to also specify a
+ * (background) color that will not be blended in anti-aliased drawing
+ * operations.
+ *
+ * Parameters:
+ * im - The image.
+ * c - The color.
+ * dont_blend - Whether to blend.
+ */
+BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
+{
+ im->AA = 1;
+ im->AA_color = c;
+ im->AA_dont_blend = dont_blend;
+}
+
+/**
+ * Function: gdImageInterlace
+ *
+ * Sets whether an image is interlaced
+ *
+ * This is relevant only when saving the image in a format that supports
+ * interlacing.
+ *
+ * Parameters:
+ * im - The image.
+ * interlaceArg - Whether the image is interlaced.
+ *
+ * See also:
+ * - <gdImageGetInterlaced>
+*/
+BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg)
+{
+ im->interlace = interlaceArg;
+}
+
+/**
+ * Function: gdImageCompare
+ *
+ * Compare two images
+ *
+ * Parameters:
+ * im1 - An image.
+ * im2 - Another image.
+ *
+ * Returns:
+ * A bitmask of <Image Comparison> flags where each set flag signals
+ * which attributes of the images are different.
+ */
+BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2)
+{
+ int x, y;
+ int p1, p2;
+ int cmpStatus = 0;
+ int sx, sy;
+
+ if (im1->interlace != im2->interlace) {
+ cmpStatus |= GD_CMP_INTERLACE;
+ }
+
+ if (im1->transparent != im2->transparent) {
+ cmpStatus |= GD_CMP_TRANSPARENT;
+ }
+
+ if (im1->trueColor != im2->trueColor) {
+ cmpStatus |= GD_CMP_TRUECOLOR;
+ }
+
+ sx = im1->sx;
+ if (im1->sx != im2->sx) {
+ cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
+ if (im2->sx < im1->sx) {
+ sx = im2->sx;
+ }
+ }
+
+ sy = im1->sy;
+ if (im1->sy != im2->sy) {
+ cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
+ if (im2->sy < im1->sy) {
+ sy = im2->sy;
+ }
+ }
+
+ if (im1->colorsTotal != im2->colorsTotal) {
+ cmpStatus |= GD_CMP_NUM_COLORS;
+ }
+
+ for (y = 0; (y < sy); y++) {
+ for (x = 0; (x < sx); x++) {
+ p1 =
+ im1->trueColor ? gdImageTrueColorPixel (im1, x,
+ y) :
+ gdImagePalettePixel (im1, x, y);
+ p2 =
+ im2->trueColor ? gdImageTrueColorPixel (im2, x,
+ y) :
+ gdImagePalettePixel (im2, x, y);
+ if (gdImageRed (im1, p1) != gdImageRed (im2, p2)) {
+ cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+ break;
+ }
+ if (gdImageGreen (im1, p1) != gdImageGreen (im2, p2)) {
+ cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+ break;
+ }
+ if (gdImageBlue (im1, p1) != gdImageBlue (im2, p2)) {
+ cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+ break;
+ }
+#if 0
+ /* Soon we'll add alpha channel to palettes */
+ if (gdImageAlpha (im1, p1) != gdImageAlpha (im2, p2)) {
+ cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
+ break;
+ }
+#endif
+ }
+ if (cmpStatus & GD_CMP_COLOR) {
+ break;
+ };
+ }
+
+ return cmpStatus;
+}
+
+
+/* Thanks to Frank Warmerdam for this superior implementation
+ of gdAlphaBlend(), which merges alpha in the
+ destination color much better. */
+
+/**
+ * Function: gdAlphaBlend
+ *
+ * Blend two colors
+ *
+ * Parameters:
+ * dst - The color to blend onto.
+ * src - The color to blend.
+ *
+ * See also:
+ * - <gdImageAlphaBlending>
+ * - <gdLayerOverlay>
+ * - <gdLayerMultiply>
+ */
+BGD_DECLARE(int) gdAlphaBlend (int dst, int src)
+{
+ int src_alpha = gdTrueColorGetAlpha(src);
+ int dst_alpha, alpha, red, green, blue;
+ int src_weight, dst_weight, tot_weight;
+
+ /* -------------------------------------------------------------------- */
+ /* Simple cases we want to handle fast. */
+ /* -------------------------------------------------------------------- */
+ if( src_alpha == gdAlphaOpaque )
+ return src;
+
+ dst_alpha = gdTrueColorGetAlpha(dst);
+ if( src_alpha == gdAlphaTransparent )
+ return dst;
+ if( dst_alpha == gdAlphaTransparent )
+ return src;
+
+ /* -------------------------------------------------------------------- */
+ /* What will the source and destination alphas be? Note that */
+ /* the destination weighting is substantially reduced as the */
+ /* overlay becomes quite opaque. */
+ /* -------------------------------------------------------------------- */
+ src_weight = gdAlphaTransparent - src_alpha;
+ dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
+ tot_weight = src_weight + dst_weight;
+
+ /* -------------------------------------------------------------------- */
+ /* What red, green and blue result values will we use? */
+ /* -------------------------------------------------------------------- */
+ alpha = src_alpha * dst_alpha / gdAlphaMax;
+
+ red = (gdTrueColorGetRed(src) * src_weight
+ + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
+ green = (gdTrueColorGetGreen(src) * src_weight
+ + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
+ blue = (gdTrueColorGetBlue(src) * src_weight
+ + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
+
+ /* -------------------------------------------------------------------- */
+ /* Return merged result. */
+ /* -------------------------------------------------------------------- */
+ return ((alpha << 24) + (red << 16) + (green << 8) + blue);
+}
+
+static int gdAlphaOverlayColor (int src, int dst, int max );
+
+/**
+ * Function: gdLayerOverlay
+ *
+ * Overlay two colors
+ *
+ * Parameters:
+ * dst - The color to overlay onto.
+ * src - The color to overlay.
+ *
+ * See also:
+ * - <gdImageAlphaBlending>
+ * - <gdAlphaBlend>
+ * - <gdLayerMultiply>
+ */
+BGD_DECLARE(int) gdLayerOverlay (int dst, int src)
+{
+ int a1, a2;
+ a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
+ a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
+ return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
+ (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
+ (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
+ (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
+ );
+}
+
+/* Apply 'overlay' effect - background pixels are colourised by the foreground colour */
+static int gdAlphaOverlayColor (int src, int dst, int max )
+{
+ dst = dst << 1;
+ if( dst > max ) {
+ /* in the "light" zone */
+ return dst + (src << 1) - (dst * src / max) - max;
+ } else {
+ /* in the "dark" zone */
+ return dst * src / max;
+ }
+}
+
+/**
+ * Function: gdLayerMultiply
+ *
+ * Overlay two colors with multiply effect
+ *
+ * Parameters:
+ * dst - The color to overlay onto.
+ * src - The color to overlay.
+ *
+ * See also:
+ * - <gdImageAlphaBlending>
+ * - <gdAlphaBlend>
+ * - <gdLayerOverlay>
+ */
+BGD_DECLARE(int) gdLayerMultiply (int dst, int src)
+{
+ int a1, a2, r1, r2, g1, g2, b1, b2;
+ a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
+ a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
+
+ r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
+ r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
+ g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
+ g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
+ b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
+ b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
+
+ a1 = gdAlphaMax - a1;
+ a2 = gdAlphaMax - a2;
+ return ( ((a1*a2/gdAlphaMax) << 24) +
+ ((r1*r2/gdRedMax) << 16) +
+ ((g1*g2/gdGreenMax) << 8) +
+ ((b1*b2/gdBlueMax))
+ );
+}
+
+/**
+ * Function: gdImageAlphaBlending
+ *
+ * Set the effect for subsequent drawing operations
+ *
+ * Note that the effect is used for truecolor images only.
+ *
+ * Parameters:
+ * im - The image.
+ * alphaBlendingArg - The effect.
+ *
+ * See also:
+ * - <Effects>
+ */
+BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
+{
+ im->alphaBlendingFlag = alphaBlendingArg;
+}
+
+/**
+ * Function: gdImageSaveAlpha
+ *
+ * Sets the save alpha flag
+ *
+ * The save alpha flag specifies whether the alpha channel of the pixels should
+ * be saved. This is supported only for image formats that support full alpha
+ * transparency, e.g. PNG.
+ */
+BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
+{
+ im->saveAlphaFlag = saveAlphaArg;
+}
+
+/**
+ * Function: gdImageSetClip
+ *
+ * Sets the clipping rectangle
+ *
+ * The clipping rectangle restricts the drawing area for following drawing
+ * operations.
+ *
+ * Parameters:
+ * im - The image.
+ * x1 - The x-coordinate of the upper left corner.
+ * y1 - The y-coordinate of the upper left corner.
+ * x2 - The x-coordinate of the lower right corner.
+ * y2 - The y-coordinate of the lower right corner.
+ *
+ * See also:
+ * - <gdImageGetClip>
+ */
+BGD_DECLARE(void) gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
+{
+ if (x1 < 0) {
+ x1 = 0;
+ }
+ if (x1 >= im->sx) {
+ x1 = im->sx - 1;
+ }
+ if (x2 < 0) {
+ x2 = 0;
+ }
+ if (x2 >= im->sx) {
+ x2 = im->sx - 1;
+ }
+ if (y1 < 0) {
+ y1 = 0;
+ }
+ if (y1 >= im->sy) {
+ y1 = im->sy - 1;
+ }
+ if (y2 < 0) {
+ y2 = 0;
+ }
+ if (y2 >= im->sy) {
+ y2 = im->sy - 1;
+ }
+ im->cx1 = x1;
+ im->cy1 = y1;
+ im->cx2 = x2;
+ im->cy2 = y2;
+}
+
+/**
+ * Function: gdImageGetClip
+ *
+ * Gets the current clipping rectangle
+ *
+ * Parameters:
+ * im - The image.
+ * x1P - (out) The x-coordinate of the upper left corner.
+ * y1P - (out) The y-coordinate of the upper left corner.
+ * x2P - (out) The x-coordinate of the lower right corner.
+ * y2P - (out) The y-coordinate of the lower right corner.
+ *
+ * See also:
+ * - <gdImageSetClip>
+ */
+BGD_DECLARE(void) gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
+{
+ *x1P = im->cx1;
+ *y1P = im->cy1;
+ *x2P = im->cx2;
+ *y2P = im->cy2;
+}
+
+/**
+ * Function: gdImageSetResolution
+ *
+ * Sets the resolution of an image.
+ *
+ * Parameters:
+ * im - The image.
+ * res_x - The horizontal resolution in DPI.
+ * res_y - The vertical resolution in DPI.
+ *
+ * See also:
+ * - <gdImageResolutionX>
+ * - <gdImageResolutionY>
+ */
+BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
+{
+ if (res_x > 0) im->res_x = res_x;
+ if (res_y > 0) im->res_y = res_y;
+}
+
+/*
+ * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
+ * */
+#define BLEND_COLOR(a, nc, c, cc) \
+nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
+
+static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
+{
+ int dr,dg,db,p,r,g,b;
+
+ /* 2.0.34: watch out for out of range calls */
+ if (!gdImageBoundsSafeMacro(im, x, y)) {
+ return;
+ }
+ p = gdImageGetPixel(im,x,y);
+ /* TBB: we have to implement the dont_blend stuff to provide
+ the full feature set of the old implementation */
+ if ((p == color)
+ || ((p == im->AA_dont_blend)
+ && (t != 0x00))) {
+ return;
+ }
+ dr = gdTrueColorGetRed(color);
+ dg = gdTrueColorGetGreen(color);
+ db = gdTrueColorGetBlue(color);
+
+ r = gdTrueColorGetRed(p);
+ g = gdTrueColorGetGreen(p);
+ b = gdTrueColorGetBlue(p);
+
+ BLEND_COLOR(t, dr, r, dr);
+ BLEND_COLOR(t, dg, g, dg);
+ BLEND_COLOR(t, db, b, db);
+ im->tpixels[y][x] = gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
+}
+
+static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
+{
+ /* keep them as 32bits */
+ long x, y, inc, frac;
+ long dx, dy,tmp;
+ int w, wid, wstart;
+ int thick = im->thick;
+
+ if (!im->trueColor) {
+ /* TBB: don't crash when the image is of the wrong type */
+ gdImageLine(im, x1, y1, x2, y2, col);
+ return;
+ }
+
+ /* TBB: use the clipping rectangle */
+ if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
+ return;
+ if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
+ return;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ if (dx == 0 && dy == 0) {
+ /* TBB: allow setting points */
+ gdImageSetAAPixelColor(im, x1, y1, col, 0xFF);
+ return;
+ } else {
+ double ag;
+ /* Cast the long to an int to avoid compiler warnings about truncation.
+ * This isn't a problem as computed dy/dx values came from ints above. */
+ ag = fabs(abs((int)dy) < abs((int)dx) ? cos(atan2(dy, dx)) : sin(atan2(dy, dx)));
+ if (ag != 0) {
+ wid = thick / ag;
+ } else {
+ wid = 1;
+ }
+ if (wid == 0) {
+ wid = 1;
+ }
+ }
+
+ /* Axis aligned lines */
+ if (dx == 0) {
+ gdImageVLine(im, x1, y1, y2, col);
+ return;
+ } else if (dy == 0) {
+ gdImageHLine(im, y1, x1, x2, col);
+ return;
+ }
+
+ if (abs((int)dx) > abs((int)dy)) {
+ if (dx < 0) {
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ tmp = y1;
+ y1 = y2;
+ y2 = tmp;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ }
+ y = y1;
+ inc = (dy * 65536) / dx;
+ frac = 0;
+ /* TBB: set the last pixel for consistency (<=) */
+ for (x = x1 ; x <= x2 ; x++) {
+ wstart = y - wid / 2;
+ for (w = wstart; w < wstart + wid; w++) {
+ gdImageSetAAPixelColor(im, x , w , col , (frac >> 8) & 0xFF);
+ gdImageSetAAPixelColor(im, x , w + 1 , col, (~frac >> 8) & 0xFF);
+ }
+ frac += inc;
+ if (frac >= 65536) {
+ frac -= 65536;
+ y++;
+ } else if (frac < 0) {
+ frac += 65536;
+ y--;
+ }
+ }
+ } else {
+ if (dy < 0) {
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
+ tmp = y1;
+ y1 = y2;
+ y2 = tmp;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ }
+ x = x1;
+ inc = (dx * 65536) / dy;
+ frac = 0;
+ /* TBB: set the last pixel for consistency (<=) */
+ for (y = y1 ; y <= y2 ; y++) {
+ wstart = x - wid / 2;
+ for (w = wstart; w < wstart + wid; w++) {
+ gdImageSetAAPixelColor(im, w , y , col, (frac >> 8) & 0xFF);
+ gdImageSetAAPixelColor(im, w + 1, y, col, (~frac >> 8) & 0xFF);
+ }
+ frac += inc;
+ if (frac >= 65536) {
+ frac -= 65536;
+ x++;
+ } else if (frac < 0) {
+ frac += 65536;
+ x--;
+ }
+ }
+ }
+}
+
+
+/**
+ * Function: gdImagePaletteToTrueColor
+ *
+ * Convert a palette image to true color
+ *
+ * Parameters:
+ * src - The image.
+ *
+ * Returns:
+ * Non-zero if the conversion succeeded, zero otherwise.
+ *
+ * See also:
+ * - <gdImageTrueColorToPalette>
+ */
+BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src)
+{
+ unsigned int y;
+ unsigned int yy;
+
+ if (src == NULL) {
+ return 0;
+ }
+
+ if (src->trueColor == 1) {
+ return 1;
+ } else {
+ unsigned int x;
+ const unsigned int sy = gdImageSY(src);
+ const unsigned int sx = gdImageSX(src);
+
+ src->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
+ if (src->tpixels == NULL) {
+ return 0;
+ }
+
+ for (y = 0; y < sy; y++) {
+ const unsigned char *src_row = src->pixels[y];
+ int * dst_row;
+
+ /* no need to calloc it, we overwrite all pxl anyway */
+ src->tpixels[y] = (int *) gdMalloc(sx * sizeof(int));
+ if (src->tpixels[y] == NULL) {
+ goto clean_on_error;
+ }
+
+ dst_row = src->tpixels[y];
+ for (x = 0; x < sx; x++) {
+ const unsigned char c = *(src_row + x);
+ if (c == src->transparent) {
+ *(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
+ } else {
+ *(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
+ }
+ }
+ }
+ }
+
+ /* free old palette buffer (y is sy) */
+ for (yy = 0; yy < y; yy++) {
+ gdFree(src->pixels[yy]);
+ }
+ gdFree(src->pixels);
+ src->trueColor = 1;
+ src->pixels = NULL;
+ src->alphaBlendingFlag = 0;
+ src->saveAlphaFlag = 1;
+
+ if (src->transparent >= 0) {
+ const unsigned char c = src->transparent;
+ src->transparent = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
+ }
+
+ return 1;
+
+clean_on_error:
+ /* free new true color buffer (y is not allocated, have failed) */
+ for (yy = 0; yy < y; yy++) {
+ gdFree(src->tpixels[yy]);
+ }
+ gdFree(src->tpixels);
+ return 0;
+}
diff --git a/libmscgen/gd.h b/libmscgen/gd.h
new file mode 100644
index 0000000..d6bbebd
--- /dev/null
+++ b/libmscgen/gd.h
@@ -0,0 +1,1620 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#ifndef GD_H
+#define GD_H 1
+
+/* Version information. This gets parsed by build scripts as well as
+ * gcc so each #define line in this group must also be splittable on
+ * whitespace, take the form GD_*_VERSION and contain the magical
+ * trailing comment. */
+#define GD_MAJOR_VERSION 2 /*version605b5d1778*/
+#define GD_MINOR_VERSION 2 /*version605b5d1778*/
+#define GD_RELEASE_VERSION 4 /*version605b5d1778*/
+#define GD_EXTRA_VERSION "" /*version605b5d1778*/
+/* End parsable section. */
+
+/* The version string. This is constructed from the version number
+ * parts above via macro abuse^Wtrickery. */
+#define GDXXX_VERSION_STR(mjr, mnr, rev, ext) mjr "." mnr "." rev ext
+#define GDXXX_STR(s) GDXXX_SSTR(s) /* Two levels needed to expand args. */
+#define GDXXX_SSTR(s) #s
+
+#define GD_VERSION_STRING \
+ GDXXX_VERSION_STR(GDXXX_STR(GD_MAJOR_VERSION), \
+ GDXXX_STR(GD_MINOR_VERSION), \
+ GDXXX_STR(GD_RELEASE_VERSION), \
+ GD_EXTRA_VERSION)
+
+
+/* Do the DLL dance: dllexport when building the DLL,
+ dllimport when importing from it, nothing when
+ not on Silly Silly Windows (tm Aardman Productions). */
+
+/* 2.0.20: for headers */
+
+/* 2.0.24: __stdcall also needed for Visual BASIC
+ and other languages. This breaks ABI compatibility
+ with previous DLL revs, but it's necessary. */
+
+/* 2.0.29: WIN32 programmers can declare the NONDLL macro if they
+ wish to build gd as a static library or by directly including
+ the gd sources in a project. */
+
+/* http://gcc.gnu.org/wiki/Visibility */
+
+#define BGD_EXPORT_DATA_PROT
+#define BGD_DECLARE(rt) rt
+
+/* VS2012+ disable keyword macroizing unless _ALLOW_KEYWORD_MACROS is set
+ We define inline, snprintf, and strcasecmp if they're missing
+*/
+#ifdef _MSC_VER
+# define _ALLOW_KEYWORD_MACROS
+# ifndef inline
+# define inline __inline
+# endif
+# ifndef strcasecmp
+# define strcasecmp _stricmp
+# endif
+#if _MSC_VER < 1900
+ extern int snprintf(char*, size_t, const char*, ...);
+#endif
+#endif
+
+#ifdef __cplusplus
+ extern "C"
+ {
+#endif
+
+/* gd.h: declarations file for the graphic-draw module.
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "AS IS." Thomas Boutell and
+ * Boutell.Com, Inc. disclaim all warranties, either express or implied,
+ * including but not limited to implied warranties of merchantability and
+ * fitness for a particular purpose, with respect to this code and accompanying
+ * documentation. */
+
+/* stdio is needed for file I/O. */
+#include <stdio.h>
+#include <stdarg.h>
+//#include "gd_io.h"
+
+/* The maximum number of palette entries in palette-based images.
+ In the wonderful new world of gd 2.0, you can of course have
+ many more colors when using truecolor mode. */
+
+#define gdMaxColors 256
+
+/* Image type. See functions below; you will not need to change
+ the elements directly. Use the provided macros to
+ access sx, sy, the color table, and colorsTotal for
+ read-only purposes. */
+
+/* If 'truecolor' is set true, the image is truecolor;
+ pixels are represented by integers, which
+ must be 32 bits wide or more.
+
+ True colors are repsented as follows:
+
+ ARGB
+
+ Where 'A' (alpha channel) occupies only the
+ LOWER 7 BITS of the MSB. This very small
+ loss of alpha channel resolution allows gd 2.x
+ to keep backwards compatibility by allowing
+ signed integers to be used to represent colors,
+ and negative numbers to represent special cases,
+ just as in gd 1.x. */
+
+#define gdAlphaMax 127
+#define gdAlphaOpaque 0
+#define gdAlphaTransparent 127
+#define gdRedMax 255
+#define gdGreenMax 255
+#define gdBlueMax 255
+
+/**
+ * Group: Color Decomposition
+ */
+
+/**
+ * Macro: gdTrueColorGetAlpha
+ *
+ * Gets the alpha channel value
+ *
+ * Parameters:
+ * c - The color
+ *
+ * See also:
+ * - <gdTrueColorAlpha>
+ */
+#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24)
+
+/**
+ * Macro: gdTrueColorGetRed
+ *
+ * Gets the red channel value
+ *
+ * Parameters:
+ * c - The color
+ *
+ * See also:
+ * - <gdTrueColorAlpha>
+ */
+#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16)
+
+/**
+ * Macro: gdTrueColorGetGreen
+ *
+ * Gets the green channel value
+ *
+ * Parameters:
+ * c - The color
+ *
+ * See also:
+ * - <gdTrueColorAlpha>
+ */
+#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8)
+
+/**
+ * Macro: gdTrueColorGetBlue
+ *
+ * Gets the blue channel value
+ *
+ * Parameters:
+ * c - The color
+ *
+ * See also:
+ * - <gdTrueColorAlpha>
+ */
+#define gdTrueColorGetBlue(c) ((c) & 0x0000FF)
+
+/**
+ * Group: Effects
+ *
+ * The layering effect
+ *
+ * When pixels are drawn the new colors are "mixed" with the background
+ * depending on the effect.
+ *
+ * Note that the effect does not apply to palette images, where pixels
+ * are always replaced.
+ *
+ * Modes:
+ * gdEffectReplace - replace pixels
+ * gdEffectAlphaBlend - blend pixels, see <gdAlphaBlend>
+ * gdEffectNormal - default mode; same as gdEffectAlphaBlend
+ * gdEffectOverlay - overlay pixels, see <gdLayerOverlay>
+ * gdEffectMultiply - overlay pixels with multiply effect, see
+ * <gdLayerMultiply>
+ *
+ * See also:
+ * - <gdImageAlphaBlending>
+ */
+#define gdEffectReplace 0
+#define gdEffectAlphaBlend 1
+#define gdEffectNormal 2
+#define gdEffectOverlay 3
+#define gdEffectMultiply 4
+
+#define GD_TRUE 1
+#define GD_FALSE 0
+
+#define GD_EPSILON 1e-6
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+/* This function accepts truecolor pixel values only. The
+ source color is composited with the destination color
+ based on the alpha channel value of the source color.
+ The resulting color is opaque. */
+
+BGD_DECLARE(int) gdAlphaBlend (int dest, int src);
+BGD_DECLARE(int) gdLayerOverlay (int dest, int src);
+BGD_DECLARE(int) gdLayerMultiply (int dest, int src);
+
+
+/**
+ * Group: Color Quantization
+ *
+ * Enum: gdPaletteQuantizationMethod
+ *
+ * Constants:
+ * GD_QUANT_DEFAULT - GD_QUANT_LIQ if libimagequant is available,
+ * GD_QUANT_JQUANT otherwise.
+ * GD_QUANT_JQUANT - libjpeg's old median cut. Fast, but only uses 16-bit
+ * color.
+ * GD_QUANT_NEUQUANT - NeuQuant - approximation using Kohonen neural network.
+ * GD_QUANT_LIQ - A combination of algorithms used in libimagequant
+ * aiming for the highest quality at cost of speed.
+ *
+ * Note that GD_QUANT_JQUANT does not retain the alpha channel, and
+ * GD_QUANT_NEUQUANT does not support dithering.
+ *
+ * See also:
+ * - <gdImageTrueColorToPaletteSetMethod>
+ */
+enum gdPaletteQuantizationMethod {
+ GD_QUANT_DEFAULT = 0,
+ GD_QUANT_JQUANT = 1,
+ GD_QUANT_NEUQUANT = 2,
+ GD_QUANT_LIQ = 3
+};
+
+
+/**
+ * Group: Transform
+ *
+ * Constants: gdInterpolationMethod
+ *
+ * GD_BELL - Bell
+ * GD_BESSEL - Bessel
+ * GD_BILINEAR_FIXED - fixed point bilinear
+ * GD_BICUBIC - Bicubic
+ * GD_BICUBIC_FIXED - fixed point bicubic integer
+ * GD_BLACKMAN - Blackman
+ * GD_BOX - Box
+ * GD_BSPLINE - BSpline
+ * GD_CATMULLROM - Catmullrom
+ * GD_GAUSSIAN - Gaussian
+ * GD_GENERALIZED_CUBIC - Generalized cubic
+ * GD_HERMITE - Hermite
+ * GD_HAMMING - Hamming
+ * GD_HANNING - Hannig
+ * GD_MITCHELL - Mitchell
+ * GD_NEAREST_NEIGHBOUR - Nearest neighbour interpolation
+ * GD_POWER - Power
+ * GD_QUADRATIC - Quadratic
+ * GD_SINC - Sinc
+ * GD_TRIANGLE - Triangle
+ * GD_WEIGHTED4 - 4 pixels weighted bilinear interpolation
+ * GD_LINEAR - bilinear interpolation
+ *
+ * See also:
+ * - <gdImageSetInterpolationMethod>
+ * - <gdImageGetInterpolationMethod>
+ */
+typedef enum {
+ GD_DEFAULT = 0,
+ GD_BELL,
+ GD_BESSEL,
+ GD_BILINEAR_FIXED,
+ GD_BICUBIC,
+ GD_BICUBIC_FIXED,
+ GD_BLACKMAN,
+ GD_BOX,
+ GD_BSPLINE,
+ GD_CATMULLROM,
+ GD_GAUSSIAN,
+ GD_GENERALIZED_CUBIC,
+ GD_HERMITE,
+ GD_HAMMING,
+ GD_HANNING,
+ GD_MITCHELL,
+ GD_NEAREST_NEIGHBOUR,
+ GD_POWER,
+ GD_QUADRATIC,
+ GD_SINC,
+ GD_TRIANGLE,
+ GD_WEIGHTED4,
+ GD_LINEAR,
+ GD_METHOD_COUNT = 23
+} gdInterpolationMethod;
+
+/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */
+
+/* Interpolation function ptr */
+typedef double (* interpolation_method )(double);
+
+
+/*
+ Group: Types
+
+ typedef: gdImage
+
+ typedef: gdImagePtr
+
+ The data structure in which gd stores images. <gdImageCreate>,
+ <gdImageCreateTrueColor> and the various image file-loading functions
+ return a pointer to this type, and the other functions expect to
+ receive a pointer to this type as their first argument.
+
+ *gdImagePtr* is a pointer to *gdImage*.
+
+ See also:
+ <Accessor Macros>
+
+ (Previous versions of this library encouraged directly manipulating
+ the contents ofthe struct but we are attempting to move away from
+ this practice so the fields are no longer documented here. If you
+ need to poke at the internals of this struct, feel free to look at
+ *gd.h*.)
+*/
+typedef struct gdImageStruct {
+ /* Palette-based image pixels */
+ unsigned char **pixels;
+ int sx;
+ int sy;
+ /* These are valid in palette images only. See also
+ 'alpha', which appears later in the structure to
+ preserve binary backwards compatibility */
+ int colorsTotal;
+ int red[gdMaxColors];
+ int green[gdMaxColors];
+ int blue[gdMaxColors];
+ int open[gdMaxColors];
+ /* For backwards compatibility, this is set to the
+ first palette entry with 100% transparency,
+ and is also set and reset by the
+ gdImageColorTransparent function. Newer
+ applications can allocate palette entries
+ with any desired level of transparency; however,
+ bear in mind that many viewers, notably
+ many web browsers, fail to implement
+ full alpha channel for PNG and provide
+ support for full opacity or transparency only. */
+ int transparent;
+ int *polyInts;
+ int polyAllocated;
+ struct gdImageStruct *brush;
+ struct gdImageStruct *tile;
+ int brushColorMap[gdMaxColors];
+ int tileColorMap[gdMaxColors];
+ int styleLength;
+ int stylePos;
+ int *style;
+ int interlace;
+ /* New in 2.0: thickness of line. Initialized to 1. */
+ int thick;
+ /* New in 2.0: alpha channel for palettes. Note that only
+ Macintosh Internet Explorer and (possibly) Netscape 6
+ really support multiple levels of transparency in
+ palettes, to my knowledge, as of 2/15/01. Most
+ common browsers will display 100% opaque and
+ 100% transparent correctly, and do something
+ unpredictable and/or undesirable for levels
+ in between. TBB */
+ int alpha[gdMaxColors];
+ /* Truecolor flag and pixels. New 2.0 fields appear here at the
+ end to minimize breakage of existing object code. */
+ int trueColor;
+ int **tpixels;
+ /* Should alpha channel be copied, or applied, each time a
+ pixel is drawn? This applies to truecolor images only.
+ No attempt is made to alpha-blend in palette images,
+ even if semitransparent palette entries exist.
+ To do that, build your image as a truecolor image,
+ then quantize down to 8 bits. */
+ int alphaBlendingFlag;
+ /* Should the alpha channel of the image be saved? This affects
+ PNG at the moment; other future formats may also
+ have that capability. JPEG doesn't. */
+ int saveAlphaFlag;
+
+ /* There should NEVER BE ACCESSOR MACROS FOR ITEMS BELOW HERE, so this
+ part of the structure can be safely changed in new releases. */
+
+ /* 2.0.12: anti-aliased globals. 2.0.26: just a few vestiges after
+ switching to the fast, memory-cheap implementation from PHP-gd. */
+ int AA;
+ int AA_color;
+ int AA_dont_blend;
+
+ /* 2.0.12: simple clipping rectangle. These values
+ must be checked for safety when set; please use
+ gdImageSetClip */
+ int cx1;
+ int cy1;
+ int cx2;
+ int cy2;
+
+ /* 2.1.0: allows to specify resolution in dpi */
+ unsigned int res_x;
+ unsigned int res_y;
+
+ /* Selects quantization method, see gdImageTrueColorToPaletteSetMethod() and gdPaletteQuantizationMethod enum. */
+ int paletteQuantizationMethod;
+ /* speed/quality trade-off. 1 = best quality, 10 = best speed. 0 = method-specific default.
+ Applicable to GD_QUANT_LIQ and GD_QUANT_NEUQUANT. */
+ int paletteQuantizationSpeed;
+ /* Image will remain true-color if conversion to palette cannot achieve given quality.
+ Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/
+ int paletteQuantizationMinQuality;
+ /* Image will use minimum number of palette colors needed to achieve given quality. Must be higher than paletteQuantizationMinQuality
+ Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/
+ int paletteQuantizationMaxQuality;
+ gdInterpolationMethod interpolation_id;
+ interpolation_method interpolation;
+}
+gdImage;
+
+typedef gdImage *gdImagePtr;
+
+
+/* Point type for use in polygon drawing. */
+
+/**
+ * Group: Types
+ *
+ * typedef: gdPointF
+ * Defines a point in a 2D coordinate system using floating point
+ * values.
+ * x - Floating point position (increase from left to right)
+ * y - Floating point Row position (increase from top to bottom)
+ *
+ * typedef: gdPointFPtr
+ * Pointer to a <gdPointF>
+ *
+ * See also:
+ * <gdImageCreate>, <gdImageCreateTrueColor>,
+ **/
+typedef struct
+{
+ double x, y;
+}
+gdPointF, *gdPointFPtr;
+
+
+/*
+ Group: Types
+
+ typedef: gdFont
+
+ typedef: gdFontPtr
+
+ A font structure, containing the bitmaps of all characters in a
+ font. Used to declare the characteristics of a font. Text-output
+ functions expect these as their second argument, following the
+ <gdImagePtr> argument. <gdFontGetSmall> and <gdFontGetLarge> both
+ return one.
+
+ You can provide your own font data by providing such a structure and
+ the associated pixel array. You can determine the width and height
+ of a single character in a font by examining the w and h members of
+ the structure. If you will not be creating your own fonts, you will
+ not need to concern yourself with the rest of the components of this
+ structure.
+
+ Please see the files gdfontl.c and gdfontl.h for an example of
+ the proper declaration of this structure.
+
+ > typedef struct {
+ > // # of characters in font
+ > int nchars;
+ > // First character is numbered... (usually 32 = space)
+ > int offset;
+ > // Character width and height
+ > int w;
+ > int h;
+ > // Font data; array of characters, one row after another.
+ > // Easily included in code, also easily loaded from
+ > // data files.
+ > char *data;
+ > } gdFont;
+
+ gdFontPtr is a pointer to gdFont.
+
+*/
+typedef struct {
+ /* # of characters in font */
+ int nchars;
+ /* First character is numbered... (usually 32 = space) */
+ int offset;
+ /* Character width and height */
+ int w;
+ int h;
+ /* Font data; array of characters, one row after another.
+ Easily included in code, also easily loaded from
+ data files. */
+ char *data;
+}
+gdFont;
+
+/* Text functions take these. */
+typedef gdFont *gdFontPtr;
+
+typedef void(*gdErrorMethod)(int, const char *, va_list);
+
+BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod);
+BGD_DECLARE(void) gdClearErrorMethod(void);
+
+/* For backwards compatibility only. Use gdImageSetStyle()
+ for MUCH more flexible line drawing. Also see
+ gdImageSetBrush(). */
+#define gdDashSize 4
+
+/**
+ * Group: Colors
+ *
+ * Colors are always of type int which is supposed to be at least 32 bit large.
+ *
+ * Kinds of colors:
+ * true colors - ARGB values where the alpha channel is stored as most
+ * significant, and the blue channel as least significant
+ * byte. Note that the alpha channel only uses the 7 least
+ * significant bits.
+ * Don't rely on the internal representation, though, and
+ * use <gdTrueColorAlpha> to compose a truecolor value, and
+ * <gdTrueColorGetAlpha>, <gdTrueColorGetRed>,
+ * <gdTrueColorGetGreen> and <gdTrueColorGetBlue> to access
+ * the respective channels.
+ * palette indexes - The index of a color palette entry (0-255).
+ * special colors - As listed in the following section.
+ *
+ * Constants: Special Colors
+ * gdStyled - use the current style, see <gdImageSetStyle>
+ * gdBrushed - use the current brush, see <gdImageSetBrush>
+ * gdStyledBrushed - use the current style and brush
+ * gdTiled - use the current tile, see <gdImageSetTile>
+ * gdTransparent - indicate transparency, what is not the same as the
+ * transparent color index; used for lines only
+ * gdAntiAliased - draw anti aliased
+ */
+
+#define gdStyled (-2)
+#define gdBrushed (-3)
+#define gdStyledBrushed (-4)
+#define gdTiled (-5)
+#define gdTransparent (-6)
+#define gdAntiAliased (-7)
+
+/* Functions to manipulate images. */
+
+/* Creates a palette-based image (up to 256 colors). */
+BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy);
+
+/* An alternate name for the above (2.0). */
+#define gdImageCreatePalette gdImageCreate
+
+/* Creates a truecolor image (millions of colors). */
+BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy);
+
+/* Creates an image from various file types. These functions
+ return a palette or truecolor image based on the
+ nature of the file being loaded. Truecolor PNG
+ stays truecolor; palette PNG stays palette-based;
+ JPEG is always truecolor. */
+BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * fd);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx (gdIOCtxPtr in);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data);
+
+/* These read the first frame only */
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGif (FILE * fd);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx (gdIOCtxPtr in);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMP (FILE * inFile);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPCtx (gdIOCtx * infile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPPtr (int size, void *data);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg (FILE * infile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegEx (FILE * infile, int ignore_warning);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx (gdIOCtx * infile);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtxEx (gdIOCtx * infile, int ignore_warning);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr (int size, void *data);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtrEx (int size, void *data, int ignore_warning);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile);
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtx *infile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data);
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromTga( FILE * fp );
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaCtx(gdIOCtx* ctx);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaPtr(int size, void *data);
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp (FILE * inFile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr (int size, void *data);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx (gdIOCtxPtr infile);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromFile(const char *filename);
+
+
+/*
+ Group: Types
+
+ typedef: gdSource
+
+ typedef: gdSourcePtr
+
+ *Note:* This interface is *obsolete* and kept only for
+ *compatibility. Use <gdIOCtx> instead.
+
+ Represents a source from which a PNG can be read. Programmers who
+ do not wish to read PNGs from a file can provide their own
+ alternate input mechanism, using the <gdImageCreateFromPngSource>
+ function. See the documentation of that function for an example of
+ the proper use of this type.
+
+ > typedef struct {
+ > int (*source) (void *context, char *buffer, int len);
+ > void *context;
+ > } gdSource, *gdSourcePtr;
+
+ The source function must return -1 on error, otherwise the number
+ of bytes fetched. 0 is EOF, not an error!
+
+ 'context' will be passed to your source function.
+
+*/
+typedef struct {
+ int (*source) (void *context, char *buffer, int len);
+ void *context;
+}
+gdSource, *gdSourcePtr;
+
+/* Deprecated in favor of gdImageCreateFromPngCtx */
+BGD_DECLARE(gdImagePtr) gdImageCreateFromPngSource (gdSourcePtr in);
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGd (FILE * in);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromGdCtx (gdIOCtxPtr in);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGdPtr (int size, void *data);
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * in);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data);
+
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * in, int srcx, int srcy, int w,
+ int h);
+//BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx (gdIOCtxPtr in, int srcx, int srcy,
+// int w, int h);
+BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy,
+ int w, int h);
+/* 2.0.10: prototype was missing */
+BGD_DECLARE(gdImagePtr) gdImageCreateFromXbm (FILE * in);
+//BGD_DECLARE(void) gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtx * out);
+
+/* NOTE: filename, not FILE */
+BGD_DECLARE(gdImagePtr) gdImageCreateFromXpm (char *filename);
+
+BGD_DECLARE(void) gdImageDestroy (gdImagePtr im);
+
+/* Replaces or blends with the background depending on the
+ most recent call to gdImageAlphaBlending and the
+ alpha channel value of 'color'; default is to overwrite.
+ Tiling and line styling are also implemented
+ here. All other gd drawing functions pass through this call,
+ allowing for many useful effects.
+ Overlay and multiply effects are used when gdImageAlphaBlending
+ is passed gdEffectOverlay and gdEffectMultiply */
+
+BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color);
+/* FreeType 2 text output with hook to extra flags */
+
+BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y);
+BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y);
+
+BGD_DECLARE(void) gdImageAABlend (gdImagePtr im);
+
+BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color);
+
+/* For backwards compatibility only. Use gdImageSetStyle()
+ for much more flexible line drawing. */
+BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color);
+/* Corners specified (not width and height). Upper left first, lower right
+ second. */
+BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color);
+/* Solid bar. Upper left corner first, lower right corner second. */
+BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2,
+ int color);
+BGD_DECLARE(void) gdImageSetClip(gdImagePtr im, int x1, int y1, int x2, int y2);
+BGD_DECLARE(void) gdImageGetClip(gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P);
+BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y);
+BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y);
+BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c,
+ int color);
+BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c,
+ int color);
+BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f, int x, int y,
+ unsigned char *s, int color);
+BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y,
+ unsigned char *s, int color);
+BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y,
+ unsigned short *s, int color);
+BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y,
+ unsigned short *s, int color);
+
+/* 2.0.16: for thread-safe use of gdImageStringFT and friends,
+ call this before allowing any thread to call gdImageStringFT.
+ Otherwise it is invoked by the first thread to invoke
+ gdImageStringFT, with a very small but real risk of a race condition.
+ Return 0 on success, nonzero on failure to initialize freetype. */
+BGD_DECLARE(int) gdFontCacheSetup (void);
+
+/* Optional: clean up after application is done using fonts in
+ gdImageStringFT(). */
+BGD_DECLARE(void) gdFontCacheShutdown (void);
+/* 2.0.20: for backwards compatibility. A few applications did start calling
+ this function when it first appeared although it was never documented.
+ Simply invokes gdFontCacheShutdown. */
+BGD_DECLARE(void) gdFreeFontCache (void);
+
+/* Calls gdImageStringFT. Provided for backwards compatibility only. */
+BGD_DECLARE(char *) gdImageStringTTF (gdImage * im, int *brect, int fg, char *fontlist,
+ double ptsize, double angle, int x, int y,
+ char *string);
+
+/* FreeType 2 text output */
+BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
+ double ptsize, double angle, int x, int y,
+ char *string);
+
+
+/*
+ Group: Types
+
+ typedef: gdFTStringExtra
+
+ typedef: gdFTStringExtraPtr
+
+ A structure and associated pointer type used to pass additional
+ parameters to the <gdImageStringFTEx> function. See
+ <gdImageStringFTEx> for the structure definition.
+
+ Thanks to Wez Furlong.
+*/
+
+/* 2.0.5: provides an extensible way to pass additional parameters.
+ Thanks to Wez Furlong, sorry for the delay. */
+typedef struct {
+ int flags; /* Logical OR of gdFTEX_ values */
+ double linespacing; /* fine tune line spacing for '\n' */
+ int charmap; /* TBB: 2.0.12: may be gdFTEX_Unicode,
+ gdFTEX_Shift_JIS, gdFTEX_Big5,
+ or gdFTEX_Adobe_Custom;
+ when not specified, maps are searched
+ for in the above order. */
+ int hdpi; /* if (flags & gdFTEX_RESOLUTION) */
+ int vdpi; /* if (flags & gdFTEX_RESOLUTION) */
+ char *xshow; /* if (flags & gdFTEX_XSHOW)
+ then, on return, xshow is a malloc'ed
+ string containing xshow position data for
+ the last string.
+
+ NB. The caller is responsible for gdFree'ing
+ the xshow string.
+ */
+ char *fontpath; /* if (flags & gdFTEX_RETURNFONTPATHNAME)
+ then, on return, fontpath is a malloc'ed
+ string containing the actual font file path name
+ used, which can be interesting when fontconfig
+ is in use.
+
+ The caller is responsible for gdFree'ing the
+ fontpath string.
+ */
+
+}
+gdFTStringExtra, *gdFTStringExtraPtr;
+
+#define gdFTEX_LINESPACE 1
+#define gdFTEX_CHARMAP 2
+#define gdFTEX_RESOLUTION 4
+#define gdFTEX_DISABLE_KERNING 8
+#define gdFTEX_XSHOW 16
+/* The default unless gdFTUseFontConfig(1); has been called:
+ fontlist is a full or partial font file pathname or list thereof
+ (i.e. just like before 2.0.29) */
+#define gdFTEX_FONTPATHNAME 32
+/* Necessary to use fontconfig patterns instead of font pathnames
+ as the fontlist argument, unless gdFTUseFontConfig(1); has
+ been called. New in 2.0.29 */
+#define gdFTEX_FONTCONFIG 64
+/* Sometimes interesting when fontconfig is used: the fontpath
+ element of the structure above will contain a gdMalloc'd string
+ copy of the actual font file pathname used, if this flag is set
+ when the call is made */
+#define gdFTEX_RETURNFONTPATHNAME 128
+
+/* If flag is nonzero, the fontlist parameter to gdImageStringFT
+ and gdImageStringFTEx shall be assumed to be a fontconfig font pattern
+ if fontconfig was compiled into gd. This function returns zero
+ if fontconfig is not available, nonzero otherwise. */
+BGD_DECLARE(int) gdFTUseFontConfig(int flag);
+
+/* These are NOT flags; set one in 'charmap' if you set the
+ gdFTEX_CHARMAP bit in 'flags'. */
+#define gdFTEX_Unicode 0
+#define gdFTEX_Shift_JIS 1
+#define gdFTEX_Big5 2
+#define gdFTEX_Adobe_Custom 3
+
+BGD_DECLARE(char *) gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist,
+ double ptsize, double angle, int x, int y,
+ char *string, gdFTStringExtraPtr strex);
+
+
+/*
+ Group: Types
+
+ typedef: gdPoint
+
+ typedef: gdPointPtr
+
+ Represents a point in the coordinate space of the image; used by
+ <gdImagePolygon>, <gdImageOpenPolygon> and <gdImageFilledPolygon>
+ for polygon drawing.
+
+ > typedef struct {
+ > int x, y;
+ > } gdPoint, *gdPointPtr;
+
+*/
+typedef struct {
+ int x, y;
+}
+gdPoint, *gdPointPtr;
+
+/**
+ * Typedef: gdRect
+ *
+ * A rectangle in the coordinate space of the image
+ *
+ * Members:
+ * x - The x-coordinate of the upper left corner.
+ * y - The y-coordinate of the upper left corner.
+ * width - The width.
+ * height - The height.
+ *
+ * Typedef: gdRectPtr
+ *
+ * A pointer to a <gdRect>
+ */
+typedef struct {
+ int x, y;
+ int width, height;
+}
+gdRect, *gdRectPtr;
+
+
+BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c);
+BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c);
+BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c);
+
+/* These functions still work with truecolor images,
+ for which they never return error. */
+BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b);
+/* gd 2.0: palette entries with non-opaque transparency are permitted. */
+BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a);
+/* Assumes opaque is the preferred alpha channel value */
+BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b);
+/* Closest match taking all four parameters into account.
+ A slightly different color with the same transparency
+ beats the exact same color with radically different
+ transparency */
+BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a);
+/* An alternate method */
+BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b);
+/* Returns exact, 100% opaque matches only */
+BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b);
+/* Returns an exact match only, including alpha */
+BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a);
+/* Opaque only */
+BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b);
+/* Based on gdImageColorExactAlpha and gdImageColorClosestAlpha */
+BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a);
+
+/* A simpler way to obtain an opaque truecolor value for drawing on a
+ truecolor image. Not for use with palette images! */
+
+#define gdTrueColor(r, g, b) (((r) << 16) + \
+ ((g) << 8) + \
+ (b))
+
+/**
+ * Group: Color Composition
+ *
+ * Macro: gdTrueColorAlpha
+ *
+ * Compose a truecolor value from its components
+ *
+ * Parameters:
+ * r - The red channel (0-255)
+ * g - The green channel (0-255)
+ * b - The blue channel (0-255)
+ * a - The alpha channel (0-127, where 127 is fully transparent, and 0 is
+ * completely opaque).
+ *
+ * See also:
+ * - <gdTrueColorGetAlpha>
+ * - <gdTrueColorGetRed>
+ * - <gdTrueColorGetGreen>
+ * - <gdTrueColorGetBlue>
+ * - <gdImageColorExactAlpha>
+ */
+#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \
+ ((r) << 16) + \
+ ((g) << 8) + \
+ (b))
+
+BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color);
+
+/* Converts a truecolor image to a palette-based image,
+ using a high-quality two-pass quantization routine
+ which attempts to preserve alpha channel information
+ as well as R/G/B color information when creating
+ a palette. If ditherFlag is set, the image will be
+ dithered to approximate colors better, at the expense
+ of some obvious "speckling." colorsWanted can be
+ anything up to 256. If the original source image
+ includes photographic information or anything that
+ came out of a JPEG, 256 is strongly recommended.
+
+ Better yet, don't use these function -- write real
+ truecolor PNGs and JPEGs. The disk space gain of
+ conversion to palette is not great (for small images
+ it can be negative) and the quality loss is ugly.
+
+ DIFFERENCES: gdImageCreatePaletteFromTrueColor creates and
+ returns a new image. gdImageTrueColorToPalette modifies
+ an existing image, and the truecolor pixels are discarded.
+
+ gdImageTrueColorToPalette() returns TRUE on success, FALSE on failure.
+*/
+
+BGD_DECLARE(gdImagePtr) gdImageCreatePaletteFromTrueColor (gdImagePtr im, int ditherFlag,
+ int colorsWanted);
+
+BGD_DECLARE(int) gdImageTrueColorToPalette (gdImagePtr im, int ditherFlag,
+ int colorsWanted);
+
+BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src);
+
+/* An attempt at getting the results of gdImageTrueColorToPalette to
+ * look a bit more like the original (im1 is the original and im2 is
+ * the palette version */
+
+BGD_DECLARE(int) gdImageColorMatch(gdImagePtr im1, gdImagePtr im2);
+
+/* Selects quantization method used for subsequent gdImageTrueColorToPalette calls.
+ See gdPaletteQuantizationMethod enum (e.g. GD_QUANT_NEUQUANT, GD_QUANT_LIQ).
+ Speed is from 1 (highest quality) to 10 (fastest).
+ Speed 0 selects method-specific default (recommended).
+
+ Returns FALSE if the given method is invalid or not available.
+*/
+BGD_DECLARE(int) gdImageTrueColorToPaletteSetMethod (gdImagePtr im, int method, int speed);
+
+/*
+ Chooses quality range that subsequent call to gdImageTrueColorToPalette will aim for.
+ Min and max quality is in range 1-100 (1 = ugly, 100 = perfect). Max must be higher than min.
+ If palette cannot represent image with at least min_quality, then image will remain true-color.
+ If palette can represent image with quality better than max_quality, then lower number of colors will be used.
+ This function has effect only when GD_QUANT_LIQ method has been selected and the source image is true-color.
+*/
+BGD_DECLARE(void) gdImageTrueColorToPaletteSetQuality (gdImagePtr im, int min_quality, int max_quality);
+
+/* Specifies a color index (if a palette image) or an
+ RGB color (if a truecolor image) which should be
+ considered 100% transparent. FOR TRUECOLOR IMAGES,
+ THIS IS IGNORED IF AN ALPHA CHANNEL IS BEING
+ SAVED. Use gdImageSaveAlpha(im, 0); to
+ turn off the saving of a full alpha channel in
+ a truecolor image. Note that gdImageColorTransparent
+ is usually compatible with older browsers that
+ do not understand full alpha channels well. TBB */
+BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color);
+
+BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr dst, gdImagePtr src);
+
+typedef int (*gdCallbackImageColor)(gdImagePtr im, int src);
+
+BGD_DECLARE(int) gdImageColorReplace(gdImagePtr im, int src, int dst);
+BGD_DECLARE(int) gdImageColorReplaceThreshold(gdImagePtr im, int src, int dst, float threshold);
+BGD_DECLARE(int) gdImageColorReplaceArray(gdImagePtr im, int len, int *src, int *dst);
+BGD_DECLARE(int) gdImageColorReplaceCallback(gdImagePtr im, gdCallbackImageColor callback);
+
+BGD_DECLARE(void) gdImageGif (gdImagePtr im, FILE * out);
+BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * out);
+//BGD_DECLARE(void) gdImagePngCtx (gdImagePtr im, gdIOCtx * out);
+//BGD_DECLARE(void) gdImageGifCtx (gdImagePtr im, gdIOCtx * out);
+BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile);
+BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size);
+//BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtx *out);
+
+BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression);
+BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression);
+//BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression);
+
+/* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
+ 1 is FASTEST but produces larger files, 9 provides the best
+ compression (smallest files) but takes a long time to compress, and
+ -1 selects the default compiled into the zlib library. */
+BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * out, int level);
+//BGD_DECLARE(void) gdImagePngCtxEx (gdImagePtr im, gdIOCtx * out, int level);
+
+BGD_DECLARE(void) gdImageWBMP (gdImagePtr image, int fg, FILE * out);
+//BGD_DECLARE(void) gdImageWBMPCtx (gdImagePtr image, int fg, gdIOCtx * out);
+
+BGD_DECLARE(int) gdImageFile(gdImagePtr im, const char *filename);
+BGD_DECLARE(int) gdSupportsFileType(const char *filename, int writing);
+
+
+/* Guaranteed to correctly free memory returned by the gdImage*Ptr
+ functions */
+BGD_DECLARE(void) gdFree (void *m);
+
+/* Best to free this memory with gdFree(), not free() */
+BGD_DECLARE(void *) gdImageWBMPPtr (gdImagePtr im, int *size, int fg);
+
+/* 100 is highest quality (there is always a little loss with JPEG).
+ 0 is lowest. 10 is about the lowest useful setting. */
+BGD_DECLARE(void) gdImageJpeg (gdImagePtr im, FILE * out, int quality);
+//BGD_DECLARE(void) gdImageJpegCtx (gdImagePtr im, gdIOCtx * out, int quality);
+
+/* Best to free this memory with gdFree(), not free() */
+BGD_DECLARE(void *) gdImageJpegPtr (gdImagePtr im, int *size, int quality);
+
+BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization);
+BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile);
+BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size);
+BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization);
+//BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization);
+
+
+/**
+ * Group: GifAnim
+ *
+ * Legal values for Disposal. gdDisposalNone is always used by
+ * the built-in optimizer if previm is passed.
+ *
+ * Constants: gdImageGifAnim
+ *
+ * gdDisposalUnknown - Not recommended
+ * gdDisposalNone - Preserve previous frame
+ * gdDisposalRestoreBackground - First allocated color of palette
+ * gdDisposalRestorePrevious - Restore to before start of frame
+ *
+ * See also:
+ * - <gdImageGifAnimAdd>
+ */
+enum {
+ gdDisposalUnknown,
+ gdDisposalNone,
+ gdDisposalRestoreBackground,
+ gdDisposalRestorePrevious
+};
+
+BGD_DECLARE(void) gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops);
+BGD_DECLARE(void) gdImageGifAnimAdd(gdImagePtr im, FILE *outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+BGD_DECLARE(void) gdImageGifAnimEnd(FILE *outFile);
+//BGD_DECLARE(void) gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtx *out, int GlobalCM, int Loops);
+//BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtx *out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+//BGD_DECLARE(void) gdImageGifAnimEndCtx(gdIOCtx *out);
+BGD_DECLARE(void *) gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops);
+BGD_DECLARE(void *) gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm);
+BGD_DECLARE(void *) gdImageGifAnimEndPtr(int *size);
+
+
+
+/*
+ Group: Types
+
+ typedef: gdSink
+
+ typedef: gdSinkPtr
+
+ *Note:* This interface is *obsolete* and kept only for
+ *compatibility*. Use <gdIOCtx> instead.
+
+ Represents a "sink" (destination) to which a PNG can be
+ written. Programmers who do not wish to write PNGs to a file can
+ provide their own alternate output mechanism, using the
+ <gdImagePngToSink> function. See the documentation of that
+ function for an example of the proper use of this type.
+
+ > typedef struct {
+ > int (*sink) (void *context, char *buffer, int len);
+ > void *context;
+ > } gdSink, *gdSinkPtr;
+
+ The _sink_ function must return -1 on error, otherwise the number of
+ bytes written, which must be equal to len.
+
+ _context_ will be passed to your sink function.
+
+*/
+
+typedef struct {
+ int (*sink) (void *context, const char *buffer, int len);
+ void *context;
+}
+gdSink, *gdSinkPtr;
+
+BGD_DECLARE(void) gdImagePngToSink (gdImagePtr im, gdSinkPtr out);
+
+BGD_DECLARE(void) gdImageGd (gdImagePtr im, FILE * out);
+BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * out, int cs, int fmt);
+
+/* Best to free this memory with gdFree(), not free() */
+BGD_DECLARE(void *) gdImageGifPtr (gdImagePtr im, int *size);
+
+/* Best to free this memory with gdFree(), not free() */
+BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size);
+BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level);
+
+/* Best to free this memory with gdFree(), not free() */
+BGD_DECLARE(void *) gdImageGdPtr (gdImagePtr im, int *size);
+
+/* Best to free this memory with gdFree(), not free() */
+BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size);
+
+/* Style is a bitwise OR ( | operator ) of these.
+ gdArc and gdChord are mutually exclusive;
+ gdChord just connects the starting and ending
+ angles with a straight line, while gdArc produces
+ a rounded edge. gdPie is a synonym for gdArc.
+ gdNoFill indicates that the arc or chord should be
+ outlined, not filled. gdEdged, used together with
+ gdNoFill, indicates that the beginning and ending
+ angles should be connected to the center; this is
+ a good way to outline (rather than fill) a
+ 'pie slice'. */
+#define gdArc 0
+#define gdPie gdArc
+#define gdChord 1
+#define gdNoFill 2
+#define gdEdged 4
+
+BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s,
+ int e, int color, int style);
+BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e,
+ int color);
+BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color);
+BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int w, int h,
+ int color);
+BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border,
+ int color);
+BGD_DECLARE(void) gdImageFill (gdImagePtr im, int x, int y, int color);
+BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
+ int srcX, int srcY, int w, int h);
+BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
+ int srcX, int srcY, int w, int h, int pct);
+BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX,
+ int dstY, int srcX, int srcY, int w, int h,
+ int pct);
+
+/* Stretches or shrinks to fit, as needed. Does NOT attempt
+ to average the entire set of source pixels that scale down onto the
+ destination pixel. */
+BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY,
+ int srcX, int srcY, int dstW, int dstH, int srcW,
+ int srcH);
+
+/* gd 2.0: stretches or shrinks to fit, as needed. When called with a
+ truecolor destination image, this function averages the
+ entire set of source pixels that scale down onto the
+ destination pixel, taking into account what portion of the
+ destination pixel each source pixel represents. This is a
+ floating point operation, but this is not a performance issue
+ on modern hardware, except for some embedded devices. If the
+ destination is a palette image, gdImageCopyResized is
+ substituted automatically. */
+BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX,
+ int dstY, int srcX, int srcY, int dstW, int dstH,
+ int srcW, int srcH);
+
+/* gd 2.0.8: gdImageCopyRotated is added. Source
+ is a rectangle, with its upper left corner at
+ srcX and srcY. Destination is the *center* of
+ the rotated copy. Angle is in degrees, same as
+ gdImageArc. Floating point destination center
+ coordinates allow accurate rotation of
+ objects of odd-numbered width or height. */
+BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst,
+ gdImagePtr src,
+ double dstX, double dstY,
+ int srcX, int srcY,
+ int srcWidth, int srcHeight, int angle);
+
+BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src);
+
+BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush);
+BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile);
+BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c);
+BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend);
+BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels);
+/* Line thickness (defaults to 1). Affects lines, ellipses,
+ rectangles, polygons and so forth. */
+BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness);
+/* On or off (1 or 0) for all three of these. */
+BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg);
+BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg);
+BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg);
+
+BGD_DECLARE(gdImagePtr) gdImageNeuQuant(gdImagePtr im, const int max_color, int sample_factor);
+
+enum gdPixelateMode {
+ GD_PIXELATE_UPPERLEFT,
+ GD_PIXELATE_AVERAGE
+};
+
+BGD_DECLARE(int) gdImagePixelate(gdImagePtr im, int block_size, const unsigned int mode);
+
+typedef struct {
+ int sub;
+ int plus;
+ unsigned int num_colors;
+ int *colors;
+ unsigned int seed;
+} gdScatter, *gdScatterPtr;
+
+BGD_DECLARE(int) gdImageScatter(gdImagePtr im, int sub, int plus);
+BGD_DECLARE(int) gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors);
+BGD_DECLARE(int) gdImageScatterEx(gdImagePtr im, gdScatterPtr s);
+BGD_DECLARE(int) gdImageSmooth(gdImagePtr im, float weight);
+BGD_DECLARE(int) gdImageMeanRemoval(gdImagePtr im);
+BGD_DECLARE(int) gdImageEmboss(gdImagePtr im);
+BGD_DECLARE(int) gdImageGaussianBlur(gdImagePtr im);
+BGD_DECLARE(int) gdImageEdgeDetectQuick(gdImagePtr src);
+BGD_DECLARE(int) gdImageSelectiveBlur( gdImagePtr src);
+BGD_DECLARE(int) gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset);
+BGD_DECLARE(int) gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha);
+BGD_DECLARE(int) gdImageContrast(gdImagePtr src, double contrast);
+BGD_DECLARE(int) gdImageBrightness(gdImagePtr src, int brightness);
+BGD_DECLARE(int) gdImageGrayScale(gdImagePtr src);
+BGD_DECLARE(int) gdImageNegate(gdImagePtr src);
+
+BGD_DECLARE(gdImagePtr) gdImageCopyGaussianBlurred(gdImagePtr src, int radius,
+ double sigma);
+
+
+/**
+ * Group: Accessor Macros
+ */
+
+/**
+ * Macro: gdImageTrueColor
+ *
+ * Whether an image is a truecolor image.
+ *
+ * Parameters:
+ * im - The image.
+ *
+ * Returns:
+ * Non-zero if the image is a truecolor image, zero for palette images.
+ */
+#define gdImageTrueColor(im) ((im)->trueColor)
+
+/**
+ * Macro: gdImageSX
+ *
+ * Gets the width (in pixels) of an image.
+ *
+ * Parameters:
+ * im - The image.
+ */
+#define gdImageSX(im) ((im)->sx)
+
+/**
+ * Macro: gdImageSY
+ *
+ * Gets the height (in pixels) of an image.
+ *
+ * Parameters:
+ * im - The image.
+ */
+#define gdImageSY(im) ((im)->sy)
+
+/**
+ * Macro: gdImageColorsTotal
+ *
+ * Gets the number of colors in the palette.
+ *
+ * This macro is only valid for palette images.
+ *
+ * Parameters:
+ * im - The image
+ */
+#define gdImageColorsTotal(im) ((im)->colorsTotal)
+
+/**
+ * Macro: gdImageRed
+ *
+ * Gets the red component value of a given color.
+ *
+ * Parameters:
+ * im - The image.
+ * c - The color.
+ */
+#define gdImageRed(im, c) ((im)->trueColor ? gdTrueColorGetRed(c) : \
+ (im)->red[(c)])
+
+/**
+ * Macro: gdImageGreen
+ *
+ * Gets the green component value of a given color.
+ *
+ * Parameters:
+ * im - The image.
+ * c - The color.
+ */
+#define gdImageGreen(im, c) ((im)->trueColor ? gdTrueColorGetGreen(c) : \
+ (im)->green[(c)])
+
+/**
+ * Macro: gdImageBlue
+ *
+ * Gets the blue component value of a given color.
+ *
+ * Parameters:
+ * im - The image.
+ * c - The color.
+ */
+#define gdImageBlue(im, c) ((im)->trueColor ? gdTrueColorGetBlue(c) : \
+ (im)->blue[(c)])
+
+/**
+ * Macro: gdImageAlpha
+ *
+ * Gets the alpha component value of a given color.
+ *
+ * Parameters:
+ * im - The image.
+ * c - The color.
+ */
+#define gdImageAlpha(im, c) ((im)->trueColor ? gdTrueColorGetAlpha(c) : \
+ (im)->alpha[(c)])
+
+/**
+ * Macro: gdImageGetTransparent
+ *
+ * Gets the transparent color of the image.
+ *
+ * Parameters:
+ * im - The image.
+ *
+ * See also:
+ * - <gdImageColorTransparent>
+ */
+#define gdImageGetTransparent(im) ((im)->transparent)
+
+/**
+ * Macro: gdImageGetInterlaced
+ *
+ * Whether an image is interlaced.
+ *
+ * Parameters:
+ * im - The image.
+ *
+ * Returns:
+ * Non-zero for interlaced images, zero otherwise.
+ *
+ * See also:
+ * - <gdImageInterlace>
+ */
+#define gdImageGetInterlaced(im) ((im)->interlace)
+
+/**
+ * Macro: gdImagePalettePixel
+ *
+ * Gets the color of a pixel.
+ *
+ * Calling this macro is only valid for palette images.
+ * No bounds checking is done for the coordinates.
+ *
+ * Parameters:
+ * im - The image.
+ * x - The x-coordinate.
+ * y - The y-coordinate.
+ *
+ * See also:
+ * - <gdImageTrueColorPixel>
+ * - <gdImageGetPixel>
+ */
+#define gdImagePalettePixel(im, x, y) (im)->pixels[(y)][(x)]
+
+/**
+ * Macro: gdImageTrueColorPixel
+ *
+ * Gets the color of a pixel.
+ *
+ * Calling this macro is only valid for truecolor images.
+ * No bounds checking is done for the coordinates.
+ *
+ * Parameters:
+ * im - The image.
+ * x - The x-coordinate.
+ * y - The y-coordinate.
+ *
+ * See also:
+ * - <gdImagePalettePixel>
+ * - <gdImageGetTrueColorPixel>
+ */
+#define gdImageTrueColorPixel(im, x, y) (im)->tpixels[(y)][(x)]
+
+/**
+ * Macro: gdImageResolutionX
+ *
+ * Gets the horizontal resolution in DPI.
+ *
+ * Parameters:
+ * im - The image.
+ *
+ * See also:
+ * - <gdImageResolutionY>
+ * - <gdImageSetResolution>
+ */
+#define gdImageResolutionX(im) (im)->res_x
+
+/**
+ * Macro: gdImageResolutionY
+ *
+ * Gets the vertical resolution in DPI.
+ *
+ * Parameters:
+ * im - The image.
+ *
+ * See also:
+ * - <gdImageResolutionX>
+ * - <gdImageSetResolution>
+ */
+#define gdImageResolutionY(im) (im)->res_y
+
+/* I/O Support routines. */
+
+//BGD_DECLARE(gdIOCtx *) gdNewFileCtx (FILE *);
+/* If data is null, size is ignored and an initial data buffer is
+ allocated automatically. NOTE: this function assumes gd has the right
+ to free or reallocate "data" at will! Also note that gd will free
+ "data" when the IO context is freed. If data is not null, it must point
+ to memory allocated with gdMalloc, or by a call to gdImage[something]Ptr.
+ If not, see gdNewDynamicCtxEx for an alternative. */
+//BGD_DECLARE(gdIOCtx *) gdNewDynamicCtx (int size, void *data);
+/* 2.0.21: if freeFlag is nonzero, gd will free and/or reallocate "data" as
+ needed as described above. If freeFlag is zero, gd will never free
+ or reallocate "data", which means that the context should only be used
+ for *reading* an image from a memory buffer, or writing an image to a
+ memory buffer which is already large enough. If the memory buffer is
+ not large enough and an image write is attempted, the write operation
+ will fail. Those wishing to write an image to a buffer in memory have
+ a much simpler alternative in the gdImage[something]Ptr functions. */
+//BGD_DECLARE(gdIOCtx *) gdNewDynamicCtxEx (int size, void *data, int freeFlag);
+//BGD_DECLARE(gdIOCtx *) gdNewSSCtx (gdSourcePtr in, gdSinkPtr out);
+//BGD_DECLARE(void *) gdDPExtractData (struct gdIOCtx *ctx, int *size);
+
+#define GD2_CHUNKSIZE 128
+#define GD2_CHUNKSIZE_MIN 64
+#define GD2_CHUNKSIZE_MAX 4096
+
+#define GD2_VERS 2
+#define GD2_ID "gd2"
+
+#define GD2_FMT_RAW 1
+#define GD2_FMT_COMPRESSED 2
+
+/* Image comparison definitions */
+BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2);
+
+BGD_DECLARE(void) gdImageFlipHorizontal(gdImagePtr im);
+BGD_DECLARE(void) gdImageFlipVertical(gdImagePtr im);
+BGD_DECLARE(void) gdImageFlipBoth(gdImagePtr im);
+
+#define GD_FLIP_HORINZONTAL 1
+#define GD_FLIP_VERTICAL 2
+#define GD_FLIP_BOTH 3
+
+/**
+ * Group: Crop
+ *
+ * Constants: gdCropMode
+ * GD_CROP_DEFAULT - Default crop mode (4 corners or background)
+ * GD_CROP_TRANSPARENT - Crop using the transparent color
+ * GD_CROP_BLACK - Crop black borders
+ * GD_CROP_WHITE - Crop white borders
+ * GD_CROP_SIDES - Crop using colors of the 4 corners
+ *
+ * See also:
+ * - <gdImageCropAuto>
+ **/
+enum gdCropMode {
+ GD_CROP_DEFAULT = 0,
+ GD_CROP_TRANSPARENT,
+ GD_CROP_BLACK,
+ GD_CROP_WHITE,
+ GD_CROP_SIDES,
+ GD_CROP_THRESHOLD
+};
+
+BGD_DECLARE(gdImagePtr) gdImageCrop(gdImagePtr src, const gdRect *crop);
+BGD_DECLARE(gdImagePtr) gdImageCropAuto(gdImagePtr im, const unsigned int mode);
+BGD_DECLARE(gdImagePtr) gdImageCropThreshold(gdImagePtr im, const unsigned int color, const float threshold);
+
+BGD_DECLARE(int) gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id);
+BGD_DECLARE(gdInterpolationMethod) gdImageGetInterpolationMethod(gdImagePtr im);
+
+BGD_DECLARE(gdImagePtr) gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height);
+
+BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor);
+
+typedef enum {
+ GD_AFFINE_TRANSLATE = 0,
+ GD_AFFINE_SCALE,
+ GD_AFFINE_ROTATE,
+ GD_AFFINE_SHEAR_HORIZONTAL,
+ GD_AFFINE_SHEAR_VERTICAL
+} gdAffineStandardMatrix;
+
+BGD_DECLARE(int) gdAffineApplyToPointF (gdPointFPtr dst, const gdPointFPtr src, const double affine[6]);
+BGD_DECLARE(int) gdAffineInvert (double dst[6], const double src[6]);
+BGD_DECLARE(int) gdAffineFlip (double dst_affine[6], const double src_affine[6], const int flip_h, const int flip_v);
+BGD_DECLARE(int) gdAffineConcat (double dst[6], const double m1[6], const double m2[6]);
+
+BGD_DECLARE(int) gdAffineIdentity (double dst[6]);
+BGD_DECLARE(int) gdAffineScale (double dst[6], const double scale_x, const double scale_y);
+BGD_DECLARE(int) gdAffineRotate (double dst[6], const double angle);
+BGD_DECLARE(int) gdAffineShearHorizontal (double dst[6], const double angle);
+BGD_DECLARE(int) gdAffineShearVertical(double dst[6], const double angle);
+BGD_DECLARE(int) gdAffineTranslate (double dst[6], const double offset_x, const double offset_y);
+BGD_DECLARE(double) gdAffineExpansion (const double src[6]);
+BGD_DECLARE(int) gdAffineRectilinear (const double src[6]);
+BGD_DECLARE(int) gdAffineEqual (const double matrix1[6], const double matrix2[6]);
+BGD_DECLARE(int) gdTransformAffineGetImage(gdImagePtr *dst, const gdImagePtr src, gdRectPtr src_area, const double affine[6]);
+BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst, int dst_x, int dst_y, const gdImagePtr src, gdRectPtr src_region, const double affine[6]);
+/*
+gdTransformAffineCopy(gdImagePtr dst, int x0, int y0, int x1, int y1,
+ const gdImagePtr src, int src_width, int src_height,
+ const double affine[6]);
+*/
+BGD_DECLARE(int) gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox);
+
+/**
+ * Group: Image Comparison
+ *
+ * Constants:
+ * GD_CMP_IMAGE - Actual image IS different
+ * GD_CMP_NUM_COLORS - Number of colors in pallette differ
+ * GD_CMP_COLOR - Image colors differ
+ * GD_CMP_SIZE_X - Image width differs
+ * GD_CMP_SIZE_Y - Image heights differ
+ * GD_CMP_TRANSPARENT - Transparent color differs
+ * GD_CMP_BACKGROUND - Background color differs
+ * GD_CMP_INTERLACE - Interlaced setting differs
+ * GD_CMP_TRUECOLOR - Truecolor vs palette differs
+ *
+ * See also:
+ * - <gdImageCompare>
+ */
+#define GD_CMP_IMAGE 1
+#define GD_CMP_NUM_COLORS 2
+#define GD_CMP_COLOR 4
+#define GD_CMP_SIZE_X 8
+#define GD_CMP_SIZE_Y 16
+#define GD_CMP_TRANSPARENT 32
+#define GD_CMP_BACKGROUND 64
+#define GD_CMP_INTERLACE 128
+#define GD_CMP_TRUECOLOR 256
+
+/* resolution affects ttf font rendering, particularly hinting */
+#define GD_RESOLUTION 96 /* pixels per inch */
+
+
+/* Version information functions */
+BGD_DECLARE(int) gdMajorVersion(void);
+BGD_DECLARE(int) gdMinorVersion(void);
+BGD_DECLARE(int) gdReleaseVersion(void);
+BGD_DECLARE(const char *) gdExtraVersion(void);
+BGD_DECLARE(const char *) gdVersionString(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/* newfangled special effects */
+//#include "gdfx.h"
+
+#endif /* GD_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libmscgen/gd_color.c b/libmscgen/gd_color.c
new file mode 100644
index 0000000..ba0efd8
--- /dev/null
+++ b/libmscgen/gd_color.c
@@ -0,0 +1,35 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gd.h"
+#include "gd_color.h"
+
+/**
+ * The threshold method works relatively well but it can be improved.
+ * Maybe L*a*b* and Delta-E will give better results (and a better
+ * granularity).
+ */
+int gdColorMatch(gdImagePtr im, int col1, int col2, float threshold)
+{
+ const int dr = gdImageRed(im, col1) - gdImageRed(im, col2);
+ const int dg = gdImageGreen(im, col1) - gdImageGreen(im, col2);
+ const int db = gdImageBlue(im, col1) - gdImageBlue(im, col2);
+ const int da = gdImageAlpha(im, col1) - gdImageAlpha(im, col2);
+ const int dist = dr * dr + dg * dg + db * db + da * da;
+
+ return (100.0 * dist / 195075) < threshold;
+}
+
+/*
+ * To be implemented when we have more image formats.
+ * Buffer like gray8 gray16 or rgb8 will require some tweak
+ * and can be done in this function (called from the autocrop
+ * function. (Pierre)
+ */
+#if 0
+static int colors_equal (const int col1, const in col2)
+{
+
+}
+#endif
diff --git a/libmscgen/gd_color.h b/libmscgen/gd_color.h
new file mode 100644
index 0000000..08b06ce
--- /dev/null
+++ b/libmscgen/gd_color.h
@@ -0,0 +1,14 @@
+#ifndef GD_COLOR_H
+#define GD_COLOR_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int gdColorMatch(gdImagePtr im, int col1, int col2, float threshold);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmscgen/gd_errors.h b/libmscgen/gd_errors.h
new file mode 100644
index 0000000..4ecee94
--- /dev/null
+++ b/libmscgen/gd_errors.h
@@ -0,0 +1,46 @@
+#ifndef GD_ERRORS_H
+#define GD_ERRORS_H
+
+#ifndef _WIN32
+# include <syslog.h>
+#else
+/*
+ * priorities/facilities are encoded into a single 32-bit quantity, where the
+ * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
+ * (0-big number). Both the priorities and the facilities map roughly
+ * one-to-one to strings in the syslogd(8) source code. This mapping is
+ * included in this file.
+ *
+ * priorities (these are ordered)
+ */
+# define LOG_EMERG 0 /* system is unusable */
+# define LOG_ALERT 1 /* action must be taken immediately */
+# define LOG_CRIT 2 /* critical conditions */
+# define LOG_ERR 3 /* error conditions */
+# define LOG_WARNING 4 /* warning conditions */
+# define LOG_NOTICE 5 /* normal but significant condition */
+# define LOG_INFO 6 /* informational */
+# define LOG_DEBUG 7 /* debug-level messages */
+#endif
+
+/*
+LOG_EMERG system is unusable
+LOG_ALERT action must be taken immediately
+LOG_CRIT critical conditions
+LOG_ERR error conditions
+LOG_WARNING warning conditions
+LOG_NOTICE normal, but significant, condition
+LOG_INFO informational message
+LOG_DEBUG debug-level message
+*/
+
+#define GD_ERROR LOG_ERR
+#define GD_WARNING LOG_WARNING
+#define GD_NOTICE LOG_NOTICE
+#define GD_INFO LOG_INFO
+#define GD_DEBUG LOG_DEBUG
+
+void gd_error(const char *format, ...);
+void gd_error_ex(int priority, const char *format, ...);
+
+#endif
diff --git a/libmscgen/gd_intern.h b/libmscgen/gd_intern.h
new file mode 100644
index 0000000..2e7264b
--- /dev/null
+++ b/libmscgen/gd_intern.h
@@ -0,0 +1,78 @@
+#ifndef GD_INTERN_H
+#define GD_INTERN_H
+
+#include <limits.h>
+#include <stdint.h>
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# elif defined(MAX_PATH)
+# define MAXPATHLEN MAX_PATH
+# else
+# if defined(__GNU__)
+# define MAXPATHLEN 4096
+# else
+# define MAXPATHLEN 256 /* Should be safe for any weird systems that do not define it */
+# endif
+# endif
+#endif
+
+#include "gd.h"
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
+#ifndef MAX
+#define MAX(a,b) ((a)<(b)?(b):(a))
+#endif
+#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
+
+
+typedef enum {
+ HORIZONTAL,
+ VERTICAL,
+} gdAxis;
+
+/* Convert a double to an unsigned char, rounding to the nearest
+ * integer and clamping the result between 0 and max. The absolute
+ * value of clr must be less than the maximum value of an unsigned
+ * short. */
+static inline unsigned char
+uchar_clamp(double clr, unsigned char max) {
+ unsigned short result;
+
+ //assert(fabs(clr) <= SHRT_MAX);
+
+ /* Casting a negative float to an unsigned short is undefined.
+ * However, casting a float to a signed truncates toward zero and
+ * casting a negative signed value to an unsigned of the same size
+ * results in a bit-identical value (assuming twos-complement
+ * arithmetic). This is what we want: all legal negative values
+ * for clr will be greater than 255. */
+
+ /* Convert and clamp. */
+ result = (unsigned short)(short)(clr + 0.5);
+ if (result > max) {
+ result = (clr < 0) ? 0 : max;
+ }/* if */
+
+ return result;
+}/* uchar_clamp*/
+
+
+/* Internal prototypes: */
+
+/* gd_rotate.c */
+gdImagePtr gdImageRotate90(gdImagePtr src, int ignoretransparent);
+gdImagePtr gdImageRotate180(gdImagePtr src, int ignoretransparent);
+gdImagePtr gdImageRotate270(gdImagePtr src, int ignoretransparent);
+
+
+
+
+
+
+#endif
+
diff --git a/libmscgen/gd_lodepng.c b/libmscgen/gd_lodepng.c
new file mode 100644
index 0000000..b8ed22b
--- /dev/null
+++ b/libmscgen/gd_lodepng.c
@@ -0,0 +1,35 @@
+#include "gd.h"
+#include "lodepng.h"
+
+BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * outFile)
+{
+ unsigned char *buffer;
+ size_t bufferSize;
+ int **ptpixels = im->tpixels;
+ unsigned char *pixelBuffer = (unsigned char *)malloc(3*im->sx*im->sy);
+ unsigned char *pOut = pixelBuffer;
+ int x,y;
+ for (y=0;y<im->sy;y++)
+ {
+ int *pThisRow = *ptpixels++;
+ for (x=0;x<im->sx;x++)
+ {
+ int thisPixel = *pThisRow++;
+ *pOut++ = gdTrueColorGetRed(thisPixel);
+ *pOut++ = gdTrueColorGetGreen(thisPixel);
+ *pOut++ = gdTrueColorGetBlue(thisPixel);
+ }
+ }
+ // TODO: convert ptPixels into pixelBuffer...
+ LodePNG_Encoder encoder;
+ LodePNG_Encoder_init(&encoder);
+ encoder.infoPng.color.colorType = 2; // 2=RGB 24 bit
+ encoder.infoRaw.color.colorType = 2; // 2=RGB 24 bit
+ LodePNG_encode(&encoder, &buffer, &bufferSize, pixelBuffer, im->sx, im->sy);
+ // write bufferSize bytes from buffer into outFile
+ fwrite(buffer,1,bufferSize,outFile);
+ LodePNG_Encoder_cleanup(&encoder);
+ free(buffer);
+ free(pixelBuffer);
+}
+
diff --git a/libmscgen/gd_security.c b/libmscgen/gd_security.c
new file mode 100644
index 0000000..0051ebf
--- /dev/null
+++ b/libmscgen/gd_security.c
@@ -0,0 +1,32 @@
+/*
+ * gd_security.c
+ *
+ * Implements buffer overflow check routines.
+ *
+ * Written 2004, Phil Knirsch.
+ * Based on netpbm fixes by Alan Cox.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "gd.h"
+#include "gd_errors.h"
+
+int overflow2(int a, int b)
+{
+ if(a <= 0 || b <= 0) {
+ gd_error_ex(GD_WARNING, "one parameter to a memory allocation multiplication is negative or zero, failing operation gracefully\n");
+ return 1;
+ }
+ if(a > INT_MAX / b) {
+ gd_error_ex(GD_WARNING, "product of memory allocation multiplication would exceed INT_MAX, failing operation gracefully\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/libmscgen/gdfonts.c b/libmscgen/gdfonts.c
new file mode 100644
index 0000000..e184e36
--- /dev/null
+++ b/libmscgen/gdfonts.c
@@ -0,0 +1,3890 @@
+/*
+ This is a header file for gd font, generated using
+ bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
+ from bdf font
+ -misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2
+ at Thu Jan 8 14:13:20 1998.
+ No copyright info was found in the original bdf.
+ */
+
+/**
+ * File: Small Font
+ *
+ * A small ISO-8859-2 raster font (7x13 pixels).
+ *
+ * The font is supposed to be used with <gdImageChar> and <gdImageString>
+ * and their variants.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gdfonts.h"
+
+char gdFontSmallData[] = {
+ /* Char 0 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 1 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 2 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1, 0,
+
+ /* Char 3 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 4 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 5 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 6 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 7 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 8 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 9 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 10 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 11 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 12 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 13 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 14 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 15 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 16 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 17 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 18 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 19 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 20 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 21 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 22 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 23 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 24 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 25 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 26 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 27 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 28 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 29 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 30 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 31 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 32 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 33 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 34 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 35 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 36 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 37 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 38 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 39 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 40 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 41 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 42 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 43 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 44 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 45 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 46 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 47 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 48 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 49 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 50 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 51 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 52 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 53 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 54 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 55 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 56 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 57 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 58 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 59 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 60 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 61 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 62 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 63 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 64 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 65 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 66 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 67 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 68 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 69 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 70 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 71 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 72 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 73 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 74 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 75 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 76 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 77 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 1, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 78 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 79 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 80 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 81 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 82 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 83 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 84 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 85 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 86 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 87 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 88 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 89 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 90 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 91 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 92 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 93 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 94 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 95 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 96 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 97 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 98 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 99 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 100 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 101 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 102 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 103 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+
+ /* Char 104 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 105 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 106 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+
+ /* Char 107 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 108 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 109 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 0, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 110 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 111 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 112 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+
+ /* Char 113 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+
+ /* Char 114 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 115 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 116 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 117 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 118 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 119 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 120 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 121 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+
+ /* Char 122 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 123 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 124 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 125 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 126 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 127 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 128 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 129 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 130 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 131 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 132 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 133 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 134 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 135 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 136 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 137 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 138 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 139 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 140 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 141 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 142 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 143 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 144 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 145 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 146 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 147 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 148 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 149 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 150 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 151 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 152 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 153 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 154 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 155 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 156 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 157 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 158 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 159 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 160 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 161 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 1,
+
+ /* Char 162 */
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 163 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 164 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 165 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 166 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 167 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 168 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 169 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 170 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+
+ /* Char 171 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 172 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 173 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 174 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 175 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 176 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 177 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 1, 1,
+
+ /* Char 178 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+
+ /* Char 179 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 180 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 181 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1,
+ 0, 1, 1, 0, 0, 1,
+ 0, 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 182 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 183 */
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 184 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+
+ /* Char 185 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 186 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+
+ /* Char 187 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 188 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 189 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 1,
+ 0, 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 190 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 191 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 192 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 193 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 194 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 195 */
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 196 */
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 197 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 198 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 199 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+
+ /* Char 200 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 201 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 202 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+
+ /* Char 203 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 204 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 205 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 206 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 207 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 208 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 209 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 210 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 211 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 212 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 213 */
+ 0, 0, 1, 0, 0, 1,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 214 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 215 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 216 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 217 */
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 218 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 219 */
+ 0, 0, 1, 0, 0, 1,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 220 */
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 221 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 222 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 223 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 224 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 225 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 226 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 227 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 228 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 229 */
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 230 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 231 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+
+ /* Char 232 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 233 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 234 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+
+ /* Char 235 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 236 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 237 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 238 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 239 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 240 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 241 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 242 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 243 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 244 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 245 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 246 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 247 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 248 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 249 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 250 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 251 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 252 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+ /* Char 253 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0,
+ 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0, 0,
+
+ /* Char 254 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0,
+ 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+
+ /* Char 255 */
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+
+
+};
+
+gdFont gdFontSmallRep = {
+ 256,
+ 0,
+ 6,
+ 13,
+ gdFontSmallData
+};
+
+BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall = &gdFontSmallRep;
+
+/**
+ * Function: gdFontGetSmall
+ *
+ * Returns the built-in small font.
+ */
+BGD_DECLARE(gdFontPtr)
+gdFontGetSmall (void)
+{
+ return gdFontSmall;
+}
+
+/* This file has not been truncated. */
diff --git a/libmscgen/gdfonts.h b/libmscgen/gdfonts.h
new file mode 100644
index 0000000..b5127e9
--- /dev/null
+++ b/libmscgen/gdfonts.h
@@ -0,0 +1,27 @@
+#ifndef _GDFONTS_H_
+#define _GDFONTS_H_ 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ This is a header file for gd font, generated using
+ bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
+ from bdf font
+ -misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2
+ at Thu Jan 8 14:13:20 1998.
+ No copyright info was found in the original bdf.
+ */
+
+#include "gd.h"
+
+extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall;
+BGD_DECLARE(gdFontPtr) gdFontGetSmall(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmscgen/gdfontt.c b/libmscgen/gdfontt.c
new file mode 100644
index 0000000..e7bb345
--- /dev/null
+++ b/libmscgen/gdfontt.c
@@ -0,0 +1,2613 @@
+
+
+/*
+ This is a header file for gd font, generated using
+ bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
+ from bdf font
+ -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2
+ at Thu Jan 8 13:49:54 1998.
+ The original bdf was holding following copyright:
+ "Libor Skarvada, libor@informatics.muni.cz"
+ */
+
+/**
+ * File: Tiny Font
+ *
+ * A very small ISO-8859-2 raster font (5x8 pixels).
+ *
+ * The font is supposed to be used with <gdImageChar> and <gdImageString>
+ * and their variants.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gdfontt.h"
+
+char gdFontTinyData[] = {
+ /* Char 0 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 1 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 2 */
+ 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+
+ /* Char 3 */
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+
+ /* Char 4 */
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0,
+ 1, 0, 1, 1, 1,
+ 1, 0, 1, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 5 */
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 1,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 1,
+
+ /* Char 6 */
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 7 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 8 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 9 */
+ 1, 0, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 1,
+
+ /* Char 10 */
+ 1, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+
+ /* Char 11 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 12 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 13 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 14 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 15 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 16 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 17 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 18 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 19 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 20 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 21 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 22 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 23 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 24 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 25 */
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 26 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 27 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 28 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 29 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 30 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 1, 0, 0, 1,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 1,
+ 1, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 31 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 32 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 33 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 34 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 35 */
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 1, 1,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 36 */
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 1,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 37 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 1,
+ 1, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 1,
+ 1, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0,
+
+ /* Char 38 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 1,
+ 0, 0, 0, 0, 0,
+
+ /* Char 39 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 40 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 41 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 42 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 43 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 44 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 45 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 46 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 47 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 48 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 49 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 50 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 51 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 52 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 53 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 54 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 55 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 56 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 57 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 58 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 59 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+
+ /* Char 60 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 61 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 62 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 63 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 64 */
+ 0, 0, 1, 1, 0,
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+
+ /* Char 65 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 66 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 67 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 68 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 69 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 70 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 71 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 72 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 73 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 74 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 75 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 76 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 77 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 78 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 1, 1, 0,
+ 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 79 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 80 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 81 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+
+ /* Char 82 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 83 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 84 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 85 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 86 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 87 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 88 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 89 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 90 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 91 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 92 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0,
+
+ /* Char 93 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 94 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 95 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+
+ /* Char 96 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 97 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 98 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 99 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 100 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 101 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 102 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 103 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+
+ /* Char 104 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 105 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 106 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+
+ /* Char 107 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 108 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 109 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0,
+
+ /* Char 110 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 111 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 112 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+
+ /* Char 113 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0,
+
+ /* Char 114 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 115 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 116 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 117 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 118 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 119 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1,
+ 1, 0, 1, 0, 1,
+ 1, 0, 1, 0, 1,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 120 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 121 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+
+ /* Char 122 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 123 */
+ 0, 0, 1, 1, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 124 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 125 */
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 126 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 127 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 128 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 129 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 130 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 131 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 132 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 133 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 134 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 135 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 136 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 137 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 138 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 139 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 140 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 141 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 142 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 143 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 144 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 145 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 146 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 147 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 148 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 149 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 150 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 151 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 152 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 153 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 154 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 155 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 156 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 157 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 158 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 159 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 160 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 161 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 0, 0, 1, 1,
+
+ /* Char 162 */
+ 1, 0, 0, 0, 1,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 163 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0,
+
+ /* Char 164 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1,
+ 0, 1, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 165 */
+ 0, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 166 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 167 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 1, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+
+ /* Char 168 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 169 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 170 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+
+ /* Char 171 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 172 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 173 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 174 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 175 */
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 176 */
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 177 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 1, 1,
+
+ /* Char 178 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 1, 1,
+
+ /* Char 179 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 180 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 181 */
+ 0, 0, 0, 1, 1,
+ 1, 1, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 182 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 183 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 184 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+
+ /* Char 185 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 186 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+
+ /* Char 187 */
+ 0, 0, 0, 1, 1,
+ 0, 1, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 188 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 189 */
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 190 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 191 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 192 */
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 193 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 194 */
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 195 */
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 196 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 197 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 198 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 199 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 1, 0, 0, 0,
+
+ /* Char 200 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 201 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 202 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1,
+
+ /* Char 203 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 204 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 205 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 206 */
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 207 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 208 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 1, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 209 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 210 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 1, 1, 1, 1, 0,
+ 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 211 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 212 */
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 213 */
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 214 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 215 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 216 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 217 */
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 218 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 219 */
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 220 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 221 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 222 */
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+
+ /* Char 223 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 0,
+
+ /* Char 224 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 225 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 226 */
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 227 */
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 228 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 229 */
+ 0, 0, 0, 0, 1,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 230 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 231 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 1, 1, 0, 0,
+
+ /* Char 232 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 233 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 234 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 1,
+
+ /* Char 235 */
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 236 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 1, 0,
+ 1, 1, 0, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 237 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 238 */
+ 0, 0, 1, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 239 */
+ 0, 0, 0, 1, 1,
+ 0, 0, 1, 0, 1,
+ 0, 0, 1, 0, 1,
+ 0, 1, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 240 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 1, 1,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 241 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 242 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 243 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 244 */
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 245 */
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 246 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 247 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 248 */
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 1, 0, 0,
+ 1, 1, 0, 1, 0,
+ 1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 249 */
+ 0, 1, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 250 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 251 */
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 252 */
+ 1, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 1, 1, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0,
+
+ /* Char 253 */
+ 0, 0, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0,
+ 0, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0,
+ 0, 1, 1, 0, 0,
+
+ /* Char 254 */
+ 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 1, 0, 0, 0,
+ 0, 1, 0, 1, 0,
+ 0, 0, 1, 0, 0,
+ 0, 1, 1, 0, 0,
+
+ /* Char 255 */
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+
+
+};
+
+gdFont gdFontTinyRep = {
+ 256,
+ 0,
+ 5,
+ 8,
+ gdFontTinyData
+};
+
+BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny = &gdFontTinyRep;
+
+/**
+ * Function: gdFontGetTiny
+ *
+ * Returns the built-in tiny font.
+ */
+BGD_DECLARE(gdFontPtr)
+gdFontGetTiny (void)
+{
+ return gdFontTiny;
+}
+
+/* This file has not been truncated. */
diff --git a/libmscgen/gdfontt.h b/libmscgen/gdfontt.h
new file mode 100644
index 0000000..d61b01f
--- /dev/null
+++ b/libmscgen/gdfontt.h
@@ -0,0 +1,28 @@
+#ifndef _GDFONTT_H_
+#define _GDFONTT_H_ 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ This is a header file for gd font, generated using
+ bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz
+ from bdf font
+ -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2
+ at Thu Jan 8 13:49:54 1998.
+ The original bdf was holding following copyright:
+ "Libor Skarvada, libor@informatics.muni.cz"
+ */
+
+#include "gd.h"
+
+extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny;
+BGD_DECLARE(gdFontPtr) gdFontGetTiny(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmscgen/gdhelpers.c b/libmscgen/gdhelpers.c
new file mode 100644
index 0000000..20fff5c
--- /dev/null
+++ b/libmscgen/gdhelpers.c
@@ -0,0 +1,118 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gd.h"
+#include "gdhelpers.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <ctype.h>
+
+/* TBB: gd_strtok_r is not portable; provide an implementation */
+
+#define SEP_TEST (separators[*((unsigned char *) s)])
+
+char *
+gd_strtok_r (char *s, char *sep, char **state)
+{
+ char separators[256];
+ char *result = 0;
+ memset (separators, 0, sizeof (separators));
+ while (*sep) {
+ separators[*((unsigned char *) sep)] = 1;
+ sep++;
+ }
+ if (!s) {
+ /* Pick up where we left off */
+ s = *state;
+ }
+ /* 1. EOS */
+ if (!(*s)) {
+ *state = s;
+ return 0;
+ }
+ /* 2. Leading separators, if any */
+ if (SEP_TEST) {
+ do {
+ s++;
+ } while (SEP_TEST);
+ /* 2a. EOS after separators only */
+ if (!(*s)) {
+ *state = s;
+ return 0;
+ }
+ }
+ /* 3. A token */
+ result = s;
+ do {
+ /* 3a. Token at end of string */
+ if (!(*s)) {
+ *state = s;
+ return result;
+ }
+ s++;
+ } while (!SEP_TEST);
+ /* 4. Terminate token and skip trailing separators */
+ *s = '\0';
+ do {
+ s++;
+ } while (SEP_TEST);
+ /* 5. Return token */
+ *state = s;
+ return result;
+}
+
+void * gdCalloc (size_t nmemb, size_t size)
+{
+ return calloc (nmemb, size);
+}
+
+void *
+gdMalloc (size_t size)
+{
+ return malloc (size);
+}
+
+void *
+gdRealloc (void *ptr, size_t size)
+{
+ return realloc (ptr, size);
+}
+
+void *
+gdReallocEx (void *ptr, size_t size)
+{
+ void *newPtr = gdRealloc (ptr, size);
+ if (!newPtr && ptr)
+ gdFree(ptr);
+ return newPtr;
+}
+
+/*
+ Function: gdFree
+
+ Frees memory that has been allocated by libgd functions.
+
+ Unless more specialized functions exists (for instance, <gdImageDestroy>),
+ all memory that has been allocated by public libgd functions has to be
+ freed by calling <gdFree>, and not by free(3), because libgd internally
+ doesn't use alloc(3) and friends but rather its own allocation functions,
+ which are, however, not publicly available.
+
+ Parameters:
+
+ ptr - Pointer to the memory space to free. If it is NULL, no operation is
+ performed.
+
+ Returns:
+
+ Nothing.
+*/
+BGD_DECLARE(void) gdFree (void *ptr)
+{
+ free (ptr);
+}
+
+
diff --git a/libmscgen/gdhelpers.h b/libmscgen/gdhelpers.h
new file mode 100644
index 0000000..2a96b8b
--- /dev/null
+++ b/libmscgen/gdhelpers.h
@@ -0,0 +1,76 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GDHELPERS_H
+#define GDHELPERS_H 1
+
+ /* sys/types.h is needed for size_t on Sparc-SunOS-4.1 */
+#ifndef _WIN32_WCE
+#include <sys/types.h>
+#else
+#include <stdlib.h>
+#endif /* _WIN32_WCE */
+
+ /* TBB: strtok_r is not universal; provide an implementation of it. */
+
+ char * gd_strtok_r (char *s, char *sep, char **state);
+
+ /* These functions wrap memory management. gdFree is
+ in gd.h, where callers can utilize it to correctly
+ free memory allocated by these functions with the
+ right version of free(). */
+ void *gdCalloc (size_t nmemb, size_t size);
+ void *gdMalloc (size_t size);
+ void *gdRealloc (void *ptr, size_t size);
+ /* The extended version of gdReallocEx will free *ptr if the
+ * realloc fails */
+ void *gdReallocEx (void *ptr, size_t size);
+
+ /* Returns nonzero if multiplying the two quantities will
+ result in integer overflow. Also returns nonzero if
+ either quantity is negative. By Phil Knirsch based on
+ netpbm fixes by Alan Cox. */
+
+ int overflow2(int a, int b);
+
+ /* 2.0.16: portable mutex support for thread safety. */
+#if defined(CPP_SHARP)
+# define gdMutexDeclare(x)
+# define gdMutexSetup(x)
+# define gdMutexShutdown(x)
+# define gdMutexLock(x)
+# define gdMutexUnlock(x)
+#elif defined(_WIN32)
+ /* 2.0.18: must include windows.h to get CRITICAL_SECTION. */
+# include <windows.h>
+# define gdMutexDeclare(x) CRITICAL_SECTION x
+# define gdMutexSetup(x) InitializeCriticalSection(&x)
+# define gdMutexShutdown(x) DeleteCriticalSection(&x)
+# define gdMutexLock(x) EnterCriticalSection(&x)
+# define gdMutexUnlock(x) LeaveCriticalSection(&x)
+#elif defined(HAVE_PTHREAD)
+# include <pthread.h>
+# define gdMutexDeclare(x) pthread_mutex_t x
+# define gdMutexSetup(x) pthread_mutex_init(&x, 0)
+# define gdMutexShutdown(x) pthread_mutex_destroy(&x)
+# define gdMutexLock(x) pthread_mutex_lock(&x)
+# define gdMutexUnlock(x) pthread_mutex_unlock(&x)
+#else
+# define gdMutexDeclare(x)
+# define gdMutexSetup(x)
+# define gdMutexShutdown(x)
+# define gdMutexLock(x)
+# define gdMutexUnlock(x)
+#endif /* _WIN32 || HAVE_PTHREAD */
+
+#define DPCM2DPI(dpcm) (unsigned int)((dpcm)*2.54 + 0.5)
+#define DPM2DPI(dpm) (unsigned int)((dpm)*0.0254 + 0.5)
+#define DPI2DPCM(dpi) (unsigned int)((dpi)/2.54 + 0.5)
+#define DPI2DPM(dpi) (unsigned int)((dpi)/0.0254 + 0.5)
+
+#endif /* GDHELPERS_H */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libmscgen/gdtables.c b/libmscgen/gdtables.c
new file mode 100644
index 0000000..7753b21
--- /dev/null
+++ b/libmscgen/gdtables.c
@@ -0,0 +1,726 @@
+
+const int gdCosT[] = {
+ 1024,
+ 1023,
+ 1023,
+ 1022,
+ 1021,
+ 1020,
+ 1018,
+ 1016,
+ 1014,
+ 1011,
+ 1008,
+ 1005,
+ 1001,
+ 997,
+ 993,
+ 989,
+ 984,
+ 979,
+ 973,
+ 968,
+ 962,
+ 955,
+ 949,
+ 942,
+ 935,
+ 928,
+ 920,
+ 912,
+ 904,
+ 895,
+ 886,
+ 877,
+ 868,
+ 858,
+ 848,
+ 838,
+ 828,
+ 817,
+ 806,
+ 795,
+ 784,
+ 772,
+ 760,
+ 748,
+ 736,
+ 724,
+ 711,
+ 698,
+ 685,
+ 671,
+ 658,
+ 644,
+ 630,
+ 616,
+ 601,
+ 587,
+ 572,
+ 557,
+ 542,
+ 527,
+ 512,
+ 496,
+ 480,
+ 464,
+ 448,
+ 432,
+ 416,
+ 400,
+ 383,
+ 366,
+ 350,
+ 333,
+ 316,
+ 299,
+ 282,
+ 265,
+ 247,
+ 230,
+ 212,
+ 195,
+ 177,
+ 160,
+ 142,
+ 124,
+ 107,
+ 89,
+ 71,
+ 53,
+ 35,
+ 17,
+ 0,
+ -17,
+ -35,
+ -53,
+ -71,
+ -89,
+ -107,
+ -124,
+ -142,
+ -160,
+ -177,
+ -195,
+ -212,
+ -230,
+ -247,
+ -265,
+ -282,
+ -299,
+ -316,
+ -333,
+ -350,
+ -366,
+ -383,
+ -400,
+ -416,
+ -432,
+ -448,
+ -464,
+ -480,
+ -496,
+ -512,
+ -527,
+ -542,
+ -557,
+ -572,
+ -587,
+ -601,
+ -616,
+ -630,
+ -644,
+ -658,
+ -671,
+ -685,
+ -698,
+ -711,
+ -724,
+ -736,
+ -748,
+ -760,
+ -772,
+ -784,
+ -795,
+ -806,
+ -817,
+ -828,
+ -838,
+ -848,
+ -858,
+ -868,
+ -877,
+ -886,
+ -895,
+ -904,
+ -912,
+ -920,
+ -928,
+ -935,
+ -942,
+ -949,
+ -955,
+ -962,
+ -968,
+ -973,
+ -979,
+ -984,
+ -989,
+ -993,
+ -997,
+ -1001,
+ -1005,
+ -1008,
+ -1011,
+ -1014,
+ -1016,
+ -1018,
+ -1020,
+ -1021,
+ -1022,
+ -1023,
+ -1023,
+ -1024,
+ -1023,
+ -1023,
+ -1022,
+ -1021,
+ -1020,
+ -1018,
+ -1016,
+ -1014,
+ -1011,
+ -1008,
+ -1005,
+ -1001,
+ -997,
+ -993,
+ -989,
+ -984,
+ -979,
+ -973,
+ -968,
+ -962,
+ -955,
+ -949,
+ -942,
+ -935,
+ -928,
+ -920,
+ -912,
+ -904,
+ -895,
+ -886,
+ -877,
+ -868,
+ -858,
+ -848,
+ -838,
+ -828,
+ -817,
+ -806,
+ -795,
+ -784,
+ -772,
+ -760,
+ -748,
+ -736,
+ -724,
+ -711,
+ -698,
+ -685,
+ -671,
+ -658,
+ -644,
+ -630,
+ -616,
+ -601,
+ -587,
+ -572,
+ -557,
+ -542,
+ -527,
+ -512,
+ -496,
+ -480,
+ -464,
+ -448,
+ -432,
+ -416,
+ -400,
+ -383,
+ -366,
+ -350,
+ -333,
+ -316,
+ -299,
+ -282,
+ -265,
+ -247,
+ -230,
+ -212,
+ -195,
+ -177,
+ -160,
+ -142,
+ -124,
+ -107,
+ -89,
+ -71,
+ -53,
+ -35,
+ -17,
+ 0,
+ 17,
+ 35,
+ 53,
+ 71,
+ 89,
+ 107,
+ 124,
+ 142,
+ 160,
+ 177,
+ 195,
+ 212,
+ 230,
+ 247,
+ 265,
+ 282,
+ 299,
+ 316,
+ 333,
+ 350,
+ 366,
+ 383,
+ 400,
+ 416,
+ 432,
+ 448,
+ 464,
+ 480,
+ 496,
+ 512,
+ 527,
+ 542,
+ 557,
+ 572,
+ 587,
+ 601,
+ 616,
+ 630,
+ 644,
+ 658,
+ 671,
+ 685,
+ 698,
+ 711,
+ 724,
+ 736,
+ 748,
+ 760,
+ 772,
+ 784,
+ 795,
+ 806,
+ 817,
+ 828,
+ 838,
+ 848,
+ 858,
+ 868,
+ 877,
+ 886,
+ 895,
+ 904,
+ 912,
+ 920,
+ 928,
+ 935,
+ 942,
+ 949,
+ 955,
+ 962,
+ 968,
+ 973,
+ 979,
+ 984,
+ 989,
+ 993,
+ 997,
+ 1001,
+ 1005,
+ 1008,
+ 1011,
+ 1014,
+ 1016,
+ 1018,
+ 1020,
+ 1021,
+ 1022,
+ 1023,
+ 1023
+};
+
+const int gdSinT[] = {
+ 0,
+ 17,
+ 35,
+ 53,
+ 71,
+ 89,
+ 107,
+ 124,
+ 142,
+ 160,
+ 177,
+ 195,
+ 212,
+ 230,
+ 247,
+ 265,
+ 282,
+ 299,
+ 316,
+ 333,
+ 350,
+ 366,
+ 383,
+ 400,
+ 416,
+ 432,
+ 448,
+ 464,
+ 480,
+ 496,
+ 512,
+ 527,
+ 542,
+ 557,
+ 572,
+ 587,
+ 601,
+ 616,
+ 630,
+ 644,
+ 658,
+ 671,
+ 685,
+ 698,
+ 711,
+ 724,
+ 736,
+ 748,
+ 760,
+ 772,
+ 784,
+ 795,
+ 806,
+ 817,
+ 828,
+ 838,
+ 848,
+ 858,
+ 868,
+ 877,
+ 886,
+ 895,
+ 904,
+ 912,
+ 920,
+ 928,
+ 935,
+ 942,
+ 949,
+ 955,
+ 962,
+ 968,
+ 973,
+ 979,
+ 984,
+ 989,
+ 993,
+ 997,
+ 1001,
+ 1005,
+ 1008,
+ 1011,
+ 1014,
+ 1016,
+ 1018,
+ 1020,
+ 1021,
+ 1022,
+ 1023,
+ 1023,
+ 1024,
+ 1023,
+ 1023,
+ 1022,
+ 1021,
+ 1020,
+ 1018,
+ 1016,
+ 1014,
+ 1011,
+ 1008,
+ 1005,
+ 1001,
+ 997,
+ 993,
+ 989,
+ 984,
+ 979,
+ 973,
+ 968,
+ 962,
+ 955,
+ 949,
+ 942,
+ 935,
+ 928,
+ 920,
+ 912,
+ 904,
+ 895,
+ 886,
+ 877,
+ 868,
+ 858,
+ 848,
+ 838,
+ 828,
+ 817,
+ 806,
+ 795,
+ 784,
+ 772,
+ 760,
+ 748,
+ 736,
+ 724,
+ 711,
+ 698,
+ 685,
+ 671,
+ 658,
+ 644,
+ 630,
+ 616,
+ 601,
+ 587,
+ 572,
+ 557,
+ 542,
+ 527,
+ 512,
+ 496,
+ 480,
+ 464,
+ 448,
+ 432,
+ 416,
+ 400,
+ 383,
+ 366,
+ 350,
+ 333,
+ 316,
+ 299,
+ 282,
+ 265,
+ 247,
+ 230,
+ 212,
+ 195,
+ 177,
+ 160,
+ 142,
+ 124,
+ 107,
+ 89,
+ 71,
+ 53,
+ 35,
+ 17,
+ 0,
+ -17,
+ -35,
+ -53,
+ -71,
+ -89,
+ -107,
+ -124,
+ -142,
+ -160,
+ -177,
+ -195,
+ -212,
+ -230,
+ -247,
+ -265,
+ -282,
+ -299,
+ -316,
+ -333,
+ -350,
+ -366,
+ -383,
+ -400,
+ -416,
+ -432,
+ -448,
+ -464,
+ -480,
+ -496,
+ -512,
+ -527,
+ -542,
+ -557,
+ -572,
+ -587,
+ -601,
+ -616,
+ -630,
+ -644,
+ -658,
+ -671,
+ -685,
+ -698,
+ -711,
+ -724,
+ -736,
+ -748,
+ -760,
+ -772,
+ -784,
+ -795,
+ -806,
+ -817,
+ -828,
+ -838,
+ -848,
+ -858,
+ -868,
+ -877,
+ -886,
+ -895,
+ -904,
+ -912,
+ -920,
+ -928,
+ -935,
+ -942,
+ -949,
+ -955,
+ -962,
+ -968,
+ -973,
+ -979,
+ -984,
+ -989,
+ -993,
+ -997,
+ -1001,
+ -1005,
+ -1008,
+ -1011,
+ -1014,
+ -1016,
+ -1018,
+ -1020,
+ -1021,
+ -1022,
+ -1023,
+ -1023,
+ -1024,
+ -1023,
+ -1023,
+ -1022,
+ -1021,
+ -1020,
+ -1018,
+ -1016,
+ -1014,
+ -1011,
+ -1008,
+ -1005,
+ -1001,
+ -997,
+ -993,
+ -989,
+ -984,
+ -979,
+ -973,
+ -968,
+ -962,
+ -955,
+ -949,
+ -942,
+ -935,
+ -928,
+ -920,
+ -912,
+ -904,
+ -895,
+ -886,
+ -877,
+ -868,
+ -858,
+ -848,
+ -838,
+ -828,
+ -817,
+ -806,
+ -795,
+ -784,
+ -772,
+ -760,
+ -748,
+ -736,
+ -724,
+ -711,
+ -698,
+ -685,
+ -671,
+ -658,
+ -644,
+ -630,
+ -616,
+ -601,
+ -587,
+ -572,
+ -557,
+ -542,
+ -527,
+ -512,
+ -496,
+ -480,
+ -464,
+ -448,
+ -432,
+ -416,
+ -400,
+ -383,
+ -366,
+ -350,
+ -333,
+ -316,
+ -299,
+ -282,
+ -265,
+ -247,
+ -230,
+ -212,
+ -195,
+ -177,
+ -160,
+ -142,
+ -124,
+ -107,
+ -89,
+ -71,
+ -53,
+ -35,
+ -17
+};
diff --git a/libmscgen/mscgen_adraw.c b/libmscgen/mscgen_adraw.c
new file mode 100644
index 0000000..8e638a5
--- /dev/null
+++ b/libmscgen/mscgen_adraw.c
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *
+ * $Id: adraw.c 161 2010-10-26 20:17:16Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+/***************************************************************************
+ * Include Files
+ ***************************************************************************/
+
+#include "mscgen_config.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include "mscgen_adraw_int.h"
+
+/***************************************************************************
+ * Functions
+ ***************************************************************************/
+
+Boolean ADrawOpen(unsigned int w,
+ unsigned int h,
+ const char *file,
+ const char *fontName,
+ ADrawOutputType type,
+ struct ADrawTag *outContext)
+{
+ assert(outContext);
+
+ switch(type)
+ {
+ case ADRAW_FMT_NULL:
+ return NullInit(outContext);
+
+ case ADRAW_FMT_PNG:
+#if !defined(REMOVE_PNG_OUTPUT)
+ return GdoInit(w, h, file, fontName, outContext);
+#else
+ fprintf(stderr, "Built with REMOVE_PNG_OUTPUT; PNG output is not supported\n");
+ return FALSE;
+#endif
+ case ADRAW_FMT_EPS:
+ return PsInit(w, h, file, outContext);
+
+ case ADRAW_FMT_SVG:
+ return SvgInit(w, h, file, outContext);
+
+ default:
+ return FALSE;
+ }
+}
+
+
+ADrawColour ADrawGetColour(const char *colour)
+{
+ assert(colour != NULL);
+
+ /* Check if an RGB value has been specified */
+ if(*colour == '#')
+ {
+ unsigned int c = ADRAW_COL_BLACK;
+
+ if(sscanf(&colour[1], "%x", &c) == 1)
+ {
+ return (ADrawColour)c;
+ }
+ }
+ else /* Check for name matches */
+ {
+ static const struct
+ {
+ char *name;
+ ADrawColour col;
+ }
+ colourMap[] =
+ {
+ { "WHITE", ADRAW_COL_WHITE },
+ { "BLACK", ADRAW_COL_BLACK },
+ { "RED", ADRAW_COL_RED },
+ { "ORANGE", ADRAW_COL_ORANGE },
+ { "YELLOW", ADRAW_COL_YELLOW },
+ { "GREEN", ADRAW_COL_GREEN },
+ { "BLUE", ADRAW_COL_BLUE },
+ { "INDIGO", ADRAW_COL_INDIGO },
+ { "VIOLET", ADRAW_COL_VIOLET },
+ { "SILVER", ADRAW_COL_SILVER },
+ { "LIME", ADRAW_COL_LIME },
+ { "GRAY", ADRAW_COL_GRAY },
+ { "OLIVE", ADRAW_COL_OLIVE },
+ { "MAROON", ADRAW_COL_MAROON },
+ { "NAVY", ADRAW_COL_NAVY },
+ { "PURPLE", ADRAW_COL_PURPLE },
+ { "TEAL", ADRAW_COL_TEAL },
+ { "FUCHSIA", ADRAW_COL_FUCHSIA },
+ { "AQUA", ADRAW_COL_AQUA }
+ };
+
+ unsigned int t;
+
+ for(t = 0; t < sizeof(colourMap) / sizeof(colourMap[0]); t++)
+ {
+ if(strcasecmp(colour, colourMap[t].name) == 0)
+ {
+ return colourMap[t].col;
+ }
+ }
+ }
+
+ /* Default to black if all else failed */
+ return ADRAW_COL_BLACK;
+}
+
+
+void ADrawComputeArcPoint(float cx, float cy, float w, float h, float degrees,
+ unsigned int *x, unsigned int *y)
+{
+ float rad = (float)((degrees * M_PI) / 180.0f);
+
+ *x = (unsigned int)round(cx + ((w / 2.0f) * cos(rad)));
+ *y = (unsigned int)round(cy + ((h / 2.0f) * sin(rad)));
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_adraw.h b/libmscgen/mscgen_adraw.h
new file mode 100644
index 0000000..b2e11a3
--- /dev/null
+++ b/libmscgen/mscgen_adraw.h
@@ -0,0 +1,300 @@
+/***************************************************************************
+ *
+ * $Id: adraw.h 161 2010-10-26 20:17:16Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#ifndef MSCGEN_ADRAW_H
+#define MSCGEN_ADRAW_H
+
+#include "mscgen_bool.h"
+
+/***************************************************************************
+ * Types
+ ***************************************************************************/
+
+/** Output format types.
+ * Enumerated types for output formats.
+ */
+typedef enum
+{
+ /** Null output format.
+ * This allows all the graphics commands to be called, but does nothing.
+ */
+ ADRAW_FMT_NULL = 0,
+
+ /** Generate a PNG. */
+ ADRAW_FMT_PNG,
+
+ /** Generate Encapsulated Postscript. */
+ ADRAW_FMT_EPS,
+
+ /** Scalable Vector Graphics. */
+ ADRAW_FMT_SVG
+}
+ADrawOutputType;
+
+
+/** Supported colours.
+ * Enumerated type to describe colours.
+ *
+ * The 16 basic HTML colours at http://www.w3.org/TR/html4/types.html#h-6.5
+ * are defined as well as a few other common colour names.
+ */
+typedef enum
+{
+ ADRAW_COL_WHITE = 0x00ffffff,
+ ADRAW_COL_BLACK = 0x00000000,
+ ADRAW_COL_RED = 0x00ff0000,
+ ADRAW_COL_ORANGE = 0x00ffb000,
+ ADRAW_COL_YELLOW = 0x00ffff00,
+ ADRAW_COL_GREEN = 0x0000ff00,
+ ADRAW_COL_BLUE = 0x000000ff,
+ ADRAW_COL_INDIGO = 0x00440088,
+ ADRAW_COL_VIOLET = 0x00d02090,
+ ADRAW_COL_SILVER = 0x00C0C0C0,
+ ADRAW_COL_LIME = 0x0000FF00,
+ ADRAW_COL_GRAY = 0x00808080,
+ ADRAW_COL_OLIVE = 0x00808000,
+ ADRAW_COL_MAROON = 0x00800000,
+ ADRAW_COL_NAVY = 0x00000080,
+ ADRAW_COL_PURPLE = 0x00800080,
+ ADRAW_COL_TEAL = 0x00008080,
+ ADRAW_COL_FUCHSIA = 0x00FF00FF,
+ ADRAW_COL_AQUA = 0x0000FFFF,
+
+ ADRAW_COL_INVALID = 0xff000000,
+}
+ADrawColour;
+
+
+/** Basic font sizes.
+ * Enumerated type for different font sizes.
+ */
+typedef enum
+{
+ ADRAW_FONT_TINY = 0,
+ ADRAW_FONT_SMALL
+}
+ADrawFontSize;
+
+
+/** An ADraw context.
+ * This is the main structure used for accessing ADraw functions.
+ * ADrawOpen() returns an instance of this structure that can then be used
+ * to render to some device. Once drawing is complete, ADrawClose() should
+ * be called to reclaim resources and finalise any output.
+ *
+ * All the functions assume that 0,0 is in the top-left corner of the image,
+ * and that the dimensions grow towards w,y at the bottom-right corner.
+ */
+typedef struct ADrawTag
+{
+ /** Draw a line.
+ * Draw a solid straight line between two points.
+ * \param ctx The drawing context.
+ * \param x1 The first x co-ordinate,
+ * \param y1 The first y co-ordinate,
+ * \param x2 The second x co-ordinate,
+ * \param y2 The second y co-ordinate,
+ */
+ void (*line) (struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2);
+
+ /** Draw a dotted line.
+ * Draw a dotted straight line between two points.
+ * \param ctx The drawing context.
+ * \param x1 The first x co-ordinate,
+ * \param y1 The first y co-ordinate,
+ * \param x2 The second x co-ordinate,
+ * \param y2 The second y co-ordinate,
+ */
+ void (*dottedLine) (struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2);
+
+ /** Left aligned text.
+ * Write a single line of text that will end at some co-ordinates.
+ * \param ctx The drawing context.
+ * \param x The position at which the text should terminate.
+ * \param y The position above which the text will lie.
+ * \param string The string to write.
+ */
+ void (*textL) (struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string);
+
+ /** Center aligned text.
+ * Write a single line of text that will center on some co-ordinates.
+ * \param ctx The drawing context.
+ * \param x The position at which the text should be centered.
+ * \param y The position above which the text will lie.
+ * \param string The string to write.
+ */
+ void (*textC) (struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string);
+
+ /** Right aligned text.
+ * Write a single line of text that will start at some co-ordinates.
+ * \param ctx The drawing context.
+ * \param x The position at which the text should start.
+ * \param y The position above which the text will lie.
+ * \param string The string to write.
+ */
+ void (*textR) (struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string);
+
+ /** Determine the width of some string.
+ * \param ctx The drawing context.
+ * \param string The string for which the width should be determined.
+ * \returns The width of the passed string as it would be rendered
+ * by the current drawing context.
+ */
+ unsigned int (*textWidth) (struct ADrawTag *ctx,
+ const char *string);
+
+ /** Determine the height of text in the current font.
+ * \param ctx The drawing context.
+ *
+ */
+ int (*textHeight) (struct ADrawTag *ctx);
+
+ void (*filledRectangle)(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2);
+
+ void (*filledTriangle)(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2,
+ unsigned int x3,
+ unsigned int y3);
+
+ void (*filledCircle)(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ unsigned int r);
+
+ /** Draw an arc.
+ * This draws an arc centred at (cx,cy) which fits in a box of \a w by \a h.
+ * The arc is drawn from \a s degrees to \a e degrees.
+ * \note 0 degrees points east on the page and 90 degrees is south.
+ *
+ */
+ void (*arc) (struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e);
+
+ void (*dottedArc) (struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e);
+
+ void (*setPen) (struct ADrawTag *ctx,
+ ADrawColour col);
+
+ void (*setBgPen) (struct ADrawTag *ctx,
+ ADrawColour col);
+
+ void (*setFontSize) (struct ADrawTag *ctx,
+ ADrawFontSize size);
+
+ Boolean (*close) (struct ADrawTag *context);
+
+ /* Internal context, not accessible by the user */
+ void *internal;
+}
+ADraw;
+
+/***************************************************************************
+ * Functions
+ ***************************************************************************/
+
+/** Create a new drawing context.
+ * This will create a drawing context with some dimensions, and some format.
+ * After this has been called, the function pointers in the returned structure
+ * can be called together with a pointer to the structure itself to cause
+ * image functions to be executed.
+ *
+ * \param[in] w The width of the output image.
+ * \param[in] h The height of the ouput image.
+ * \param[in] file The file to which the image should be written.
+ * \param[in] fontName The name of the font to use for rendering.
+ * \param[in] type The output type to generate.
+ * \param[in, out] *outContext Pointer to an \a ADraw structure to populate
+ * with values.
+ * \retval Boolean On error, #FALSE will be returned.
+ */
+Boolean ADrawOpen(unsigned int w,
+ unsigned int h,
+ const char *file,
+ const char *fontName,
+ ADrawOutputType type,
+ struct ADrawTag *outContext);
+
+/** Given a string name for a colour, return the corresponding ADrawColour.
+ *
+ * \param[in] colour The string representation of the colour that is sought.
+ */
+ADrawColour ADrawGetColour(const char *colour);
+
+/** Compute the position of a point on an arc.
+ * This allows co-ordinates on arc drawn using arc() or dottedArc() to be
+ * computed. The centre and bounding box for the arc are supplied as well
+ * as an angular offset.
+ *
+ * \param[in] cx Center of the arc.
+ * \param[in] cy Center of the arc.
+ * \param[in] w Arc x-diameter (width).
+ * \param[in] h Arc y-diameter (height).
+ * \param[in] degrees Position on the arc to be returned.
+ * \param[in,out] x Pointer to fill with x coordinate.
+ * \param[in,out] y Pointer to fill with y coordinate.
+ */
+void ADrawComputeArcPoint(float cx,
+ float cy,
+ float w,
+ float h,
+ float degrees,
+ unsigned int *x,
+ unsigned int *y);
+
+#endif /* MSCGEN_ADRAW_H */
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_adraw_int.h b/libmscgen/mscgen_adraw_int.h
new file mode 100644
index 0000000..6f79ca4
--- /dev/null
+++ b/libmscgen/mscgen_adraw_int.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *
+ * $Id: adraw_int.h 115 2010-08-19 09:58:45Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#ifndef MSCGEN_ADRAW_INT_H
+#define MSCGEN_ADRAW_INT_H
+
+#include "mscgen_adraw.h"
+
+/***************************************************************************
+ * Preprocessor Macros
+ ***************************************************************************/
+
+/* Define macro to supress unused parameter warnings */
+#ifndef UNUSED
+# ifdef __GNUC__
+# define UNUSED __attribute__((unused))
+# else
+# define UNUSED
+# endif
+#endif
+
+/***************************************************************************
+ * Functions
+ ***************************************************************************/
+
+Boolean NullInit(struct ADrawTag *outContext);
+
+Boolean GdoInit(unsigned int w,
+ unsigned int h,
+ const char *file,
+ const char *fontName,
+ struct ADrawTag *outContext);
+
+Boolean PsInit(unsigned int w,
+ unsigned int h,
+ const char *file,
+ struct ADrawTag *outContext);
+
+Boolean SvgInit(unsigned int w,
+ unsigned int h,
+ const char *file,
+ struct ADrawTag *outContext);
+
+#endif /* MSCGEN_ADRAW_INT_H */
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_api.c b/libmscgen/mscgen_api.c
new file mode 100644
index 0000000..0f6052a
--- /dev/null
+++ b/libmscgen/mscgen_api.c
@@ -0,0 +1,1874 @@
+#include "mscgen_api.h"
+#include "mscgen_config.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include "mscgen_lexer.h"
+#include "mscgen_adraw.h"
+#include "mscgen_msc.h"
+#include "mscgen_safe.h"
+
+/***************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define M_Max(a, b) (((a) > (b)) ? (a) : (b))
+#define M_Min(a, b) (((a) < (b)) ? (a) : (b))
+
+/***************************************************************************
+ * Types
+ ***************************************************************************/
+
+/** Structure for holding global options.
+ * This structure groups all the options that affect the text output into
+ * one structure.
+ */
+typedef struct GlobalOptionsTag
+{
+ /** Ideal width of output canvas.
+ * If this value allows the entitySpacing to be increased, then
+ * entitySpacing will be set to the larger value of it's original
+ * value and idealCanvasWidth / number of entities.
+ */
+ unsigned int idealCanvasWidth;
+
+ /** Horizontal spacing between entities. */
+ unsigned int entitySpacing;
+
+ /** Gap at the top of the page. */
+ unsigned int entityHeadGap;
+
+ /** Vertical spacing between arcs. */
+ unsigned int arcSpacing;
+
+ /** Arc gradient.
+ * Y offset of arc head, relative to tail, in pixels.
+ */
+ int arcGradient;
+
+ /** Gap between adjacent boxes. */
+ unsigned int boxSpacing;
+
+ /** Minimum distance between box edges and text. */
+ unsigned int boxInternalBorder;
+
+ /** Radius of rounded box corner arcs. */
+ unsigned int rboxArc;
+
+ /** Size of 'corner' added to note boxes. */
+ unsigned int noteCorner;
+
+ /** Anguluar box slope in pixels. */
+ unsigned int aboxSlope;
+
+ /** If TRUE, wrap arc text as well as box contents. */
+ Boolean wordWrapArcLabels;
+
+ /** Horizontal width of the arrow heads. */
+ unsigned int arrowWidth;
+
+ /** Vertical depth of the arrow heads. */
+ unsigned int arrowHeight;
+
+ /** Height of an arc which loops back to itself. */
+ unsigned int loopArcHeight;
+
+ /** Horizontal gap between text and horizontal lines. */
+ unsigned int textHGapPre;
+
+ /** Horizontal gap between text and horizontal lines. */
+ unsigned int textHGapPost;
+}
+GlobalOptions;
+
+/** Information about each out row.
+ */
+typedef struct
+{
+ /** Minimum Y value. */
+ unsigned int ymin;
+
+ /** Y position of the arc on the row. */
+ unsigned int arcliney;
+
+ /** Maximum Y value. */
+ unsigned int ymax;
+
+ /** Maximum lines of text on the row. */
+ unsigned int maxTextLines;
+}
+RowInfo;
+
+
+typedef struct ContextTag
+{
+ GlobalOptions opts;
+ ADraw drw;
+} Context;
+
+
+/***************************************************************************
+ * Local Variables.
+ ***************************************************************************/
+
+static const GlobalOptions gDefaultOpts =
+{
+ 600, /* idealCanvasWidth */
+
+ 80, /* entitySpacing */
+ 20, /* entityHeadGap */
+ 6, /* arcSpacing */
+ 0, /* arcGradient */
+ 8, /* boxSpacing */
+ 4, /* boxInternalBorder */
+ 6, /* rboxArc */
+ 12, /* noteCorner */
+ 6, /* aboxSlope */
+ FALSE, /* wordWrapArcLabels */
+
+ /* Arrow options */
+ 10, 6,
+
+ /* loopArcHeight */
+ 12,
+
+ /* textHGapPre, textHGapPost */
+ 2, 2
+};
+
+
+/***************************************************************************
+ * Functions
+ ***************************************************************************/
+
+/** Count the number of lines in some string.
+ * This counts line breaks that are written as a literal '\n' in the line to
+ * determine how many lines of output are needed.
+ *
+ * \param[in] l Pointer to the input string to inspect.
+ * \returns The count of '\n' characters appearing in the input string + 1.
+ */
+static unsigned int countLines(const char *l)
+{
+ unsigned int c = 1;
+
+ do
+ {
+ c++;
+
+ l = strstr(l, "\\n");
+ if (l) l += 2;
+ } while (l != NULL);
+
+ return c;
+}
+
+/** Check if some arc type indicates a box.
+ */
+static Boolean isBoxArc(const MscArcType a)
+{
+ return a == MSC_ARC_BOX || a == MSC_ARC_RBOX ||
+ a == MSC_ARC_ABOX || a== MSC_ARC_NOTE;
+}
+
+/** Get the skip value in pixels for some the current arc in the Msc.
+ */
+static int getArcGradient(Context *ctx, Msc m, const RowInfo *rowInfo, unsigned int row)
+{
+ const char *s = MscGetCurrentArcAttrib(m, MSC_ATTR_ARC_SKIP);
+ unsigned int v = ctx->opts.arcGradient;
+
+ if (s != NULL && rowInfo != NULL)
+ {
+ const unsigned int rowCount = MscGetNumArcs(m) - MscGetNumParallelArcs(m);
+ unsigned int skip;
+
+ if (sscanf(s, "%u", &skip) == 1)
+ {
+ unsigned int ystart = rowInfo[row].arcliney;
+ unsigned int yend = rowInfo[M_Min(rowCount - 1, row + skip)].arcliney;
+
+ v += yend - ystart;
+ }
+ else
+ {
+ fprintf(stderr, "Warning: Non-integer arcskip value: %s\n", s);
+ }
+ }
+
+ return v;
+}
+
+
+/** Check if some arc name indicates a broadcast entity.
+ */
+static Boolean isBroadcastArc(const char *entity)
+{
+ return entity != NULL && (strcmp(entity, "*") == 0);
+}
+
+/** Free memory allocated for the label lines.
+ */
+static void freeLabelLines(unsigned int n, char **lines)
+{
+ while (n > 0)
+ {
+ n--;
+ free(lines[n]);
+ }
+
+ free(lines);
+}
+
+
+/** Word wrap a line of text until the first line is less than \a width wide.
+ * This removes words from the input line and builds them into a 2nd new
+ * string until the input line is shorter than the supplied width. The
+ * input string is directly truncated, while the remaining characters are
+ * returned in a new memory allocation. On return, the input line of text
+ * will be shorter than \a width, while the newly returned string will contain
+ * all the remaining characters.
+ *
+ * If the input line is already shorter than \a width, the function returns
+ * NULL and does not modify the input line of text.
+ *
+ * \param[in,out] l Input line of text which maybe modified if needed.
+ * \param[in] width Maximum allowable text line width.
+ * \returns NULL if \a l was already less then \a width long,
+ * otherwise a new string giving the remained of the string.
+ */
+static char *splitStringToWidth(Context *ctx, char *l, unsigned int width)
+{
+ char *p = l + strlen(l);
+ char *orig = NULL;
+ int m, n;
+
+ if (ctx->drw.textWidth(&ctx->drw, l) > width)
+ {
+ /* Duplicate the original string */
+ orig = strdup_s(l);
+
+ /* Now remove words from the line until it fits the available width */
+ do
+ {
+ /* Skip back 1 word */
+ while (!isspace(*p) && p > l)
+ {
+ p--;
+ }
+
+ if (p > l)
+ {
+ *p = '\0';
+ }
+ }
+ while (ctx->drw.textWidth(&ctx->drw, l) > width && p > l);
+
+ /* Check if the first word is bigger than the available space;
+ * we need to hyphenate in this case.
+ */
+ if (p == l)
+ {
+ const unsigned int hyphenWidth = ctx->drw.textWidth(&ctx->drw, "-");
+
+ /* Find the end of the first word */
+ while (!isspace(*p) && *p != '\0')
+ {
+ p++;
+ }
+
+ /* Start removing characters from the word */
+ do
+ {
+ *p = '\0';
+ p--;
+ }
+ while (ctx->drw.textWidth(&ctx->drw, l) + hyphenWidth > width && p > l);
+
+ /* Add a hyphen */
+ *p = '-';
+ }
+
+ /* Copy the remaining line to the start of the string */
+ m = 0;
+ n = (p - l);
+
+ while (isspace(orig[n]) && orig[n] != '\0')
+ {
+ n++;
+ }
+
+ do
+ {
+ orig[m++] = orig[n++];
+ }
+ while (orig[m - 1] != '\0');
+ }
+
+ return orig;
+}
+
+
+/** Split an input arc label into lines, word-wrapping if needed.
+ * This takes the literal label supplied from the input and splits it into an
+ * array of char * text lines. Splitting is first done according to literal
+ * '\n' character sequences added by the user, then according to word wrapping
+ * to fit available space, if appropriate.
+ *
+ * \param[in] m The MSC for which the lines are to be split.
+ * \param[in] arcType The type of the arc being labelled.
+ * \param[in,out] lines Pointer to be filled with output line array.
+ * \param[in] label Original arc label from input file.
+ * \param[in] startCol Column in which the arc starts.
+ * \param[in] endCol Column in which the arc ends, or -1 for broadcast arcs.
+ *
+ * \note The returned strings and array must be free()'d. freeLabelLines() can
+ * be used for this purpose.
+ */
+static unsigned int computeLabelLines(Context *ctx,
+ Msc m,
+ const MscArcType arcType,
+ char ***lines,
+ const char *label,
+ int startCol,
+ int endCol)
+{
+ unsigned int width;
+ unsigned int nAllocLines = 8;
+ char **retLines = malloc_s(sizeof(char *) * nAllocLines);
+ unsigned int c = 0;
+
+ assert(startCol >= 0 && startCol < (signed)MscGetNumEntities(m));
+ assert(startCol >= -1 && startCol < (signed)MscGetNumEntities(m));
+
+ /* Compute available width for text */
+ if (isBoxArc(arcType) || ctx->opts.wordWrapArcLabels)
+ {
+ if (endCol == -1)
+ {
+ /* This is a special case for a broadcast arc */
+ width = ctx->opts.entitySpacing * MscGetNumEntities(m);
+ }
+ else if (startCol < endCol)
+ {
+ width = ctx->opts.entitySpacing * (1 + (endCol - startCol));
+ }
+ else
+ {
+ width = ctx->opts.entitySpacing * (1 + (startCol - endCol));
+ }
+
+ /* Reduce the width due to the box borders */
+ if (isBoxArc(arcType))
+ {
+ width -= (ctx->opts.boxSpacing + ctx->opts.boxInternalBorder) * 2;
+ }
+
+ if (arcType == MSC_ARC_NOTE)
+ {
+ width -= ctx->opts.noteCorner;
+ }
+ }
+ else
+ {
+ width = UINT_MAX;
+ }
+
+ /* Split the input label into lines */
+ while (label != NULL)
+ {
+ /* First split around user specified lines with literal '\n' */
+ char *nextLine = strstr(label, "\\n");
+ if (nextLine)
+ {
+ const int lineLen = nextLine - label;
+
+ /* Allocate storage and duplicate the line */
+ retLines[c] = malloc_s(lineLen + 1);
+ memcpy(retLines[c], label, lineLen);
+ retLines[c][lineLen] = '\0';
+
+ /* Advance the label */
+ label = nextLine + 2;
+ }
+ else
+ {
+ /* Duplicate the final line */
+ retLines[c] = strdup_s(label);
+ label = NULL;
+ }
+
+ /* Now split the line as required to wrap into the space available */
+ do
+ {
+ /* Check if more storage maybe needed */
+ if (c + 2 >= nAllocLines)
+ {
+ nAllocLines += 8;
+ retLines = realloc_s(retLines, sizeof(char *) * nAllocLines);
+ }
+
+ retLines[c + 1] = splitStringToWidth(ctx, retLines[c], width);
+ c++;
+ }
+ while (retLines[c] != NULL);
+ }
+
+ /* Return the array of lines and the count */
+ *lines = retLines;
+
+ return c;
+}
+
+
+
+/** Compute the output canvas size required for some MSC.
+ * This computes the dimensions for the canvas as well as the height for each
+ * row.
+ *
+ * \param[in] m The MSC to analyse.
+ * \param[in,out] w Pointer to be filled with the output width.
+ * \param[in,out] h Pointer to be filled with the output height.
+ * \returns An array giving the height of each row.
+ */
+static RowInfo *computeCanvasSize(Context *ctx,
+ Msc m,
+ unsigned int *w,
+ unsigned int *h)
+{
+ const unsigned int rowCount = MscGetNumArcs(m) - MscGetNumParallelArcs(m);
+ const unsigned int textHeight = ctx->drw.textHeight(&ctx->drw);
+ RowInfo *rowHeight;
+ unsigned int nextYmin, ymin, ymax, yskipmax, row;
+
+ /* Allocate storage for the height of each row */
+ rowHeight = zalloc_s(sizeof(RowInfo) * rowCount);
+ row = 0;
+
+ nextYmin = ymin = ctx->opts.entityHeadGap;
+ yskipmax = 0;
+
+ MscResetArcIterator(m);
+ do
+ {
+ const MscArcType arcType = MscGetCurrentArcType(m);
+ const int arcGradient = isBoxArc(arcType) ? 0 : getArcGradient(ctx, m, NULL, 0);
+ char **arcLabelLines = NULL;
+ unsigned int arcLabelLineCount = 0;
+ int startCol = -1, endCol = -1;
+
+ if (arcType == MSC_ARC_PARALLEL)
+ {
+ assert(row > 0);
+
+ row--;
+
+ ymin = rowHeight[row].ymin;
+ nextYmin = rowHeight[row].ymax;
+ }
+ else
+ {
+ /* Get the entity indices */
+ if (arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE)
+ {
+ startCol = MscGetEntityIndex(m, MscGetCurrentArcSource(m));
+ endCol = MscGetEntityIndex(m, MscGetCurrentArcDest(m));
+ }
+ else
+ {
+ /* Discontinuity or parallel arc spans whole chart */
+ startCol = 0;
+ endCol = MscGetNumEntities(m) - 1;
+ }
+
+ /* Work out how the label fits the gap between entities */
+ arcLabelLineCount = computeLabelLines(ctx, m, arcType, &arcLabelLines,
+ MscGetCurrentArcAttrib(m, MSC_ATTR_LABEL),
+ startCol, endCol);
+
+ assert(row < rowCount);
+
+ /* Update the max line count for the row */
+ if (arcLabelLineCount > rowHeight[row].maxTextLines)
+ {
+ rowHeight[row].maxTextLines = arcLabelLineCount;
+ }
+
+ freeLabelLines(arcLabelLineCount, arcLabelLines);
+
+ /* Compute the height of this arc */
+ if (arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE)
+ {
+ ymax = ymin + ctx->opts.arcSpacing;
+ ymax += (M_Max(rowHeight[row].maxTextLines, 2) * textHeight);
+ }
+ else
+ {
+ ymax = ymin + ctx->opts.arcSpacing;
+ ymax += (M_Max(rowHeight[row].maxTextLines, 1) * textHeight);
+ }
+
+ /* Update next potential row start */
+ if (ymax > nextYmin)
+ {
+ nextYmin = ymax;
+ }
+
+ /* Compute the dimensions for the completed row */
+ rowHeight[row].ymin = ymin;
+ rowHeight[row].ymax = nextYmin - ctx->opts.arcSpacing;
+ rowHeight[row].arcliney = rowHeight[row].ymin + (rowHeight[row].ymax - rowHeight[row].ymin) / 2;
+ row++;
+
+ /* Start new row */
+ ymin = nextYmin;
+ }
+
+ /* Keep a track of where the gradient may cause the graph to end */
+ if (ymax + arcGradient > ymax)
+ {
+ yskipmax = ymax + arcGradient;
+ }
+
+ }
+ while (MscNextArc(m));
+
+ if (ymax < yskipmax)
+ ymax = yskipmax;
+
+ /* Set the return values */
+ *w = MscGetNumEntities(m) * ctx->opts.entitySpacing;
+ *h = ymax;
+
+ return rowHeight;
+}
+
+/** Add a point to the output imagemap.
+ * If \a ismap and \a url are non-NULL, this function will add a rectangle
+ * to the imagemap according to the parameters passed.
+ *
+ * \param ismap The file to which the imagemap should be rendered.
+ * \param url The URL to which the imagemap area should link.
+ * \param x1 The x coordinate for the upper left point.
+ * \param y2 The y coordinate for the upper left point.
+ * \param x2 The x coordinate for the lower right point.
+ * \param y2 The y coordinate for the lower right point.
+ */
+static void ismapRect(FILE *ismap,
+ const char *url,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ if(ismap && url)
+ {
+ assert(x1 <= x2); assert(y1 <= y2);
+
+ fprintf(ismap,
+ "rect %s %d,%d %d,%d\n",
+ url,
+ x1, y1,
+ x2, y2);
+ }
+#if 0
+ /* For debug render a cross onto the output */
+ drw.line(&drw, x1, y1, x2, y2);
+ drw.line(&drw, x2, y1, x1, y2);
+#endif
+}
+
+
+/** Get some line from a string containing '\n' delimiters.
+ * Given a string that contains literal '\n' delimiters, return a subset in
+ * a passed buffer that gives the nth line.
+ *
+ * \param[in] string The string to parse.
+ * \param[in] line The line number to return from the string, which should
+ * count from 0.
+ * \param[in] out Pointer to a buffer to fill with line data.
+ * \param[in] outLen The length of the buffer pointed to by \a out, in bytes.
+ * \returns A pointer to \a out.
+ */
+static char *getLine(const char *string,
+ unsigned int line,
+ char *const out,
+ const unsigned int outLen)
+{
+ const char *lineStart, *lineEnd;
+ unsigned int lineLen;
+
+ /* Setup for the loop */
+ lineEnd = NULL;
+ line++;
+
+ do
+ {
+ /* Check if this is the first or a repeat iteration */
+ if(lineEnd)
+ {
+ lineStart = lineEnd + 2;
+ }
+ else
+ {
+ lineStart = string;
+ }
+
+ /* Search for next delimited */
+ lineEnd = strstr(lineStart, "\\n");
+
+ line--;
+ }
+ while (line > 0 && lineEnd != NULL);
+
+ /* Determine the length of the line */
+ if(lineEnd != NULL)
+ {
+ lineLen = lineEnd - lineStart;
+ }
+ else
+ {
+ lineLen = strlen(string) - (lineStart - string);
+ }
+
+ /* Clamp the length to the buffer */
+ if(lineLen > outLen - 1)
+ {
+ lineLen = outLen - 1;
+ }
+
+ /* Copy desired characters */
+ memcpy(out, lineStart, lineLen);
+
+ /* NULL terminate */
+ out[lineLen] = '\0';
+
+ return out;
+}
+
+
+/** Render some entity text.
+ * Draw the text for some entity.
+ * \param ismap If not \a NULL, write an ismap description here.
+ * \param x The x position at which the entity text should be centered.
+ * \param y The y position where the text should be placed.
+ * \param entLabel The label to render, which maybe \a NULL in which case
+ * no ouput is produced.
+ * \param entUrl The URL for rendering the label as a hyperlink. This
+ * maybe \a NULL if not required.
+ * \param entId The text identifier for the arc.
+ * \param entIdUrl The URL for rendering the test identifier as a hyperlink.
+ * This maybe \a NULL if not required.
+ * \param entColour The text colour name or specification for the entity text.
+ * If NULL, use default colouring scheme.
+ * \param entBgColour The text background colour name or specification for the
+ * entity text. If NULL, use default colouring scheme.
+ */
+static void entityText(Context *ctx,
+ FILE *ismap,
+ unsigned int x,
+ unsigned int y,
+ const char *entLabel,
+ const char *entUrl,
+ const char *entId,
+ const char *entIdUrl,
+ const char *entColour,
+ const char *entBgColour)
+{
+ if(entLabel)
+ {
+ const unsigned int lines = countLines(entLabel);
+ unsigned int l;
+ char lineBuffer[1024];
+
+ /* Adjust y to be above the writing line */
+ y -= ctx->drw.textHeight(&ctx->drw) * (lines - 1);
+
+ for (l = 0; l < lines - 1; l++)
+ {
+ char *lineLabel = getLine(entLabel, l, lineBuffer, sizeof(lineBuffer));
+ unsigned int width = ctx->drw.textWidth(&ctx->drw, lineLabel);
+
+ /* Push text down one line */
+ y += ctx->drw.textHeight(&ctx->drw);
+
+ /* Check if a URL is associated */
+ if(entUrl)
+ {
+ /* If no explict colour has been set, make URLS blue */
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE);
+
+ /* Image map output */
+ ismapRect(ismap,
+ entUrl,
+ x - (width / 2), y - ctx->drw.textHeight(&ctx->drw),
+ x + (width / 2), y);
+ }
+
+ /* Set to the explicit colours if directed */
+ if(entColour != NULL)
+ {
+ ctx->drw.setPen(&ctx->drw, ADrawGetColour(entColour));
+ }
+
+ if(entBgColour != NULL)
+ {
+ ctx->drw.setBgPen(&ctx->drw, ADrawGetColour(entBgColour));
+ }
+
+ /* Render text and restore pen */
+ ctx->drw.textC (&ctx->drw, x, y, lineLabel);
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+ ctx->drw.setBgPen(&ctx->drw, ADRAW_COL_WHITE);
+
+ /* Render the Id of the title, if specified and for first line only */
+ if(entId && l == 0)
+ {
+ unsigned int idwidth;
+ int idx, idy;
+
+ idy = y - ctx->drw.textHeight(&ctx->drw);
+ idx = x + (width / 2);
+
+ ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_TINY);
+
+ idwidth = ctx->drw.textWidth(&ctx->drw, entId);
+ idy += (ctx->drw.textHeight(&ctx->drw) + 1) / 2;
+
+ if(entIdUrl)
+ {
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE);
+ ctx->drw.textR (&ctx->drw, idx, idy, entId);
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+
+ /* Image map output */
+ ismapRect(ismap,
+ entIdUrl,
+ idx, idy - ctx->drw.textHeight(&ctx->drw),
+ idx + idwidth, idy);
+ }
+ else
+ {
+ ctx->drw.textR(&ctx->drw, idx, idy, entId);
+ }
+
+ ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_SMALL);
+ }
+ }
+ }
+}
+
+/** Draw vertical lines stemming from entities.
+ * This function will draw a single segment of the vertical line that
+ * drops from an entity.
+ *
+ * \param m The \a Msc for which the lines are drawn
+ * \param ymin Top of the row.
+ * \param ymax Bottom of the row.
+ * \param dotted If #TRUE, produce a dotted line, otherwise solid.
+ * \param colourRefs Colour references for each entity.
+ */
+static void entityLines(Context *ctx,
+ Msc m,
+ const unsigned int ymin,
+ const unsigned int ymax,
+ Boolean dotted,
+ const ADrawColour *colourRefs)
+{
+ unsigned int t;
+
+ for (t = 0; t < MscGetNumEntities(m); t++)
+ {
+ unsigned int x = (ctx->opts.entitySpacing / 2) + (ctx->opts.entitySpacing * t);
+
+ ctx->drw.setPen(&ctx->drw, colourRefs[t]);
+
+ if(dotted)
+ {
+ ctx->drw.dottedLine(&ctx->drw, x, ymin, x, ymax);
+ }
+ else
+ {
+ ctx->drw.line(&ctx->drw, x, ymin, x, ymax);
+ }
+ }
+
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+
+}
+
+/** Draw an arrow pointing to the right.
+ * \param x The x co-ordinate for the end point for the arrow head.
+ * \param y The y co-ordinate for the end point for the arrow head.
+ * \param type The arc type, which controls the format of the arrow head.
+ */
+static void arrowR(Context *ctx,
+ unsigned int x,
+ unsigned int y,
+ MscArcType type)
+{
+ switch(type)
+ {
+ case MSC_ARC_SIGNAL: /* Unfilled half */
+ ctx->drw.line(&ctx->drw,
+ x, y,
+ x - ctx->opts.arrowWidth, y + ctx->opts.arrowHeight);
+ break;
+
+ case MSC_ARC_DOUBLE:
+ case MSC_ARC_METHOD: /* Filled */
+ case MSC_ARC_RETVAL: /* Filled, dotted arc (not rendered here) */
+ ctx->drw.filledTriangle(&ctx->drw,
+ x, y,
+ x - ctx->opts.arrowWidth, y + ctx->opts.arrowHeight,
+ x - ctx->opts.arrowWidth, y - ctx->opts.arrowHeight);
+ break;
+
+ case MSC_ARC_CALLBACK: /* Non-filled */
+ ctx->drw.line(&ctx->drw,
+ x, y,
+ x - ctx->opts.arrowWidth, y + ctx->opts.arrowHeight);
+ ctx->drw.line(&ctx->drw,
+ x - ctx->opts.arrowWidth, y - ctx->opts.arrowHeight,
+ x, y);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+
+/** Draw an arrow pointing to the left.
+ * \param x The x co-ordinate for the end point for the arrow head.
+ * \param y The y co-ordinate for the end point for the arrow head.
+ * \param type The arc type, which controls the format of the arrow head.
+ */
+static void arrowL(Context *ctx,
+ unsigned int x,
+ unsigned int y,
+ MscArcType type)
+{
+ switch(type)
+ {
+ case MSC_ARC_SIGNAL: /* Unfilled half */
+ ctx->drw.line(&ctx->drw,
+ x, y,
+ x + ctx->opts.arrowWidth, y + ctx->opts.arrowHeight);
+ break;
+
+ case MSC_ARC_DOUBLE:
+ case MSC_ARC_METHOD: /* Filled */
+ case MSC_ARC_RETVAL: /* Filled, dotted arc (not rendered here) */
+ ctx->drw.filledTriangle(&ctx->drw,
+ x, y,
+ x + ctx->opts.arrowWidth, y + ctx->opts.arrowHeight,
+ x + ctx->opts.arrowWidth, y - ctx->opts.arrowHeight);
+ break;
+
+ case MSC_ARC_CALLBACK: /* Non-filled */
+ ctx->drw.line(&ctx->drw,
+ x, y,
+ x + ctx->opts.arrowWidth, y + ctx->opts.arrowHeight);
+ ctx->drw.line(&ctx->drw,
+ x, y,
+ x + ctx->opts.arrowWidth, y - ctx->opts.arrowHeight);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+/** Draw vertical lines and boxes stemming from entities.
+ * \param ymin Top of the row.
+ * \param ymax Bottom of the row.
+ * \param boxStart Column in which the box starts.
+ * \param boxEnd Column in which the box ends.
+ * \param boxType The type of box to draw, MSC_ARC_BOX, MSC_ARC_RBOX etc.
+ * \param lineColour Colour of the lines to use for rendering the box.
+ * \param bgColour Background colour for rendering the box.
+ */
+static void arcBox(Context *ctx,
+ unsigned int ymin,
+ unsigned int ymax,
+ unsigned int boxStart,
+ unsigned int boxEnd,
+ MscArcType boxType,
+ const char *lineColour,
+ const char *bgColour)
+{
+ unsigned int t;
+
+ /* Ensure the start is less than or equal to the end */
+ if(boxStart > boxEnd)
+ {
+ t = boxEnd;
+ boxEnd = boxStart;
+ boxStart = t;
+ }
+
+ /* Now draw the box */
+ unsigned int x1 = (ctx->opts.entitySpacing * boxStart) + ctx->opts.boxSpacing;
+ unsigned int x2 = ctx->opts.entitySpacing * (boxEnd + 1) - ctx->opts.boxSpacing;
+ unsigned int ymid = (ymin + ymax) / 2;
+
+ /* Set colour for the background area */
+ if(bgColour != NULL)
+ {
+ ctx->drw.setPen(&ctx->drw, ADrawGetColour(bgColour));
+ }
+ else
+ {
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_WHITE);
+ }
+
+ /* Draw the background to overwrite the entity lines */
+ switch(boxType)
+ {
+ case MSC_ARC_BOX:
+ ctx->drw.filledRectangle(&ctx->drw, x1, ymin, x2, ymax);
+ break;
+
+ case MSC_ARC_RBOX:
+ ctx->drw.filledRectangle(&ctx->drw, x1 + ctx->opts.rboxArc, ymin, x2 - ctx->opts.rboxArc, ymax);
+ ctx->drw.filledRectangle(&ctx->drw, x1, ymin + ctx->opts.rboxArc, x2, ymax - ctx->opts.rboxArc);
+ ctx->drw.filledCircle(&ctx->drw, x1 + ctx->opts.rboxArc, ymin + ctx->opts.rboxArc, ctx->opts.rboxArc);
+ ctx->drw.filledCircle(&ctx->drw, x2 - ctx->opts.rboxArc, ymin + ctx->opts.rboxArc, ctx->opts.rboxArc);
+ ctx->drw.filledCircle(&ctx->drw, x1 + ctx->opts.rboxArc, ymax - ctx->opts.rboxArc, ctx->opts.rboxArc);
+ ctx->drw.filledCircle(&ctx->drw, x2 - ctx->opts.rboxArc, ymax - ctx->opts.rboxArc, ctx->opts.rboxArc);
+ break;
+
+ case MSC_ARC_NOTE:
+ ctx->drw.filledRectangle(&ctx->drw, x1, ymin, x2 - ctx->opts.noteCorner, ymax);
+ ctx->drw.filledRectangle(&ctx->drw, x1, ymin + ctx->opts.noteCorner, x2, ymax);
+ ctx->drw.filledTriangle(&ctx->drw, x2 - ctx->opts.noteCorner, ymin,
+ x2, ymin + ctx->opts.noteCorner,
+ x2 - ctx->opts.noteCorner, ymin + ctx->opts.noteCorner);
+ break;
+
+ case MSC_ARC_ABOX:
+ ctx->drw.filledRectangle(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, x2 - ctx->opts.aboxSlope, ymax);
+ ctx->drw.filledTriangle(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin,
+ x1 + ctx->opts.aboxSlope, ymax,
+ x1, ymid);
+ ctx->drw.filledTriangle(&ctx->drw, x2 - ctx->opts.aboxSlope, ymin,
+ x2 - ctx->opts.aboxSlope, ymax,
+ x2, ymid);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ /* Setup the colour for rendering the boxes */
+ if(lineColour)
+ {
+ ctx->drw.setPen(&ctx->drw, ADrawGetColour(lineColour));
+ }
+ else
+ {
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+ }
+
+ /* Draw the outline */
+ switch(boxType)
+ {
+ case MSC_ARC_BOX:
+ ctx->drw.line(&ctx->drw, x1, ymin, x2, ymin);
+ ctx->drw.line(&ctx->drw, x1, ymax, x2, ymax);
+ ctx->drw.line(&ctx->drw, x1, ymin, x1, ymax);
+ ctx->drw.line(&ctx->drw, x2, ymin, x2, ymax);
+ break;
+
+ case MSC_ARC_NOTE:
+ ctx->drw.line(&ctx->drw, x1, ymin, x2 - ctx->opts.noteCorner, ymin);
+ ctx->drw.line(&ctx->drw, x1, ymax, x2, ymax);
+ ctx->drw.line(&ctx->drw, x1, ymin, x1, ymax);
+ ctx->drw.line(&ctx->drw, x2, ymin + ctx->opts.noteCorner, x2, ymax);
+ ctx->drw.line(&ctx->drw, x2 - ctx->opts.noteCorner, ymin,
+ x2, ymin + ctx->opts.noteCorner);
+ ctx->drw.line(&ctx->drw, x2 - ctx->opts.noteCorner, ymin,
+ x2 - ctx->opts.noteCorner, ymin + ctx->opts.noteCorner);
+ ctx->drw.line(&ctx->drw, x2, ymin + ctx->opts.noteCorner,
+ x2 - ctx->opts.noteCorner, ymin + ctx->opts.noteCorner);
+ break;
+
+ case MSC_ARC_RBOX:
+ ctx->drw.line(&ctx->drw, x1 + ctx->opts.rboxArc, ymin, x2 - ctx->opts.rboxArc, ymin);
+ ctx->drw.line(&ctx->drw, x1 + ctx->opts.rboxArc, ymax, x2 - ctx->opts.rboxArc, ymax);
+ ctx->drw.line(&ctx->drw, x1, ymin + ctx->opts.rboxArc, x1, ymax - ctx->opts.rboxArc);
+ ctx->drw.line(&ctx->drw, x2, ymin + ctx->opts.rboxArc, x2, ymax - ctx->opts.rboxArc);
+
+ ctx->drw.arc(&ctx->drw, x1 + ctx->opts.rboxArc,
+ ymin + ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2,
+ 180, 270);
+ ctx->drw.arc(&ctx->drw, x2 - ctx->opts.rboxArc,
+ ymin + ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2,
+ 270, 0);
+ ctx->drw.arc(&ctx->drw, x2 - ctx->opts.rboxArc,
+ ymax - ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2,
+ 0, 90);
+ ctx->drw.arc(&ctx->drw, x1 + ctx->opts.rboxArc,
+ ymax - ctx->opts.rboxArc, ctx->opts.rboxArc * 2, ctx->opts.rboxArc * 2,
+ 90, 180);
+ break;
+
+ case MSC_ARC_ABOX:
+ ctx->drw.line(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, x2 - ctx->opts.aboxSlope, ymin);
+ ctx->drw.line(&ctx->drw, x1 + ctx->opts.aboxSlope, ymax, x2 - ctx->opts.aboxSlope, ymax);
+ ctx->drw.line(&ctx->drw, x1 + ctx->opts.aboxSlope, ymin, x1, ymid);
+ ctx->drw.line(&ctx->drw, x1, ymid, x1 + ctx->opts.aboxSlope, ymax);
+ ctx->drw.line(&ctx->drw, x2 - ctx->opts.aboxSlope, ymin, x2, ymid);
+ ctx->drw.line(&ctx->drw, x2, ymid, x2 - ctx->opts.aboxSlope, ymax);
+ break;
+
+ default:
+ assert(0);
+ }
+
+ /* Restore the pen colour if needed */
+ if(lineColour)
+ {
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+ }
+}
+
+
+/** Render text on an arc.
+ * Draw the text on some arc.
+ * \param m The Msc for which the text is being rendered.
+ * \param ismap If not \a NULL, write an ismap description here.
+ * \param outwidth Width of the output image.
+ * \param ymid Co-ordinate of the row on which the text should be aligned.
+ * \param startCol The column at which the arc being labelled starts.
+ * \param endCol The column at which the arc being labelled ends.
+ * \param arcLabelLineCount Count of lines of text in arcLabelLines.
+ * \param arcLabelLines Array of lines of text from 0 to arcLabelLineCount - 1.
+ * \param arcUrl The URL for rendering the label as a hyperlink. This
+ * maybe \a NULL if not required.
+ * \param arcId The text identifier for the arc.
+ * \param arcIdUrl The URL for rendering the test identifier as a hyperlink.
+ * This maybe \a NULL if not required.
+ * \param arcTextColour Colour for the arc text, or NULL to use default.
+ * \param arcTextColour Colour for the arc text backgroun, or NULL to use default.
+ * \param arcType The type of arc, used to control output semantics.
+ */
+static void arcText(Context *ctx,
+ Msc m,
+ FILE *ismap,
+ unsigned int outwidth,
+ unsigned int ymid,
+ int ygradient,
+ unsigned int startCol,
+ unsigned int endCol,
+ const unsigned int arcLabelLineCount,
+ char **arcLabelLines,
+ const char *arcUrl,
+ const char *arcId,
+ const char *arcIdUrl,
+ const char *arcTextColour,
+ const char *arcTextBgColour,
+ const MscArcType arcType)
+{
+ unsigned int l;
+ unsigned int y;
+
+ /* A single line of normal text is above the midline */
+ if(arcLabelLineCount == 1 && !isBoxArc(arcType) &&
+ arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER &&
+ arcType != MSC_ARC_SPACE)
+ {
+ y = ymid + (ygradient / 2) - ctx->drw.textHeight(&ctx->drw);
+ }
+ else /* Text is vertically centered on the midline */
+ {
+ int yoff = ygradient - (ctx->drw.textHeight(&ctx->drw) * arcLabelLineCount);
+ y = ymid + (yoff / 2);
+ }
+
+ for (l = 0; l < arcLabelLineCount; l++)
+ {
+ const char *lineLabel = arcLabelLines[l];
+ unsigned int width = ctx->drw.textWidth(&ctx->drw, lineLabel);
+ int x = ((startCol + endCol + 1) * ctx->opts.entitySpacing) / 2;
+
+ y += ctx->drw.textHeight(&ctx->drw);
+
+ if(startCol != endCol || isBoxArc(arcType))
+ {
+ /* Produce central aligned text */
+ x -= width / 2;
+ }
+ else if(startCol < (MscGetNumEntities(m) / 2))
+ {
+ /* Form text to the right */
+ x += ctx->opts.textHGapPre;
+ }
+ else
+ {
+ /* Form text to the left */
+ x -= width + ctx->opts.textHGapPost;
+ }
+
+ /* Clip against edges of image */
+ if(x + width > outwidth)
+ {
+ x = outwidth - width;
+ }
+
+ if(x < 0)
+ {
+ x = 0;
+ }
+
+ /* Check if a URL is associated */
+ if(arcUrl)
+ {
+ /* Default to blue */
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE);
+
+ /* Image map output */
+ ismapRect(ismap,
+ arcUrl,
+ x, y - ctx->drw.textHeight(&ctx->drw),
+ x + width, y);
+ }
+
+
+ /* Set to the explicit colours if directed */
+ if(arcTextColour != NULL)
+ {
+ ctx->drw.setPen(&ctx->drw, ADrawGetColour(arcTextColour));
+ }
+
+ if(arcTextBgColour != NULL)
+ {
+ ctx->drw.setBgPen(&ctx->drw, ADrawGetColour(arcTextBgColour));
+ }
+
+ /* Render text and restore pen */
+ ctx->drw.textR (&ctx->drw, x, y, lineLabel);
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+ ctx->drw.setBgPen(&ctx->drw, ADRAW_COL_WHITE);
+
+ /* Render the Id of the arc, if specified and for the first line*/
+ if(arcId && l == 0)
+ {
+ unsigned int idwidth;
+ int idx, idy;
+
+ idy = y - ctx->drw.textHeight(&ctx->drw);
+ idx = x + width;
+
+ ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_TINY);
+
+ idwidth = ctx->drw.textWidth(&ctx->drw, arcId);
+ idy += (ctx->drw.textHeight(&ctx->drw) + 1) / 2;
+
+ if(arcIdUrl)
+ {
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLUE);
+
+ /* Image map output */
+ ismapRect(ismap,
+ arcIdUrl,
+ idx, idy - ctx->drw.textHeight(&ctx->drw),
+ idx + idwidth, idy);
+ }
+
+ /* Render text and restore pen and font */
+ ctx->drw.textR (&ctx->drw, idx, idy, arcId);
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+ ctx->drw.setFontSize(&ctx->drw, ADRAW_FONT_SMALL);
+ }
+ }
+}
+
+
+/** Render the line and arrow head for some arc.
+ * This will draw the arc line and arrow head between two columns,
+ * noting that if the start and end column are the same, an arc is
+ * rendered.
+ * \param m The Msc for which the text is being rendered.
+ * \param ymin Top of row.
+ * \param ymax Bottom of row.
+ * \param ygradient The gradient of the arc which alters the y position a
+ * the ending column.
+ * \param startCol Starting column for the arc.
+ * \param endCol Column at which the arc terminates.
+ * \param hasArrows If true, draw arc arrows, otherwise omit them.
+ * \param hasBiArrows If true, has arrows in both directions.
+ * \param arcType The type of the arc, which dictates its rendered style.
+ */
+static void arcLine(Context *ctx,
+ Msc m,
+ unsigned int y,
+ unsigned int ygradient,
+ unsigned int startCol,
+ unsigned int endCol,
+ const char *arcLineCol,
+ Boolean hasArrows,
+ const int hasBiArrows,
+ const MscArcType arcType)
+{
+ const unsigned int sx = (startCol * ctx->opts.entitySpacing) +
+ (ctx->opts.entitySpacing / 2);
+ const unsigned int dx = (endCol * ctx->opts.entitySpacing) +
+ (ctx->opts.entitySpacing / 2);
+
+ /* Check if an explicit line colour is requested */
+ if(arcLineCol != NULL)
+ {
+ ctx->drw.setPen(&ctx->drw, ADrawGetColour(arcLineCol));
+ }
+
+ if(startCol != endCol)
+ {
+ /* Draw the line */
+ if(arcType == MSC_ARC_RETVAL)
+ {
+ ctx->drw.dottedLine(&ctx->drw, sx, y, dx, y + ygradient);
+ }
+ else if(arcType == MSC_ARC_DOUBLE)
+ {
+ ctx->drw.line(&ctx->drw, sx, y - 1, dx, y - 1 + ygradient);
+ ctx->drw.line(&ctx->drw, sx, y + 1, dx, y + 1 + ygradient);
+ }
+ else if(arcType == MSC_ARC_LOSS)
+ {
+ signed int span = dx - sx;
+ unsigned int mx = sx + (span / 4) * 3;
+
+ ctx->drw.line(&ctx->drw, sx, y, mx, y + ygradient);
+ hasArrows = 0;
+
+ ctx->drw.line(&ctx->drw, mx - 4, y + ygradient - 4, mx + 4, y + ygradient + 4);
+ ctx->drw.line(&ctx->drw, mx + 4, y + ygradient - 4, mx - 4, y + ygradient + 4);
+ }
+ else
+ {
+ ctx->drw.line(&ctx->drw, sx, y, dx, y + ygradient);
+ }
+
+ /* Now the arrow heads */
+ if(hasArrows)
+ {
+ if(startCol < endCol)
+ {
+ arrowR(ctx, dx, y + ygradient, arcType);
+ }
+ else
+ {
+ arrowL(ctx, dx, y + ygradient, arcType);
+ }
+
+ if(hasBiArrows)
+ {
+ if(startCol < endCol)
+ {
+ arrowL(ctx, sx, y + ygradient, arcType);
+ }
+ else
+ {
+ arrowR(ctx, sx, y + ygradient, arcType);
+ }
+ }
+ }
+ }
+ else if(startCol < (MscGetNumEntities(m) / 2))
+ {
+ /* Arc looping to the left */
+ if(arcType == MSC_ARC_RETVAL)
+ {
+ ctx->drw.dottedArc(&ctx->drw,
+ sx, y,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 90,
+ 270);
+ }
+ else if(arcType == MSC_ARC_DOUBLE)
+ {
+ ctx->drw.arc(&ctx->drw,
+ sx, y - 1,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 90,
+ 270);
+ ctx->drw.arc(&ctx->drw,
+ sx, y + 1,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 90,
+ 270);
+ }
+ else if(arcType == MSC_ARC_LOSS)
+ {
+ unsigned int px, py;
+
+ ctx->drw.arc(&ctx->drw,
+ sx, y - 1,
+ ctx->opts.entitySpacing - 8,
+ ctx->opts.loopArcHeight,
+ 180 - 45,
+ 270);
+
+ hasArrows = FALSE;
+
+ /* Get co-ordinates of the arc end-point */
+ ADrawComputeArcPoint(sx, y - 1, ctx->opts.entitySpacing - 8,
+ ctx->opts.loopArcHeight, 180 - 45,
+ &px, &py);
+
+ /* Draw a cross */
+ ctx->drw.line(&ctx->drw, px - 4, py - 4, px + 4, py + 4);
+ ctx->drw.line(&ctx->drw, px + 4, py - 4, px - 4, py + 4);
+ }
+ else
+ {
+ ctx->drw.arc(&ctx->drw,
+ sx, y,
+ ctx->opts.entitySpacing - 4,
+ ctx->opts.loopArcHeight,
+ 90,
+ 270);
+ }
+
+ if(hasArrows)
+ {
+ arrowR(ctx, dx, y + (ctx->opts.loopArcHeight / 2), arcType);
+ }
+ }
+ else
+ {
+ /* Arc looping to right */
+ if(arcType == MSC_ARC_RETVAL)
+ {
+ ctx->drw.dottedArc(&ctx->drw,
+ sx, y,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 270,
+ 90);
+ }
+ else if(arcType == MSC_ARC_DOUBLE)
+ {
+ ctx->drw.arc(&ctx->drw,
+ sx, y - 1,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 270,
+ 90);
+ ctx->drw.arc(&ctx->drw,
+ sx, y + 1,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 270,
+ 90);
+ }
+ else if(arcType == MSC_ARC_LOSS)
+ {
+ unsigned int px, py;
+
+ ctx->drw.arc(&ctx->drw,
+ sx, y - 1,
+ ctx->opts.entitySpacing - 8,
+ ctx->opts.loopArcHeight,
+ 270,
+ 45);
+
+ hasArrows = FALSE;
+
+ /* Get co-ordinates of the arc end-point */
+ ADrawComputeArcPoint(sx, y - 1, ctx->opts.entitySpacing - 8,
+ ctx->opts.loopArcHeight, 45,
+ &px, &py);
+
+ /* Draw a cross */
+ ctx->drw.line(&ctx->drw, px - 4, py - 4, px + 4, py + 4);
+ ctx->drw.line(&ctx->drw, px + 4, py - 4, px - 4, py + 4);
+ }
+ else
+ {
+ ctx->drw.arc(&ctx->drw,
+ sx, y,
+ ctx->opts.entitySpacing,
+ ctx->opts.loopArcHeight,
+ 270,
+ 90);
+ }
+
+ if(hasArrows)
+ {
+ arrowL(ctx, dx, y + (ctx->opts.loopArcHeight / 2), arcType);
+ }
+ }
+
+ /* Restore pen if needed */
+ if(arcLineCol != NULL)
+ {
+ ctx->drw.setPen(&ctx->drw, ADRAW_COL_BLACK);
+ }
+}
+
+
+
+/* Perform post-parsing validation of the MSC.
+ * This checks the passed MSC for various rules which can't easily be tested
+ * at parse time.
+ */
+static Boolean checkMsc(Msc m)
+{
+ /* Check all arc entites are known */
+ MscResetArcIterator(m);
+ do
+ {
+ const MscArcType arcType = MscGetCurrentArcType(m);
+
+ if (arcType != MSC_ARC_PARALLEL && arcType != MSC_ARC_DISCO &&
+ arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE)
+ {
+ const char *src = MscGetCurrentArcSource(m);
+ const char *dst = MscGetCurrentArcDest(m);
+ const int startCol = MscGetEntityIndex(m, src);
+ const int endCol = MscGetEntityIndex(m, dst);
+
+ /* Check the start column is valid */
+ if (startCol == -1)
+ {
+ fprintf(stderr, "Error detected at line %u: Unknown source entity '%s'.\n",
+ MscGetCurrentArcInputLine(m), src);
+ return FALSE;
+ }
+
+ if (endCol == -1 && !isBroadcastArc(dst))
+ {
+ fprintf(stderr, "Error detected at line %u: Unknown destination entity '%s'.\n",
+ MscGetCurrentArcInputLine(m), dst);
+ return FALSE;
+ }
+ }
+ }
+ while (MscNextArc(m));
+
+ return TRUE;
+}
+
+
+int mscgen_generate(const char *inputFile,
+ const char *outputFile,
+ mscgen_format_t format
+ )
+{
+ //printf("mscgen_generate(in=%s,out=%s,format=%d)\n",inputFile,outputFile,format);
+ ADrawOutputType outType;
+ ADrawColour *entColourRef = NULL;
+ const char *outImage = outputFile;
+ Msc m;
+ float f;
+ unsigned int w, h, row, col;
+ RowInfo *rowInfo = NULL;
+ Boolean addLines;
+ FILE *ismap = NULL;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ const char *nullFile = "nul";
+#else
+ const char *nullFile = "/dev/null";
+#endif
+ Context ctx;
+ ctx.opts = gDefaultOpts;
+
+ switch (format)
+ {
+ case mscgen_format_png:
+ outType = ADRAW_FMT_PNG;
+ break;
+ case mscgen_format_eps:
+ outType = ADRAW_FMT_EPS;
+ break;
+ case mscgen_format_svg:
+ outType = ADRAW_FMT_SVG;
+ break;
+ case mscgen_format_pngmap:
+ outType = ADRAW_FMT_PNG;
+ outImage = nullFile;
+ break;
+ case mscgen_format_svgmap:
+ outType = ADRAW_FMT_SVG;
+ outImage = nullFile;
+ break;
+ }
+ /* open file */
+ FILE *in = fopen(inputFile, "r");
+ if (!in)
+ {
+ fprintf(stderr, "Failed to open input file '%s'\n", inputFile);
+ return MSCGEN_FILE_ERROR;
+ }
+ /* parse file */
+ m = MscParse(in);
+ fclose(in);
+ if (!m || !checkMsc(m))
+ {
+ fprintf(stderr, "Input format error for '%s'\n", inputFile);
+ return MSCGEN_INPUT_FORMAT_ERROR;
+ }
+
+ /* Check if an ismap file should also be generated */
+ if (format==mscgen_format_pngmap || format==mscgen_format_svgmap)
+ {
+ ismap = fopen(outputFile, "w");
+ if (!ismap)
+ {
+ fprintf(stderr, "Failed to open output file '%s': %s\n", outputFile, strerror(errno));
+ MscFree(m);
+ return MSCGEN_FILE_ERROR;
+ }
+ }
+
+ /* Open the drawing context with dummy dimensions */
+ if (!ADrawOpen(10, 10, nullFile, "", outType, &ctx.drw))
+ {
+ if (ismap)
+ {
+ fclose(ismap);
+ }
+ MscFree(m);
+ fprintf(stderr, "Failed to open temporary drawing context\n");
+ return MSCGEN_OUTPUT_CONTEXT_ERROR;
+ }
+
+ /* Now compute ideal canvas size, which may use text metrics */
+ if (MscGetOptAsFloat(m, MSC_OPT_WIDTH, &f))
+ {
+ ctx.opts.idealCanvasWidth = (unsigned int)f;
+ }
+ else if (MscGetOptAsFloat(m, MSC_OPT_HSCALE, &f))
+ {
+ ctx.opts.idealCanvasWidth *= (unsigned int)f;
+ }
+
+ /* Set the arc gradient if needed */
+ if (MscGetOptAsFloat(m, MSC_OPT_ARCGRADIENT, &f))
+ {
+ ctx.opts.arcGradient = (int)f;
+ ctx.opts.arcSpacing += ctx.opts.arcGradient;
+ }
+
+ /* Check if word wrapping on arcs other than boxes should be used */
+ MscGetOptAsBoolean(m, MSC_OPT_WORDWRAPARCS, &ctx.opts.wordWrapArcLabels);
+
+ /* Work out the entitySpacing */
+ if (ctx.opts.idealCanvasWidth / MscGetNumEntities(m) > ctx.opts.entitySpacing)
+ {
+ ctx.opts.entitySpacing = ctx.opts.idealCanvasWidth / MscGetNumEntities(m);
+ }
+
+ /* Work out the entityHeadGap */
+ MscResetEntityIterator(m);
+ for (col = 0; col < MscGetNumEntities(m); col++)
+ {
+ unsigned int lines = countLines(MscGetCurrentEntAttrib(m, MSC_ATTR_LABEL));
+ unsigned int gap;
+
+ /* Get the required gap */
+ gap = lines * ctx.drw.textHeight(&ctx.drw);
+ if (gap > ctx.opts.entityHeadGap)
+ {
+ ctx.opts.entityHeadGap = gap;
+ }
+
+ MscNextEntity(m);
+ }
+
+ //printf("opts: idealCanvasWidth=%d entitySpacing=%d entityHeadGap=%d "
+ // "arcSpacing=%d arcGradient=%d boxSpacing=%d boxInternalBorder=%d "
+ // "rboxArc=%d noteCorner=%d aboxSlope=%d wordWrapArcLabels=%d arrowWidth=%d "
+ // "arrowHeight=%d loopArcHeight=%d textHGapPre=%d textHGapPost=%d\n",
+ // ctx.opts.idealCanvasWidth,ctx.opts.entitySpacing,ctx.opts.entityHeadGap,
+ // ctx.opts.arcSpacing,ctx.opts.arcGradient,ctx.opts.boxSpacing,ctx.opts.boxInternalBorder,
+ // ctx.opts.rboxArc,ctx.opts.noteCorner,ctx.opts.aboxSlope,ctx.opts.wordWrapArcLabels,ctx.opts.arrowWidth,
+ // ctx.opts.arrowHeight,ctx.opts.loopArcHeight,ctx.opts.textHGapPre,ctx.opts.textHGapPost);
+
+ /* Work out the width and height of the canvas */
+ rowInfo = computeCanvasSize(&ctx, m, &w , &h);
+
+ /* Close the temporary output file */
+ ctx.drw.close(&ctx.drw);
+
+ //printf("opening canvas %d x %d for %s type=%d\n",w,h,outImage,outType);
+
+ /* Open the output */
+ if (!ADrawOpen(w, h, outImage, "", outType, &ctx.drw))
+ {
+ free(rowInfo);
+ if (ismap)
+ {
+ fclose(ismap);
+ }
+ MscFree(m);
+ return MSCGEN_OUTPUT_CONTEXT_ERROR;
+ }
+
+ /* Allocate storage for entity heading colours */
+ entColourRef = malloc_s(MscGetNumEntities(m) * sizeof(ADrawColour));
+
+ /* Draw the entity headings */
+ MscResetEntityIterator(m);
+ for (col = 0; col < MscGetNumEntities(m); col++)
+ {
+ unsigned int x = (ctx.opts.entitySpacing / 2) + (ctx.opts.entitySpacing * col);
+ const char *line;
+
+ /* Titles */
+ entityText(&ctx, ismap,
+ x,
+ ctx.opts.entityHeadGap - (ctx.drw.textHeight(&ctx.drw) / 2),
+ MscGetCurrentEntAttrib(m, MSC_ATTR_LABEL),
+ MscGetCurrentEntAttrib(m, MSC_ATTR_URL),
+ MscGetCurrentEntAttrib(m, MSC_ATTR_ID),
+ MscGetCurrentEntAttrib(m, MSC_ATTR_IDURL),
+ MscGetCurrentEntAttrib(m, MSC_ATTR_TEXT_COLOUR),
+ MscGetCurrentEntAttrib(m, MSC_ATTR_TEXT_BGCOLOUR));
+
+ /* Get the colours */
+ line = MscGetCurrentEntAttrib(m, MSC_ATTR_LINE_COLOUR);
+ if (line != NULL)
+ {
+ entColourRef[col] = ADrawGetColour(line);
+ }
+ else
+ {
+ entColourRef[col] = ADRAW_COL_BLACK;
+ }
+
+ MscNextEntity(m);
+ }
+
+ /* Draw the arcs */
+ addLines = TRUE;
+ row = 0;
+
+ MscResetArcIterator(m);
+ do
+ {
+ const MscArcType arcType = MscGetCurrentArcType(m);
+ const char *arcUrl = MscGetCurrentArcAttrib(m, MSC_ATTR_URL);
+ const char *arcId = MscGetCurrentArcAttrib(m, MSC_ATTR_ID);
+ const char *arcIdUrl = MscGetCurrentArcAttrib(m, MSC_ATTR_IDURL);
+ const char *arcTextColour = MscGetCurrentArcAttrib(m, MSC_ATTR_TEXT_COLOUR);
+ const char *arcTextBgColour = MscGetCurrentArcAttrib(m, MSC_ATTR_TEXT_BGCOLOUR);
+ const char *arcLineColour = MscGetCurrentArcAttrib(m, MSC_ATTR_LINE_COLOUR);
+ const int arcGradient = isBoxArc(arcType) ? 0 : getArcGradient(&ctx, m, rowInfo, row);
+ const int arcHasArrows = MscGetCurrentArcAttrib(m, MSC_ATTR_NO_ARROWS) == NULL;
+ const int arcHasBiArrows = MscGetCurrentArcAttrib(m, MSC_ATTR_BI_ARROWS) != NULL;
+ char **arcLabelLines = NULL;
+ unsigned int arcLabelLineCount = 0;
+ int startCol = -1, endCol = -1;
+
+ if (arcType == MSC_ARC_PARALLEL)
+ {
+ addLines = FALSE;
+
+ /* Rewind the row */
+ assert(row > 0);
+ row--;
+ }
+ else
+ {
+ const unsigned int ymin = rowInfo[row].ymin;
+ const unsigned int ymid = rowInfo[row].arcliney;
+ const unsigned int ymax = rowInfo[row].ymax;
+
+#if 0
+ /* For debug, mark the row spacing */
+ ctx.drw.line(&ctx.drw, 0, ymin, 10, ymin);
+ ctx.drw.line(&ctx.drw, 0, ymid, 5, ymid);
+ ctx.drw.line(&ctx.drw, 0, ymax, 10, ymax);
+#endif
+ /* Get the entity indices */
+ if (arcType != MSC_ARC_DISCO && arcType != MSC_ARC_DIVIDER && arcType != MSC_ARC_SPACE)
+ {
+ startCol = MscGetEntityIndex(m, MscGetCurrentArcSource(m));
+ endCol = MscGetEntityIndex(m, MscGetCurrentArcDest(m));
+
+ /* Check that the start column is known and the end column is
+ * known, or that it's a broadcast arc
+ */
+ assert(startCol != -1);
+ assert(endCol != -1 || isBroadcastArc(MscGetCurrentArcDest(m)));
+
+ /* Check for entity colouring if not set explicity on the arc */
+ if (arcTextColour == NULL)
+ {
+ arcTextColour = MscGetEntAttrib(m, startCol, MSC_ATTR_ARC_TEXT_COLOUR);
+ }
+
+ if (arcTextBgColour == NULL)
+ {
+ arcTextBgColour = MscGetEntAttrib(m, startCol, MSC_ATTR_ARC_TEXT_BGCOLOUR);
+ }
+
+ if (arcLineColour == NULL)
+ {
+ arcLineColour = MscGetEntAttrib(m, startCol, MSC_ATTR_ARC_LINE_COLOUR);
+ }
+
+ }
+ else
+ {
+ /* Discontinuity or parallel arc spans whole chart */
+ startCol = 0;
+ endCol = MscGetNumEntities(m) - 1;
+ }
+
+ /* Work out how the label fits the gap between entities */
+ arcLabelLineCount = computeLabelLines(&ctx, m, arcType, &arcLabelLines,
+ MscGetCurrentArcAttrib(m, MSC_ATTR_LABEL),
+ startCol, endCol);
+
+ /* Check if this is a broadcast message */
+ if (isBroadcastArc(MscGetCurrentArcDest(m)))
+ {
+ unsigned int t;
+
+ /* Add in the entity lines */
+ if (addLines)
+ {
+ entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef);
+ }
+
+ /* Draw arcs to each entity */
+ for (t = 0; t < MscGetNumEntities(m); t++)
+ {
+ if ((signed)t != startCol)
+ {
+ arcLine(&ctx, m, ymid, arcGradient, startCol,
+ t, arcLineColour, arcHasArrows,
+ arcHasBiArrows, arcType);
+ }
+ }
+
+ /* Fix up the start/end columns to span chart */
+ startCol = 0;
+ endCol = MscGetNumEntities(m) - 1;
+ }
+ else
+ {
+ /* Check if it is a box, discontinuity arc etc... */
+ if (isBoxArc(arcType))
+ {
+ if (addLines)
+ {
+ entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef);
+ }
+ arcBox(&ctx, ymin, ymax, startCol, endCol, arcType, arcLineColour, arcTextBgColour);
+ }
+ else if (arcType == MSC_ARC_DISCO)
+ {
+ if (addLines)
+ {
+ entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, TRUE /* dotted */, entColourRef);
+ }
+ }
+ else if (arcType == MSC_ARC_DIVIDER || arcType == MSC_ARC_SPACE)
+ {
+ if (addLines)
+ {
+ entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef);
+ }
+
+ /* Dividers also have a horizontal line at the middle */
+ if (arcType == MSC_ARC_DIVIDER)
+ {
+ const unsigned int margin = ctx.opts.entitySpacing / 4;
+
+ if (arcLineColour != NULL)
+ {
+ ctx.drw.setPen(&ctx.drw, ADrawGetColour(arcLineColour));
+ }
+
+ /* Draw line through middle of text */
+ ctx.drw.dottedLine(&ctx.drw,
+ margin, ymid,
+ (MscGetNumEntities(m) * ctx.opts.entitySpacing) - margin, ymid);
+
+ if (arcLineColour != NULL)
+ {
+ ctx.drw.setPen(&ctx.drw, ADRAW_COL_BLACK);
+ }
+ }
+ }
+ else
+ {
+ if (addLines)
+ {
+ entityLines(&ctx, m, ymin, ymax + ctx.opts.arcSpacing, FALSE, entColourRef);
+ }
+ arcLine(&ctx, m, ymid, arcGradient, startCol, endCol, arcLineColour,
+ arcHasArrows, arcHasBiArrows, arcType);
+ }
+ }
+
+ /* All may have text */
+ if (arcLabelLineCount > 0)
+ {
+ arcText(&ctx, m, ismap, w, ymid, arcGradient,
+ startCol, endCol,
+ arcLabelLineCount, arcLabelLines,
+ arcUrl, arcId, arcIdUrl,
+ arcTextColour, arcTextBgColour, arcType);
+ }
+
+ freeLabelLines(arcLabelLineCount, arcLabelLines);
+
+ /* Advance the row */
+ row++;
+ addLines = TRUE;
+ }
+ } while (MscNextArc(m));
+
+ /* Skip arcs may require the entity lines to be extended */
+ entityLines(&ctx, m,
+ rowInfo[(MscGetNumArcs(m) - MscGetNumParallelArcs(m)) - 1].ymax,
+ h, FALSE, entColourRef);
+
+ if (ismap)
+ {
+ fclose(ismap);
+ }
+
+ free(entColourRef);
+ free(rowInfo);
+ MscFree(m);
+ /* Close the context */
+ ctx.drw.close(&ctx.drw);
+
+ return MSCGEN_OK;
+}
+
+
+const char *mscgen_error2str(int code)
+{
+ switch (code)
+ {
+ case MSCGEN_OK: return "OK";
+ case MSCGEN_FILE_ERROR: return "FILE ERROR";
+ case MSCGEN_INPUT_FORMAT_ERROR: return "INPUT FORMAT ERROR";
+ case MSCGEN_OUTPUT_CONTEXT_ERROR: return "OUTPUT CONTEXT ERROR";
+ default: return "UNKNOWN_ERROR";
+ }
+}
+
diff --git a/libmscgen/mscgen_api.h b/libmscgen/mscgen_api.h
new file mode 100644
index 0000000..43a1bf8
--- /dev/null
+++ b/libmscgen/mscgen_api.h
@@ -0,0 +1,41 @@
+#ifndef MSCGEN_API_H
+#define MSCGEN_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MSCGEN_OK ( 0)
+#define MSCGEN_FILE_ERROR (-1)
+#define MSCGEN_INPUT_FORMAT_ERROR (-2)
+#define MSCGEN_OUTPUT_CONTEXT_ERROR (-3)
+
+/** The supported image formats */
+typedef enum
+{
+ mscgen_format_png, /**< PNG bitmap image file */
+ mscgen_format_eps, /**< Encapsulated PostScript file */
+ mscgen_format_svg, /**< Scalable Vector Graphics file */
+ mscgen_format_pngmap, /**< Image map for a bitmap file */
+ mscgen_format_svgmap /**< Image map for a SVG file */
+} mscgen_format_t;
+
+/** generate an image file for a given .msc file.
+ * @param inputFile the name of the MSC file to process.
+ * @param outputFile the name of the image file to generate.
+ * @param format the format of the image file to generate.
+ * @return 0 on success, a non zero error code on failure.
+ */
+int mscgen_generate(const char *inputFile,
+ const char *outputFile,
+ mscgen_format_t format
+ );
+
+/** Translates the error code returned by mscgen_generate into a string */
+const char *mscgen_error2str(int code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MSCGEN_API_H
diff --git a/libmscgen/mscgen_bool.h b/libmscgen/mscgen_bool.h
new file mode 100644
index 0000000..e982d80
--- /dev/null
+++ b/libmscgen/mscgen_bool.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *
+ * $Id: bool.h 115 2010-08-19 09:58:45Z Michael.McTernan $
+ *
+ * Boolean type for msclib.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ ***************************************************************************/
+
+#ifndef MSCGEN_BOOL_H
+#define MSCGEN_BOOL_H
+
+typedef enum
+{
+ FALSE = 0,
+ TRUE
+}
+Boolean;
+
+
+#endif /* MSCGEN_BOOL_H */
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_config.h b/libmscgen/mscgen_config.h
new file mode 100644
index 0000000..194b965
--- /dev/null
+++ b/libmscgen/mscgen_config.h
@@ -0,0 +1,55 @@
+#ifndef MSCGEN_CONFIG_H
+#define MSCGEN_CONFIG_H
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define M_PI 3.14159265358979323846264338327950288
+#define strcasecmp _stricmp
+#define strdup _strdup
+#define fileno _fileno
+#define YY_NO_UNISTD_H 1
+#else
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+
+/* Name of package */
+#define PACKAGE "mscgen"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "Michael.McTernan.2001@cs.bris.ac.uk"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "mscgen"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "mscgen 0.20"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "mscgen"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.20"
+
+/* If set, remove PNG output support thereby removing libgd dependence. */
+//#define REMOVE_PNG_OUTPUT /**/
+
+/* Define to 1 if you have the ANSI C header files. */
+//#define STDC_HEADERS 1
+
+/* Use FreeType for rendering text in PNGs. */
+/* #undef USE_FREETYPE */
+
+/* Version number of package */
+#define VERSION "0.20"
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#define YYTEXT_POINTER 1
+#endif /* MSCGEN_CONFIG_H */
diff --git a/libmscgen/mscgen_gd_out.c b/libmscgen/mscgen_gd_out.c
new file mode 100644
index 0000000..263431e
--- /dev/null
+++ b/libmscgen/mscgen_gd_out.c
@@ -0,0 +1,606 @@
+/***************************************************************************
+ *
+ * $Id: gd_out.c 186 2011-03-01 21:18:19Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#include "mscgen_config.h"
+#ifndef REMOVE_PNG_OUTPUT
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include "gd.h"
+#ifndef USE_FREETYPE
+#include "gdfontt.h" /* Tiny font */
+#include "gdfonts.h" /* Small font */
+#endif
+#include "mscgen_adraw_int.h"
+#include "mscgen_safe.h"
+
+/***************************************************************************
+ * Manifest Constants
+ ***************************************************************************/
+
+#define MAX_COLOURS 128
+
+/***************************************************************************
+ * Local types
+ ***************************************************************************/
+
+typedef struct GdoContextTag
+{
+ gdImagePtr img;
+#ifdef USE_FREETYPE
+ double fontPoints;
+ const char *fontName;
+#else
+ gdFontPtr font;
+#endif
+
+ /** Array of colours and GD references. */
+ struct
+ {
+ int ref;
+ ADrawColour col;
+ }
+ colour[MAX_COLOURS];
+
+ /** Number of valid references in \a colourRef[]. */
+ int colourCount;
+
+ /** The current pen for GD. */
+ int pen;
+
+ /** Background colour for rendering text. */
+ int bgpen;
+
+ FILE *outFile;
+}
+GdoContext;
+
+/***************************************************************************
+ * Helper functions
+ ***************************************************************************/
+
+/** Swap a pair of values inplace.
+ */
+static void swap(unsigned int *a, unsigned int *b)
+{
+ unsigned int x;
+
+ x = *a;
+ *a = *b;
+ *b = x;
+}
+
+
+/** Get the context pointer from an ADraw structure.
+ */
+static GdoContext *getGdoCtx(struct ADrawTag *ctx)
+{
+ return (GdoContext *)ctx->internal;
+}
+
+
+/** Get the GD image pointer from an ADraw structure.
+ */
+static gdImagePtr getGdoImg(struct ADrawTag *ctx)
+{
+ return getGdoCtx(ctx)->img;
+}
+
+/** Get the current GD pen index from an ADraw structure.
+ */
+static int getGdoPen(struct ADrawTag *ctx)
+{
+ return getGdoCtx(ctx)->pen;
+}
+
+
+/** Given a colour value, convert to a gd colour reference.
+ * This searches the current pallette of colours for the passed colour and
+ * returns an existing reference if possible. Otherwise a new colour reference
+ * is allocated and returned.
+ */
+static int getColourRef(GdoContext *context, ADrawColour col)
+{
+ int t;
+
+ /* Check if the colour is already allocated */
+ for(t = 0; t < context->colourCount; t++)
+ {
+ if(context->colour[t].col == col)
+ {
+ return context->colour[t].ref;
+ }
+ }
+
+ /* Allocate a new colour if there is space */
+ if(t < MAX_COLOURS)
+ {
+ /* Store the colour and allocate a reference */
+ context->colour[t].col = col;
+ context->colour[t].ref = gdImageColorAllocate(context->img,
+ (col & 0xff0000) >> 16,
+ (col & 0x00ff00) >> 8,
+ (col & 0x0000ff) >> 0);
+ context->colourCount++;
+
+ /* Return the new colour reference */
+ return context->colour[t].ref;
+ }
+ else
+ {
+ /* Cannot allocate more colours, so return black by default */
+ return getColourRef(context, ADRAW_COL_BLACK);
+ }
+}
+
+
+/** Set the dashed style.
+ */
+static void setStyle(struct ADrawTag *ctx)
+{
+ GdoContext *context = getGdoCtx(ctx);
+ int style[4];
+
+ /* Create dash pattern */
+ style[0] = style[1] = context->pen;
+ style[2] = style[3] = getColourRef(context, ADRAW_COL_WHITE);
+
+ gdImageSetStyle(context->img, style, 4);
+}
+
+/***************************************************************************
+ * API Functions
+ ***************************************************************************/
+
+unsigned int gdoTextWidth(struct ADrawTag *ctx,
+ const char *string)
+{
+#ifndef USE_FREETYPE
+ const unsigned int l = strlen(string);
+
+ /* Remove 1 pixel since there is usually an uneven gap at
+ * the right of the last character for the fixed width
+ * font.
+ */
+ return l == 0 ? 0 : (getGdoCtx(ctx)->font->w * l) - 1;
+#else
+ GdoContext *context = getGdoCtx(ctx);
+ int rect[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ const char *r;
+
+ r = gdImageStringFT(NULL,
+ rect,
+ context->pen,
+ (char *)context->fontName,
+ context->fontPoints,
+ 0,
+ 0, 0,
+ (char *)string);
+ if(r)
+ {
+ fprintf(stderr, "Error: gdoTextWidth: %s (GDFONTPATH=%s)\n", r, mscgen_getenv_s("GDFONTPATH"));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Remove 1 pixel since there is usually an uneven gap at
+ * the right of the last character for the fixed width
+ * font.
+ */
+ return rect[2] - 1;
+#endif
+}
+
+
+int gdoTextHeight(struct ADrawTag *ctx)
+{
+#ifndef USE_FREETYPE
+ return getGdoCtx(ctx)->font->h;
+#else
+ GdoContext *context = getGdoCtx(ctx);
+ int rect[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ const char *r;
+
+ r = gdImageStringFT(NULL,
+ rect,
+ context->pen,
+ (char *)context->fontName,
+ context->fontPoints,
+ 0,
+ 0, 0,
+ "gHELLOWt");
+ if(r)
+ {
+ fprintf(stderr, "Error: gdoTextHeight: %s (GDFONTPATH=%s)\n", r, mscgen_getenv_s("GDFONTPATH"));
+ exit(EXIT_FAILURE);
+ }
+
+ return (-rect[5]) + 1;
+#endif
+}
+
+
+void gdoLine(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ /* Range check since gdImageLine() takes signed values */
+ if(x1 <= INT_MAX && y1 <= INT_MAX && x2 <= INT_MAX && y2 <= INT_MAX)
+ {
+ /* Anti-aliasing fails if drawing 'backwards' for some octants */
+ if(x1 > x2 && abs((int)x1 - (int)x2) > abs((int)y1 - (int)y2))
+ {
+ swap(&x1, &x2);
+ swap(&y1, &y2);
+ }
+
+ gdImageSetAntiAliased(getGdoImg(ctx), getGdoPen(ctx));
+ gdImageLine(getGdoImg(ctx),
+ x1, y1, x2, y2, gdAntiAliased);
+ }
+}
+
+
+void gdoDottedLine(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ setStyle(ctx);
+
+ /* Range check since gdImageLine() takes signed values */
+ if(x1 <= INT_MAX && y1 <= INT_MAX && x2 <= INT_MAX && y2 <= INT_MAX)
+ {
+ gdImageLine(getGdoImg(ctx), x1, y1, x2, y2, gdStyled);
+ }
+}
+
+
+void gdoTextR(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ GdoContext *context = getGdoCtx(ctx);
+#ifdef USE_FREETYPE
+ int rect[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ const char *r;
+#endif
+ int textWidth;
+
+ textWidth = gdoTextWidth(ctx, string);
+
+ /* Range check since gdImageFilledRectangle() takes signed values */
+ if(x + textWidth <= INT_MAX && y <= INT_MAX)
+ {
+ gdImageFilledRectangle(getGdoImg(ctx),
+ x,
+ y - (gdoTextHeight(ctx) - 2),
+ x + textWidth,
+ y - 2,
+ context->bgpen);
+
+#ifdef USE_FREETYPE
+ r = gdImageStringFT(getGdoImg(ctx),
+ rect,
+ context->pen,
+ (char *)context->fontName,
+ context->fontPoints,
+ 0,
+ x, y - 2,
+ (char *)string);
+
+ if(r)
+ {
+ fprintf(stderr, "Error: gdoTextR: %s (GDFONTPATH=%s)\n", r, mscgen_getenv_s("GDFONTPATH"));
+ exit(EXIT_FAILURE);
+ }
+#else
+ gdImageString(getGdoImg(ctx),
+ getGdoCtx(ctx)->font,
+ x,
+ y - gdoTextHeight(ctx),
+ (unsigned char *)string,
+ getGdoPen(ctx));
+#endif
+ }
+
+}
+
+
+void gdoTextL(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ x -= gdoTextWidth(ctx, string);
+
+ /* Range check since gdImageFilledRectangle() takes signed values */
+ if(x <= INT_MAX && y <= INT_MAX)
+ {
+ gdoTextR(ctx, x, y, string);
+ }
+}
+
+void gdoTextC(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ gdoTextR(ctx, x - (gdoTextWidth(ctx, string) / 2), y, string);
+}
+
+void gdoFilledRectangle(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ gdPoint p[4];
+
+ /* Range check since gdPoint contains signed values */
+ if(x1 <= INT_MAX && y1 <= INT_MAX && x2 <= INT_MAX && y2 <= INT_MAX)
+ {
+ p[0].x = x1; p[0].y = y1;
+ p[1].x = x2; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x1; p[3].y = y2;
+
+
+ gdImageFilledPolygon(getGdoImg(ctx), p, 4, getGdoPen(ctx));
+ }
+}
+
+void gdoFilledTriangle(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2,
+ unsigned int x3,
+ unsigned int y3)
+{
+ gdPoint p[3];
+
+ /* Range check since gdPoint contains signed values */
+ if(x1 <= INT_MAX && y1 <= INT_MAX &&
+ x2 <= INT_MAX && y2 <= INT_MAX &&
+ x3 <= INT_MAX && y3 <= INT_MAX)
+ {
+ p[0].x = x1; p[0].y = y1;
+ p[1].x = x2; p[1].y = y2;
+ p[2].x = x3; p[2].y = y3;
+
+ gdImageSetAntiAliased(getGdoImg(ctx), getGdoPen(ctx));
+ gdImageFilledPolygon(getGdoImg(ctx), p, 3, gdAntiAliased);
+ }
+}
+
+
+void gdoFilledCircle(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ unsigned int r)
+{
+ gdImageSetAntiAliased(getGdoImg(ctx), getGdoPen(ctx));
+ gdImageFilledEllipse(getGdoImg(ctx), x, y, r * 2, r * 2, gdAntiAliased);
+}
+
+
+void gdoArc(struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e)
+{
+
+ /* Range check since gdImageArc takes signed values */
+ if(cx <= INT_MAX && cy <= INT_MAX)
+ {
+ gdImageArc(getGdoImg(ctx), cx, cy, w, h, s, e, getGdoPen(ctx));
+ }
+}
+
+
+void gdoDottedArc(struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e)
+{
+ /* Range check since gdImageArc takes signed values */
+ if(cx <= INT_MAX && cy <= INT_MAX)
+ {
+ setStyle(ctx);
+ gdImageArc(getGdoImg(ctx), cx, cy, w, h, s, e, gdStyled);
+ }
+}
+
+
+void gdoSetPen(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ GdoContext *context = getGdoCtx(ctx);;
+
+ context->pen = getColourRef(context, col);
+}
+
+
+void gdoSetBgPen(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ GdoContext *context = getGdoCtx(ctx);;
+
+ context->bgpen = getColourRef(context, col);
+}
+
+
+void gdoSetFontSize(struct ADrawTag *ctx,
+ ADrawFontSize size)
+{
+ switch(size)
+ {
+#ifdef USE_FREETYPE
+ case ADRAW_FONT_TINY:
+ getGdoCtx(ctx)->fontPoints = 9.0;
+ break;
+
+ case ADRAW_FONT_SMALL:
+ getGdoCtx(ctx)->fontPoints = 11.0;
+ break;
+#else
+ case ADRAW_FONT_TINY:
+ getGdoCtx(ctx)->font = gdFontGetTiny();
+ break;
+
+ case ADRAW_FONT_SMALL:
+ getGdoCtx(ctx)->font = gdFontGetSmall();
+ break;
+#endif
+ default:
+ assert(0);
+ }
+}
+
+
+Boolean gdoClose(struct ADrawTag *ctx)
+{
+ GdoContext *context = getGdoCtx(ctx);
+
+ /* Output the image to the disk file in PNG format. */
+ gdImagePng(getGdoImg(ctx), context->outFile);
+ if(context->outFile != stdout)
+ {
+ fclose(context->outFile);
+ }
+
+ /* Destroy the image in memory */
+ gdImageDestroy(context->img);
+
+ /* Free and destroy context */
+ free(context);
+ ctx->internal = NULL;
+
+ return TRUE;
+}
+
+
+
+Boolean GdoInit(unsigned int w,
+ unsigned int h,
+ const char *file,
+ const char *fontName UNUSED,
+ struct ADrawTag *outContext)
+{
+ GdoContext *context;
+
+ /* Range check the size */
+ if(w > INT_MAX || h > INT_MAX)
+ {
+ fprintf(stderr, "Warning: The output image size larger than can be supported for png; output\n"
+ " will be clipped.\n");
+ }
+
+ /* Clip image size to limits */
+ if(w > INT_MAX) w = INT_MAX;
+ if(h > INT_MAX) h = INT_MAX;
+
+ /* Create context */
+ context = outContext->internal = zalloc_s(sizeof(GdoContext));
+ if(context == NULL)
+ {
+ return FALSE;
+ }
+
+ /* Open the output file */
+ if(strcmp(file, "-") == 0)
+ {
+ context->outFile = stdout;
+ }
+ else
+ {
+ context->outFile = fopen(file, "wb");
+ if(!context->outFile)
+ {
+ fprintf(stderr, "GdoInit: Failed to open output file '%s': %s\n", file, strerror(errno));
+ return FALSE;
+ }
+ }
+
+#ifdef USE_FREETYPE
+ /* Request that we use font config strings and store font name */
+ gdFTUseFontConfig(1);
+ context->fontName = fontName;
+
+ assert(fontName != NULL);
+#endif
+
+ /* Allocate the image */
+ context->img = gdImageCreateTrueColor(w, h);
+
+ /* Allocate first colour and clear background */
+ gdImageFilledRectangle(context->img,
+ 0, 0,
+ w, h,
+ getColourRef(context, ADRAW_COL_WHITE));
+
+ /* Set pen colour to black and background to white */
+ context->pen = getColourRef(context, ADRAW_COL_BLACK);
+ context->bgpen = getColourRef(context, ADRAW_COL_WHITE);
+
+ /* Get the default font size */
+ gdoSetFontSize(outContext, ADRAW_FONT_SMALL);
+
+ /* Now fill in the function pointers */
+ outContext->line = gdoLine;
+ outContext->dottedLine = gdoDottedLine;
+ outContext->textL = gdoTextL;
+ outContext->textC = gdoTextC;
+ outContext->textR = gdoTextR;
+ outContext->textWidth = gdoTextWidth;
+ outContext->textHeight = gdoTextHeight;
+ outContext->filledRectangle = gdoFilledRectangle;
+ outContext->filledTriangle = gdoFilledTriangle;
+ outContext->filledCircle = gdoFilledCircle;
+ outContext->arc = gdoArc;
+ outContext->dottedArc = gdoDottedArc;
+ outContext->setPen = gdoSetPen;
+ outContext->setBgPen = gdoSetBgPen;
+ outContext->setFontSize = gdoSetFontSize;
+ outContext->close = gdoClose;
+
+ return TRUE;
+}
+
+#endif /* REMOVE_PNG_OUTPUT */
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_language.h b/libmscgen/mscgen_language.h
new file mode 100644
index 0000000..4f401a6
--- /dev/null
+++ b/libmscgen/mscgen_language.h
@@ -0,0 +1,186 @@
+
+/* A Bison parser, made by GNU Bison 2.4.1. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ TOK_STRING = 258,
+ TOK_QSTRING = 259,
+ TOK_EQUAL = 260,
+ TOK_COMMA = 261,
+ TOK_SEMICOLON = 262,
+ TOK_OCBRACKET = 263,
+ TOK_CCBRACKET = 264,
+ TOK_OSBRACKET = 265,
+ TOK_CSBRACKET = 266,
+ TOK_MSC = 267,
+ TOK_ATTR_LABEL = 268,
+ TOK_ATTR_URL = 269,
+ TOK_ATTR_ID = 270,
+ TOK_ATTR_IDURL = 271,
+ TOK_ATTR_LINE_COLOUR = 272,
+ TOK_ATTR_TEXT_COLOUR = 273,
+ TOK_ATTR_TEXT_BGCOLOUR = 274,
+ TOK_ATTR_ARC_LINE_COLOUR = 275,
+ TOK_ATTR_ARC_TEXT_COLOUR = 276,
+ TOK_ATTR_ARC_TEXT_BGCOLOUR = 277,
+ TOK_REL_LOSS_TO = 278,
+ TOK_REL_LOSS_FROM = 279,
+ TOK_REL_SIG_BI = 280,
+ TOK_REL_SIG_TO = 281,
+ TOK_REL_SIG_FROM = 282,
+ TOK_REL_METHOD_BI = 283,
+ TOK_REL_METHOD_TO = 284,
+ TOK_REL_METHOD_FROM = 285,
+ TOK_REL_RETVAL_BI = 286,
+ TOK_REL_RETVAL_TO = 287,
+ TOK_REL_RETVAL_FROM = 288,
+ TOK_REL_DOUBLE_BI = 289,
+ TOK_REL_DOUBLE_TO = 290,
+ TOK_REL_DOUBLE_FROM = 291,
+ TOK_REL_CALLBACK_BI = 292,
+ TOK_REL_CALLBACK_TO = 293,
+ TOK_REL_CALLBACK_FROM = 294,
+ TOK_REL_BOX = 295,
+ TOK_REL_ABOX = 296,
+ TOK_REL_RBOX = 297,
+ TOK_REL_NOTE = 298,
+ TOK_SPECIAL_ARC = 299,
+ TOK_OPT_HSCALE = 300,
+ TOK_OPT_WIDTH = 301,
+ TOK_OPT_ARCGRADIENT = 302,
+ TOK_OPT_WORDWRAPARCS = 303,
+ TOK_ASTERISK = 304,
+ TOK_UNKNOWN = 305,
+ TOK_REL_SIG = 306,
+ TOK_REL_METHOD = 307,
+ TOK_REL_RETVAL = 308,
+ TOK_REL_DOUBLE = 309,
+ TOK_ATTR_ARC_SKIP = 310
+ };
+#endif
+/* Tokens. */
+#define TOK_STRING 258
+#define TOK_QSTRING 259
+#define TOK_EQUAL 260
+#define TOK_COMMA 261
+#define TOK_SEMICOLON 262
+#define TOK_OCBRACKET 263
+#define TOK_CCBRACKET 264
+#define TOK_OSBRACKET 265
+#define TOK_CSBRACKET 266
+#define TOK_MSC 267
+#define TOK_ATTR_LABEL 268
+#define TOK_ATTR_URL 269
+#define TOK_ATTR_ID 270
+#define TOK_ATTR_IDURL 271
+#define TOK_ATTR_LINE_COLOUR 272
+#define TOK_ATTR_TEXT_COLOUR 273
+#define TOK_ATTR_TEXT_BGCOLOUR 274
+#define TOK_ATTR_ARC_LINE_COLOUR 275
+#define TOK_ATTR_ARC_TEXT_COLOUR 276
+#define TOK_ATTR_ARC_TEXT_BGCOLOUR 277
+#define TOK_REL_LOSS_TO 278
+#define TOK_REL_LOSS_FROM 279
+#define TOK_REL_SIG_BI 280
+#define TOK_REL_SIG_TO 281
+#define TOK_REL_SIG_FROM 282
+#define TOK_REL_METHOD_BI 283
+#define TOK_REL_METHOD_TO 284
+#define TOK_REL_METHOD_FROM 285
+#define TOK_REL_RETVAL_BI 286
+#define TOK_REL_RETVAL_TO 287
+#define TOK_REL_RETVAL_FROM 288
+#define TOK_REL_DOUBLE_BI 289
+#define TOK_REL_DOUBLE_TO 290
+#define TOK_REL_DOUBLE_FROM 291
+#define TOK_REL_CALLBACK_BI 292
+#define TOK_REL_CALLBACK_TO 293
+#define TOK_REL_CALLBACK_FROM 294
+#define TOK_REL_BOX 295
+#define TOK_REL_ABOX 296
+#define TOK_REL_RBOX 297
+#define TOK_REL_NOTE 298
+#define TOK_SPECIAL_ARC 299
+#define TOK_OPT_HSCALE 300
+#define TOK_OPT_WIDTH 301
+#define TOK_OPT_ARCGRADIENT 302
+#define TOK_OPT_WORDWRAPARCS 303
+#define TOK_ASTERISK 304
+#define TOK_UNKNOWN 305
+#define TOK_REL_SIG 306
+#define TOK_REL_METHOD 307
+#define TOK_REL_RETVAL 308
+#define TOK_REL_DOUBLE 309
+#define TOK_ATTR_ARC_SKIP 310
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+
+/* Line 1676 of yacc.c */
+#line 248 "language.y"
+
+ char *string;
+ Msc msc;
+ MscOpt opt;
+ MscOptType optType;
+ MscArc arc;
+ MscArcList arclist;
+ MscArcType arctype;
+ MscEntity entity;
+ MscEntityList entitylist;
+ MscAttrib attrib;
+ MscAttribType attribType;
+
+
+
+/* Line 1676 of yacc.c */
+#line 178 "language.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+
diff --git a/libmscgen/mscgen_language.y b/libmscgen/mscgen_language.y
new file mode 100644
index 0000000..0c0ab50
--- /dev/null
+++ b/libmscgen/mscgen_language.y
@@ -0,0 +1,430 @@
+%{
+/***************************************************************************
+ *
+ * $Id: language.y 175 2011-02-06 21:07:43Z Michael.McTernan $
+ *
+ * Grammar and parser for the mscgen language.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This file is part of msclib.
+ *
+ * Msc is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * Msclib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Foobar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mscgen_lexer.h"
+#include "mscgen_safe.h"
+#include "mscgen_msc.h"
+
+/* Lexer prototypes to prevent compiler warnings */
+int yylex(void);
+int yylex_destroy(void);
+
+/* Use verbose error reporting such that the expected token names are dumped */
+#define YYERROR_VERBOSE
+
+/* Name of parameter that is passed to yyparse() */
+#define YYPARSE_PARAM yyparse_result
+
+#define YYMALLOC malloc_s
+
+/* yyerror
+ * Error handling function. The TOK_XXX names are substituted for more
+ * understandable values that make more sense to the user.
+ */
+void yyerror(void *unused, const char *str)
+{
+ static const char *tokNames[] = { "TOK_OCBRACKET", "TOK_CCBRACKET",
+ "TOK_OSBRACKET", "TOK_CSBRACKET",
+ "TOK_REL_DOUBLE_TO", "TOK_REL_DOUBLE_FROM",
+ "TOK_REL_SIG_TO", "TOK_REL_SIG_FROM",
+ "TOK_REL_METHOD_TO", "TOK_REL_METHOD_FROM",
+ "TOK_REL_RETVAL_TO", "TOK_REL_RETVAL_FROM",
+ "TOK_REL_CALLBACK_TO", "TOK_REL_CALLBACK_FROM",
+ "TOK_REL_SIG", "TOK_REL_METHOD",
+ "TOK_REL_RETVAL", "TOK_REL_DOUBLE",
+ "TOK_EQUAL", "TOK_COMMA",
+ "TOK_SEMICOLON", "TOK_MSC",
+ "TOK_ATTR_LABEL", "TOK_ATTR_URL",
+ "TOK_ATTR_IDURL", "TOK_ATTR_ID",
+ "TOK_ATTR_LINE_COLOUR", "TOK_ATTR_TEXT_COLOUR",
+ "TOK_SPECIAL_ARC", "TOK_UNKNOWN",
+ "TOK_STRING", "TOK_QSTRING",
+ "TOK_OPT_HSCALE", "TOK_ASTERISK",
+ "TOK_OPT_WIDTH", "TOK_ARC_BOX",
+ "TOK_ARC_ABOX", "TOK_ARC_RBOX",
+ "TOK_ATTR_TEXT_BGCOLOUR", "TOK_ATTR_ARC_TEXT_BGCOLOUR",
+ "TOK_REL_LOSS_TO", "TOK_REL_LOSS_FROM",
+ "TOK_OPT_ARCGRADIENT", "TOK_ATTR_ARC_SKIP",
+ "TOK_OPT_WORDWRAPARCS", "TOK_REL_NOTE" };
+
+ static const char *tokRepl[] = { "'{'", "'}'",
+ "'['", "']'",
+ "':>'", "'<:'",
+ "'->'", "'<-'",
+ "'=>'", "'<='",
+ "'>>'", "'<<'",
+ "'=>>'", "'<<='",
+ "'--'", "'=='",
+ "'..'", "'::'",
+ "'='", "','",
+ "';'", "'msc'",
+ "'label'", "'url'",
+ "'idurl'", "'id'",
+ "'linecolour'", "'textcolour'",
+ "'...', '---'", "characters",
+ "'string'", "'quoted string'",
+ "'hscale'", "'*'",
+ "'width'", "'box'",
+ "'abox'", "'rbox'",
+ "'textbgcolour'", "'arctextbgcolor'",
+ "'-x'", "'x-'",
+ "'arcgradient'", "'arcskip'",
+ "'wordwraparcs'", "'note'" };
+
+ static const int tokArrayLen = sizeof(tokNames) / sizeof(char *);
+
+ char *s, *line;
+ int t;
+
+ /* Print standard message part */
+ fprintf(stderr, "Error detected at line %lu: ", lex_getlinenum());
+
+ /* Search for TOK */
+ s = (char *)strstr(str, "TOK_");
+ while(s != NULL)
+ {
+ int found = 0;
+
+ /* Print out message until start of the token is found */
+ while(str < s)
+ {
+ fprintf(stderr, "%c", *str);
+ str++;
+ }
+
+ /* Look for the token name */
+ for(t = 0; t < tokArrayLen && !found; t++)
+ {
+ if(strncmp(tokNames[t], str, strlen(tokNames[t])) == 0)
+ {
+ /* Dump the replacement string */
+ fprintf(stderr, "%s", tokRepl[t]);
+
+ /* Skip the token name */
+ str += strlen(tokNames[t]);
+
+ /* Exit the loop */
+ found = 1;
+ }
+ }
+
+ /* Check if a replacement was found */
+ if(!found)
+ {
+ /* Dump the next char and skip it so that TOK doesn't match again */
+ fprintf(stderr, "%c", *str);
+ str++;
+ }
+
+ s = (char *)strstr(str, "TOK_");
+ }
+
+ fprintf(stderr, "%s.\n", str);
+
+ line = lex_getline();
+ if(line != NULL)
+ {
+ fprintf(stderr, "> %s\n", line);
+
+ /* If the input line contains a 'lost arc', print a helpful note since
+ * without whitespace, this can confuse the lexer.
+ */
+ if(strstr(line, "x-") != NULL)
+ {
+ fprintf(stderr, "\nNote: This input line contains 'x-' which has special meaning as a \n"
+ " 'lost message' arc, but may not have been recognised as such if it\n"
+ " is preceded by other letters or numbers. Please use double-quoted\n"
+ " strings for tokens before 'x-', or insert a preceding whitespace if\n"
+ " this is what you intend.\n");
+ }
+ }
+ else
+ {
+ fprintf(stderr, ".\n");
+ }
+}
+
+int yywrap()
+{
+ return 1;
+}
+
+
+char *removeEscapes(char *in)
+{
+ const uint16_t l = strlen(in);
+ char *r = (char *)malloc_s(l + 1);
+ uint16_t t, u;
+
+ for(t = u = 0; t < l; t++)
+ {
+ r[u] = in[t];
+ if(in[t] != '\\' || in[t + 1] != '\"')
+ {
+ u++;
+ }
+ }
+
+ r[u] = '\0';
+
+ free(in);
+
+ return r;
+}
+
+extern FILE *yyin;
+extern int yyparse (void *YYPARSE_PARAM);
+
+
+Msc MscParse(FILE *in)
+{
+ Msc m;
+
+ yyin = in;
+
+ /* Parse, and check that no errors are found */
+ if(yyparse((void *)&m) != 0)
+ {
+ m = NULL;
+ }
+
+ lex_destroy();
+ yylex_destroy();
+
+ return m;
+}
+
+
+%}
+
+%parse-param {void *YYPARSE_PARAM}
+
+%token TOK_STRING TOK_QSTRING TOK_EQUAL TOK_COMMA TOK_SEMICOLON TOK_OCBRACKET TOK_CCBRACKET
+ TOK_OSBRACKET TOK_CSBRACKET TOK_MSC
+ TOK_ATTR_LABEL TOK_ATTR_URL TOK_ATTR_ID TOK_ATTR_IDURL
+ TOK_ATTR_LINE_COLOUR TOK_ATTR_TEXT_COLOUR TOK_ATTR_TEXT_BGCOLOUR
+ TOK_ATTR_ARC_LINE_COLOUR TOK_ATTR_ARC_TEXT_COLOUR TOK_ATTR_ARC_TEXT_BGCOLOUR
+ TOK_REL_LOSS_TO TOK_REL_LOSS_FROM
+ TOK_REL_SIG_BI TOK_REL_SIG_TO TOK_REL_SIG_FROM
+ TOK_REL_METHOD_BI TOK_REL_METHOD_TO TOK_REL_METHOD_FROM
+ TOK_REL_RETVAL_BI TOK_REL_RETVAL_TO TOK_REL_RETVAL_FROM
+ TOK_REL_DOUBLE_BI TOK_REL_DOUBLE_TO TOK_REL_DOUBLE_FROM
+ TOK_REL_CALLBACK_BI TOK_REL_CALLBACK_TO TOK_REL_CALLBACK_FROM
+ TOK_REL_BOX TOK_REL_ABOX
+ TOK_REL_RBOX TOK_REL_NOTE
+ TOK_SPECIAL_ARC TOK_OPT_HSCALE
+ TOK_OPT_WIDTH TOK_OPT_ARCGRADIENT
+ TOK_OPT_WORDWRAPARCS
+ TOK_ASTERISK TOK_UNKNOWN
+ TOK_REL_SIG TOK_REL_METHOD TOK_REL_RETVAL TOK_REL_DOUBLE
+ TOK_ATTR_ARC_SKIP
+
+%union
+{
+ char *string;
+ Msc msc;
+ MscOpt opt;
+ MscOptType optType;
+ MscArc arc;
+ MscArcList arclist;
+ MscArcType arctype;
+ MscEntity entity;
+ MscEntityList entitylist;
+ MscAttrib attrib;
+ MscAttribType attribType;
+};
+
+%type <msc> msc
+%type <opt> optlist opt
+%type <optType> optval TOK_OPT_HSCALE TOK_OPT_WIDTH TOK_OPT_ARCGRADIENT TOK_OPT_WORDWRAPARCS
+%type <arc> arc arcrel
+%type <arclist> arclist
+%type <entity> entity
+%type <entitylist> entitylist
+%type <arctype> relation_box relation_line relation_bi relation_to relation_from
+ TOK_REL_SIG_BI TOK_REL_METHOD_BI TOK_REL_RETVAL_BI TOK_REL_CALLBACK_BI
+ TOK_REL_SIG_TO TOK_REL_METHOD_TO TOK_REL_RETVAL_TO TOK_REL_CALLBACK_TO TOK_REL_DOUBLE_BI
+ TOK_REL_SIG_FROM TOK_REL_METHOD_FROM TOK_REL_RETVAL_FROM TOK_REL_CALLBACK_FROM
+ TOK_REL_DOUBLE_TO TOK_REL_DOUBLE_FROM
+ TOK_REL_LOSS_TO TOK_REL_LOSS_FROM
+ TOK_SPECIAL_ARC TOK_REL_BOX TOK_REL_ABOX TOK_REL_RBOX TOK_REL_NOTE
+ TOK_REL_SIG TOK_REL_METHOD TOK_REL_RETVAL TOK_REL_DOUBLE
+%type <attrib> attrlist attr
+%type <attribType> attrval
+ TOK_ATTR_LABEL TOK_ATTR_URL TOK_ATTR_ID TOK_ATTR_IDURL
+ TOK_ATTR_LINE_COLOUR TOK_ATTR_TEXT_COLOUR TOK_ATTR_TEXT_BGCOLOUR
+ TOK_ATTR_ARC_LINE_COLOUR TOK_ATTR_ARC_TEXT_COLOUR TOK_ATTR_ARC_TEXT_BGCOLOUR
+ TOK_ATTR_ARC_SKIP
+%type <string> string TOK_STRING TOK_QSTRING
+
+
+%%
+msc: TOK_MSC TOK_OCBRACKET optlist TOK_SEMICOLON entitylist TOK_SEMICOLON arclist TOK_SEMICOLON TOK_CCBRACKET
+{
+ $$ = MscAlloc($3, $5, $7);
+ *(Msc *)yyparse_result = $$;
+
+}
+ | TOK_MSC TOK_OCBRACKET entitylist TOK_SEMICOLON arclist TOK_SEMICOLON TOK_CCBRACKET
+{
+ $$ = MscAlloc(NULL, $3, $5);
+ *(Msc *)yyparse_result = $$;
+
+};
+
+optlist: opt
+ | optlist TOK_COMMA opt
+{
+ $$ = MscLinkOpt($1, $3);
+};
+
+opt: optval TOK_EQUAL string
+{
+ $$ = MscAllocOpt($1, $3);
+};
+
+optval: TOK_OPT_HSCALE | TOK_OPT_WIDTH | TOK_OPT_ARCGRADIENT | TOK_OPT_WORDWRAPARCS;
+
+entitylist: entity
+{
+ $$ = MscLinkEntity(NULL, $1); /* Create new list */
+}
+ | entitylist TOK_COMMA entity
+{
+ $$ = MscLinkEntity($1, $3); /* Add to existing list */
+};
+
+
+
+entity: string
+{
+ $$ = MscAllocEntity($1);
+}
+ | entity TOK_OSBRACKET attrlist TOK_CSBRACKET
+{
+ MscEntityLinkAttrib($1, $3);
+}
+;
+
+arclist: arc
+{
+ $$ = MscLinkArc(NULL, $1); /* Create new list */
+}
+ | arclist TOK_SEMICOLON arc
+{
+ $$ = MscLinkArc($1, $3); /* Add to existing list */
+}
+ | arclist TOK_COMMA arc
+{
+ /* Add a special 'parallel' arc */
+ $$ = MscLinkArc(MscLinkArc($1, MscAllocArc(NULL, NULL, MSC_ARC_PARALLEL, lex_getlinenum())), $3);
+};
+;
+
+
+
+arc: arcrel TOK_OSBRACKET attrlist TOK_CSBRACKET
+{
+ MscArcLinkAttrib($1, $3);
+}
+ | arcrel;
+
+arcrel: TOK_SPECIAL_ARC
+{
+ $$ = MscAllocArc(NULL, NULL, $1, lex_getlinenum());
+}
+ | string relation_box string
+{
+ $$ = MscAllocArc($1, $3, $2, lex_getlinenum());
+}
+ | string relation_bi string
+{
+ MscArc arc = MscAllocArc($1, $3, $2, lex_getlinenum());
+ MscArcLinkAttrib(arc, MscAllocAttrib(MSC_ATTR_BI_ARROWS, strdup_s("true")));
+ $$ = arc;
+}
+ | string relation_to string
+{
+ $$ = MscAllocArc($1, $3, $2, lex_getlinenum());
+}
+ | string relation_line string
+{
+ MscArc arc = MscAllocArc($1, $3, $2, lex_getlinenum());
+ MscArcLinkAttrib(arc, MscAllocAttrib(MSC_ATTR_NO_ARROWS, strdup_s("true")));
+ $$ = arc;
+}
+ | string relation_from string
+{
+ $$ = MscAllocArc($3, $1, $2, lex_getlinenum());
+}
+ | string relation_to TOK_ASTERISK
+{
+ $$ = MscAllocArc($1, strdup_s("*"), $2, lex_getlinenum());
+}
+ | TOK_ASTERISK relation_from string
+{
+ $$ = MscAllocArc($3, strdup_s("*"), $2, lex_getlinenum());
+};
+
+relation_box: TOK_REL_BOX | TOK_REL_ABOX | TOK_REL_RBOX | TOK_REL_NOTE;
+relation_line: TOK_REL_SIG | TOK_REL_METHOD | TOK_REL_RETVAL | TOK_REL_DOUBLE;
+relation_bi: TOK_REL_SIG_BI | TOK_REL_METHOD_BI | TOK_REL_RETVAL_BI | TOK_REL_CALLBACK_BI | TOK_REL_DOUBLE_BI;
+relation_to: TOK_REL_SIG_TO | TOK_REL_METHOD_TO | TOK_REL_RETVAL_TO | TOK_REL_CALLBACK_TO | TOK_REL_DOUBLE_TO | TOK_REL_LOSS_TO;
+relation_from: TOK_REL_SIG_FROM | TOK_REL_METHOD_FROM | TOK_REL_RETVAL_FROM | TOK_REL_CALLBACK_FROM | TOK_REL_DOUBLE_FROM | TOK_REL_LOSS_FROM;
+
+attrlist: attr
+ | attrlist TOK_COMMA attr
+{
+ $$ = MscLinkAttrib($1, $3);
+};
+
+attr: attrval TOK_EQUAL string
+{
+ $$ = MscAllocAttrib($1, $3);
+};
+
+attrval: TOK_ATTR_LABEL | TOK_ATTR_URL | TOK_ATTR_ID | TOK_ATTR_IDURL |
+ TOK_ATTR_LINE_COLOUR | TOK_ATTR_TEXT_COLOUR | TOK_ATTR_TEXT_BGCOLOUR |
+ TOK_ATTR_ARC_LINE_COLOUR | TOK_ATTR_ARC_TEXT_COLOUR | TOK_ATTR_ARC_TEXT_BGCOLOUR |
+ TOK_ATTR_ARC_SKIP;
+
+
+string: TOK_QSTRING
+{
+ $$ = removeEscapes($1);
+}
+ | TOK_STRING
+{
+ $$ = $1;
+};
+%%
+
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_lexer.h b/libmscgen/mscgen_lexer.h
new file mode 100644
index 0000000..0cbb21f
--- /dev/null
+++ b/libmscgen/mscgen_lexer.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *
+ * $Id: lexer.h 152 2010-10-10 14:17:37Z Michael.McTernan $
+ *
+ * Extra lexer/scanner API functions.
+ * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ ***************************************************************************/
+
+#ifndef MSCGEN_LEXER_H
+#define MSCGEN_LEXER_H
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+#include "mscgen_bool.h"
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Declarations
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Function Declarations
+ *****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+Boolean lex_getutf8(void);
+#ifdef __cplusplus
+}
+#endif
+
+unsigned long lex_getlinenum(void);
+char *lex_getline(void);
+void lex_destroy(void);
+
+#endif /* MSCGEN_LEXER_H */
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_lexer.l b/libmscgen/mscgen_lexer.l
new file mode 100644
index 0000000..29d6aea
--- /dev/null
+++ b/libmscgen/mscgen_lexer.l
@@ -0,0 +1,236 @@
+%{
+/***************************************************************************
+ *
+ * $Id: lexer.l 184 2011-02-28 21:38:28Z Michael.McTernan $
+ *
+ * Mscgen language lexer definition.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This file is part of msclib.
+ *
+ * Msc is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * Msclib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with msclib; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "mscgen_config.h"
+#include "mscgen_msc.h"
+#include "mscgen_bool.h"
+#include "mscgen_safe.h"
+#include "mscgen_lexer.h"
+#include "mscgen_language.h" /* Token definitions from Yacc/Bison */
+/* Counter for error reporting */
+static unsigned long lex_linenum = 1;
+static char *lex_line = NULL;
+static Boolean lex_utf8 = FALSE;
+
+/* Local function prototypes */
+static void newline(const char *text, unsigned int n);
+static char *trimQstring(char *s);
+
+%}
+
+/* Not used, so prevent compiler warning */
+%option never-interactive
+%option noinput
+%option noyywrap
+
+%x IN_COMMENT BODY
+%%
+
+<INITIAL>{
+\xef\xbb\xbf lex_utf8 = TRUE; BEGIN(BODY);
+(\r\n).* newline(yytext, 2); BEGIN(BODY);
+(\r|\n).* newline(yytext, 1); BEGIN(BODY);
+. unput(yytext[0]); BEGIN(BODY);
+}
+
+<IN_COMMENT>{
+"*/" BEGIN(BODY);
+[^*\n]+
+"*"
+(\r\n).* newline(yytext, 2);
+(\r|\n).* newline(yytext, 1);
+}
+
+<BODY>{
+
+"/*" BEGIN(IN_COMMENT);
+
+(\r\n).* newline(yytext, 2);
+(\r|\n).* newline(yytext, 1);
+
+#.*$ /* Ignore lines after '#' */
+\/\/.*$ /* Ignore lines after '//' */
+
+msc return TOK_MSC;
+HSCALE|hscale yylval.optType = MSC_OPT_HSCALE; return TOK_OPT_HSCALE;
+WIDTH|width yylval.optType = MSC_OPT_WIDTH; return TOK_OPT_WIDTH;
+ARCGRADIENT|arcgradient yylval.optType = MSC_OPT_ARCGRADIENT; return TOK_OPT_ARCGRADIENT;
+WORDWRAPARCS|wordwraparcs yylval.optType = MSC_OPT_WORDWRAPARCS; return TOK_OPT_WORDWRAPARCS;
+URL|url yylval.attribType = MSC_ATTR_URL; return TOK_ATTR_URL;
+LABEL|label yylval.attribType = MSC_ATTR_LABEL; return TOK_ATTR_LABEL;
+IDURL|idurl yylval.attribType = MSC_ATTR_IDURL; return TOK_ATTR_IDURL;
+ID|id yylval.attribType = MSC_ATTR_ID; return TOK_ATTR_ID;
+LINECOLO(U?)R|linecolo(u?)r yylval.attribType = MSC_ATTR_LINE_COLOUR; return TOK_ATTR_LINE_COLOUR;
+TEXTCOLO(U?)R|textcolo(u?)r yylval.attribType = MSC_ATTR_TEXT_COLOUR; return TOK_ATTR_TEXT_COLOUR;
+TEXTBGCOLO(U?)R|textbgcolo(u?)r yylval.attribType = MSC_ATTR_TEXT_BGCOLOUR; return TOK_ATTR_TEXT_BGCOLOUR;
+ARCLINECOLO(U?)R|arclinecolo(u?)r yylval.attribType = MSC_ATTR_ARC_LINE_COLOUR; return TOK_ATTR_ARC_LINE_COLOUR;
+ARCTEXTCOLO(U?)R|arctextcolo(u?)r yylval.attribType = MSC_ATTR_ARC_TEXT_COLOUR; return TOK_ATTR_ARC_TEXT_COLOUR;
+ARCTEXTBGCOLO(U?)R|arctextbgcolo(u?)r yylval.attribType = MSC_ATTR_ARC_TEXT_BGCOLOUR; return TOK_ATTR_ARC_TEXT_BGCOLOUR;
+ARCSKIP|arcskip yylval.attribType = MSC_ATTR_ARC_SKIP; return TOK_ATTR_ARC_SKIP;
+\.\.\. yylval.arctype = MSC_ARC_DISCO; return TOK_SPECIAL_ARC; /* ... */
+--- yylval.arctype = MSC_ARC_DIVIDER; return TOK_SPECIAL_ARC; /* --- */
+\|\|\| yylval.arctype = MSC_ARC_SPACE; return TOK_SPECIAL_ARC; /* ||| */
+\<-\> yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG_BI; /* <-> */
+-\> yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG_TO; /* -> */
+\<- yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG_FROM; /* <- */
+-- yylval.arctype = MSC_ARC_SIGNAL; return TOK_REL_SIG; /* -- */
+-[Xx] yylval.arctype = MSC_ARC_LOSS; return TOK_REL_LOSS_TO; /* -x */
+[Xx]- yylval.arctype = MSC_ARC_LOSS; return TOK_REL_LOSS_FROM; /* x- */
+\<=\> yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD_BI; /* <=> */
+=\> yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD_TO; /* => */
+\<= yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD_FROM; /* <= */
+== yylval.arctype = MSC_ARC_METHOD; return TOK_REL_METHOD; /* == */
+\<\<\>\> yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL_BI; /* <<>> */
+\>\> yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL_TO; /* >> */
+\<\< yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL_FROM; /* << */
+\.\. yylval.arctype = MSC_ARC_RETVAL; return TOK_REL_RETVAL; /* .. */
+\<:\> yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE_BI; /* <:> */
+:\> yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE_TO; /* :> */
+\<: yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE_FROM; /* <: */
+:: yylval.arctype = MSC_ARC_DOUBLE; return TOK_REL_DOUBLE; /* :: */
+\<\<=\>\> yylval.arctype = MSC_ARC_CALLBACK; return TOK_REL_CALLBACK_BI; /* <<=>> */
+=\>\> yylval.arctype = MSC_ARC_CALLBACK; return TOK_REL_CALLBACK_TO; /* =>> */
+\<\<= yylval.arctype = MSC_ARC_CALLBACK; return TOK_REL_CALLBACK_FROM; /* <<= */
+BOX|box yylval.arctype = MSC_ARC_BOX; return TOK_REL_BOX; /* box */
+ABOX|abox yylval.arctype = MSC_ARC_ABOX; return TOK_REL_ABOX; /* abox */
+RBOX|rbox yylval.arctype = MSC_ARC_RBOX; return TOK_REL_RBOX; /* rbox */
+NOTE|note yylval.arctype = MSC_ARC_NOTE; return TOK_REL_NOTE; /* note */
+[A-Za-z0-9_]+ yylval.string = strdup_s(yytext); return TOK_STRING;
+\"(\\\"|[^\"])*\" yylval.string = trimQstring(strdup_s(yytext)); return TOK_QSTRING;
+= return TOK_EQUAL;
+, return TOK_COMMA;
+\; return TOK_SEMICOLON;
+\{ return TOK_OCBRACKET;
+\} return TOK_CCBRACKET;
+\[ return TOK_OSBRACKET;
+\] return TOK_CSBRACKET;
+\* return TOK_ASTERISK;
+[ \t]+ /* ignore whitespace */;
+
+}
+
+
+<*>.|\n|\r return TOK_UNKNOWN;
+
+%%
+
+/* Handle a new line of input.
+ * This counts the line number and duplicates the string incase we need
+ * it for error reporting. The line is then returned back for parsing
+ * without the newline characters prefixed.
+ */
+static void newline(const char *text, unsigned int n)
+{
+ lex_linenum++;
+ if(lex_line != NULL)
+ {
+ free(lex_line);
+ }
+
+ lex_line = strdup(text + n);
+ yyless(n);
+}
+
+
+/* Trim a multi-line quoted string.
+ * This allows the parsed input quoted strings to span multiple lines of
+ * input but be condensed to only a single line of output e.g.
+ * a->b [label="line 1
+ * line 1 too"];
+ * Will parse to a string such as"line1\n line1 too". This function
+ * will collapse the \n and whitespace into a single space.
+ */
+static char *trimQstring(char *const s)
+{
+ int i = 0, o = 0, skipmode = 0;
+
+ /* Strip leading " */
+ if(s[i] == '\"')
+ {
+ i++;
+ }
+
+ /* Copy body, compacting whitespace after newline sequences */
+ while(s[i] != '\0')
+ {
+ if(s[i] == '\r' || s[i] == '\n' || s[i] == '\f')
+ {
+ skipmode = 1;
+ }
+ else if(!skipmode || !isspace(s[i]))
+ {
+ if(skipmode)
+ {
+ s[o] = ' ';
+ o++;
+ }
+
+ skipmode = 0;
+ s[o] = s[i];
+ o++;
+ }
+
+ i++;
+ }
+
+ /* Null terminate */
+ s[o] = '\0';
+
+ /* Remove trailing " */
+ if(o >= 1 && s[o - 1] == '\"')
+ s[o-1] = '\0';
+
+ return s;
+}
+
+unsigned long lex_getlinenum(void)
+{
+ return lex_linenum;
+}
+
+char *lex_getline(void)
+{
+ return lex_line;
+}
+
+void lex_destroy(void)
+{
+ if(lex_line != NULL)
+ {
+ free(lex_line);
+ lex_line = NULL;
+ }
+}
+
+Boolean lex_getutf8(void)
+{
+ return lex_utf8;
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_msc.c b/libmscgen/mscgen_msc.c
new file mode 100644
index 0000000..0a17395
--- /dev/null
+++ b/libmscgen/mscgen_msc.c
@@ -0,0 +1,804 @@
+/***************************************************************************
+ *
+ * $Id: msc.c 175 2011-02-06 21:07:43Z Michael.McTernan $
+ *
+ * The message sequence parser ADT.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include "mscgen_config.h"
+#include "mscgen_safe.h"
+#include "mscgen_msc.h"
+
+/***************************************************************************
+ * Structures
+ ***************************************************************************/
+
+struct MscEntityTag
+{
+ char *label;
+ struct MscAttribTag *attr;
+ struct MscEntityTag *next;
+};
+
+struct MscEntityListTag
+{
+ unsigned int elements;
+ struct MscEntityTag *head, *tail;
+};
+
+struct MscArcTag
+{
+ char *src, *dst;
+ MscArcType type;
+ unsigned int inputLine;
+ struct MscAttribTag *attr;
+ struct MscArcTag *next;
+};
+
+struct MscArcListTag
+{
+ unsigned int elements;
+ unsigned int parElements;
+ struct MscArcTag *head, *tail;
+};
+
+
+struct MscAttribTag
+{
+ MscAttribType type;
+ char *value;
+ struct MscAttribTag *next;
+};
+
+struct MscOptTag
+{
+ MscOptType type;
+ char *value;
+ struct MscOptTag *next;
+};
+
+struct MscTag
+{
+ struct MscOptTag *optList;
+ struct MscEntityListTag *entityList;
+ struct MscArcListTag *arcList;
+
+ struct MscArcTag *nextArc;
+ struct MscEntityTag *nextEntity;
+};
+
+/***************************************************************************
+ * Local Functions
+ ***************************************************************************/
+
+/** Find come attrbute in an attribute list.
+ *
+ * \param[in] attr Head of the linked list to search.
+ * \param[in] a The attribute type to find.
+ * \retval NULL If the attribute was not found or the passed list was NULL.
+ */
+static const char *findAttrib(const struct MscAttribTag *attr, MscAttribType a)
+{
+ while(attr != NULL && attr->type != a)
+ {
+ attr = attr->next;
+ }
+
+ if(attr != NULL)
+ {
+ return attr->value;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+/** Free the memory underlying a list of attributes.
+ */
+static void freeAttribList(struct MscAttribTag *attr)
+{
+ while(attr)
+ {
+ struct MscAttribTag *next = attr->next;
+ free(attr->value);
+ free(attr);
+ attr = next;
+ }
+}
+
+/***************************************************************************
+ * Option Functions
+ ***************************************************************************/
+
+/* Allocate some option and set it's value.
+ */
+struct MscOptTag *MscAllocOpt(MscOptType type,
+ char *value)
+{
+ struct MscOptTag *a = malloc_s(sizeof(struct MscOptTag));
+
+ a->type = type;
+ a->value = value;
+ a->next = NULL;
+
+ return a;
+}
+
+/* Link one or two options together.
+ */
+struct MscOptTag *MscLinkOpt(struct MscOptTag *head,
+ struct MscOptTag *newHead)
+{
+ struct MscOptTag *tail = newHead;
+
+ assert(newHead);
+
+ /* Find the end of the list */
+ while(tail->next)
+ {
+ tail = tail->next;
+ }
+
+ tail->next = head;
+ return newHead;
+}
+
+/* MscPrettyOptType
+ * Returns a string that is the human readable form of the option
+ * code passed to the function.
+ */
+const char *MscPrettyOptType(MscOptType t)
+{
+ switch(t)
+ {
+ case MSC_OPT_HSCALE: return "hscale";
+ case MSC_OPT_WIDTH: return "width";
+ case MSC_OPT_ARCGRADIENT: return "arcgradient";
+ default:
+ return "unknown";
+ }
+}
+
+struct MscOptTag *MscFindOpt(struct MscOptTag *list,
+ MscOptType type)
+{
+ struct MscOptTag *elem = list;
+
+ while(elem && elem->type != type)
+ {
+ elem = elem->next;
+ }
+
+ if(elem && elem->type == type)
+ {
+ return elem;
+ }
+
+ return NULL;
+}
+
+void MscPrintOptList(struct MscOptTag *list)
+{
+ struct MscOptTag *elem = list;
+
+ while(elem)
+ {
+ printf("%p: %s=%s\n", elem, MscPrettyOptType(elem->type), elem->value);
+ elem = elem->next;
+ }
+}
+
+/***************************************************************************
+ * Entity Functions
+ ***************************************************************************/
+
+/* MscAllocEntity
+ * Allocate some entity and set it's name.
+ */
+struct MscEntityTag *MscAllocEntity(char *entityName)
+{
+ struct MscEntityTag *e = malloc_s(sizeof(struct MscEntityListTag));
+
+ e->label = entityName;
+ e->attr = NULL;
+ e->next = NULL;
+
+ return e;
+}
+
+
+/* MscLinkEntity
+ * Link some entity onto a list, possibly producing a new head element.
+ */
+struct MscEntityListTag *MscLinkEntity(struct MscEntityListTag *list,
+ struct MscEntityTag *elem)
+{
+ /* Check if the list has been allocated or not */
+ if(list == NULL)
+ {
+ list = zalloc_s(sizeof(struct MscEntityListTag));
+ }
+
+ /* Check for an empty list */
+ if(list->head == NULL)
+ {
+ list->head = list->tail = elem;
+ }
+ else
+ {
+ /* Add to tail */
+ list->tail->next = elem;
+ list->tail = elem;
+ }
+
+ /* Increment count of elements */
+ list->elements++;
+
+ return list;
+}
+
+
+void MscPrintEntityList(struct MscEntityListTag *list)
+{
+ struct MscEntityTag *elem = list->head;
+
+ while(elem)
+ {
+ printf("%p: %s\n", elem, elem->label);
+ MscPrintAttrib(elem->attr);
+ elem = elem->next;
+ }
+}
+
+/***************************************************************************
+ * Arc Functions
+ ***************************************************************************/
+
+/* MscAllocArc
+ * Allocate an arc, filling in the src and dst entities.
+ */
+struct MscArcTag *MscAllocArc(char *srcEntity,
+ char *dstEntity,
+ MscArcType type,
+ unsigned int inputLine)
+{
+ struct MscArcTag *a = malloc_s(sizeof(struct MscArcTag));
+
+ /* A discontinuity arcs are not between entities */
+ if(type == MSC_ARC_DISCO)
+ {
+ assert(srcEntity == NULL && dstEntity == NULL);
+ }
+
+ a->inputLine = inputLine;
+ a->src = srcEntity;
+ a->dst = dstEntity;
+ a->type = type;
+ a->next = NULL;
+ a->attr = NULL;
+
+ return a;
+}
+
+
+/* MscLinkArc
+ * Link some entity onto a list, possibly producing a new head element.
+ */
+struct MscArcListTag *MscLinkArc(struct MscArcListTag *list,
+ struct MscArcTag *elem)
+{
+ /* Check if the list has been allocated or not */
+ if(list == NULL)
+ {
+ list = zalloc_s(sizeof(struct MscArcListTag));
+ }
+
+ /* Check for an empty list */
+ if(list->head == NULL)
+ {
+ list->head = list->tail = elem;
+ }
+ else
+ {
+ /* Add to tail */
+ list->tail->next = elem;
+ list->tail = elem;
+ }
+
+ /* Increment count of elements */
+ list->elements++;
+ if(elem->type == MSC_ARC_PARALLEL)
+ {
+ /* A parallel arc is a place holder, and indicates the next arc
+ * is on the same line. It also needs to account itself, so subtract
+ * two here.
+ */
+ list->parElements += 2;
+ }
+
+ return list;
+}
+
+
+/* MscPrintArcList
+ * Dump and arc list.
+ */
+void MscPrintArcList(struct MscArcListTag *list)
+{
+ struct MscArcTag *elem = list->head;
+
+ while(elem)
+ {
+ printf("%p: '%s' -> '%s'\n", elem, elem->src, elem->dst);
+ MscPrintAttrib(elem->attr);
+
+ elem = elem->next;
+ }
+}
+
+
+/***************************************************************************
+ * Attribute functions
+ ***************************************************************************/
+
+/* MscAllocAttrib
+ * Allocate some attribute.
+ */
+struct MscAttribTag *MscAllocAttrib(MscAttribType type,
+ char *value)
+{
+ struct MscAttribTag *a = malloc_s(sizeof(struct MscAttribTag));
+
+ a->type = type;
+ a->value = value;
+ a->next = NULL;
+
+ return a;
+}
+
+
+/* MscLinkAttrib
+ * Link some attributes. The ordering of attributes is semi-important
+ * so the list is grown from the tail.
+ */
+struct MscAttribTag *MscLinkAttrib(struct MscAttribTag *head,
+ struct MscAttribTag *newHead)
+{
+ struct MscAttribTag *tail = newHead;
+
+ assert(newHead);
+
+ /* Find the end of the list */
+ while(tail->next)
+ {
+ tail = tail->next;
+ }
+
+ tail->next = head;
+ return newHead;
+}
+
+
+/* MscArcLinkAttrib
+ * Attach some attributes to some arc.
+ */
+void MscArcLinkAttrib(struct MscArcTag *arc,
+ struct MscAttribTag *att)
+{
+ if(arc->attr)
+ {
+ arc->attr = MscLinkAttrib(arc->attr, att);
+ }
+ else
+ {
+ arc->attr = att;
+ }
+}
+
+
+/* MscEntityLinkAttrib
+ * Attach some attributes to some entity.
+ */
+void MscEntityLinkAttrib(struct MscEntityTag *ent,
+ struct MscAttribTag *att)
+{
+ if(ent->attr)
+ {
+ ent->attr = MscLinkAttrib(ent->attr, att);
+ }
+ else
+ {
+ ent->attr = att;
+ }
+}
+
+
+/* MscPrintAttrib
+ * String a human readable version of the passed attribute list to stdout.
+ */
+void MscPrintAttrib(const struct MscAttribTag *att)
+{
+ while(att)
+ {
+ printf(" %s = %s\n", MscPrettyAttribType(att->type), att->value);
+ att = att->next;
+ }
+
+}
+
+
+/* MscPrettyAttribType
+ * Returns a string that is the human readable form of the attribute
+ * code passed to the function.
+ */
+const char *MscPrettyAttribType(MscAttribType t)
+{
+ switch(t)
+ {
+ case MSC_ATTR_LABEL: return "label";
+ case MSC_ATTR_URL: return "url";
+ case MSC_ATTR_ID: return "id";
+ case MSC_ATTR_IDURL: return "idurl";
+ case MSC_ATTR_LINE_COLOUR: return "linecolour";
+ case MSC_ATTR_TEXT_COLOUR: return "textcolour";
+ case MSC_ATTR_TEXT_BGCOLOUR: return "textbgcolour";
+ case MSC_ATTR_ARC_LINE_COLOUR: return "arclinecolour";
+ case MSC_ATTR_ARC_TEXT_COLOUR: return "arctextcolour";
+ case MSC_ATTR_ARC_TEXT_BGCOLOUR: return "arctextbgcolour";
+ case MSC_ATTR_NO_ARROWS: return "noarrows";
+ case MSC_ATTR_BI_ARROWS : return "biarrows";
+ default:
+ return "<unknown>";
+ }
+}
+
+
+/***************************************************************************
+ * MSC Functions
+ ***************************************************************************/
+
+struct MscTag *MscAlloc(struct MscOptTag *optList,
+ struct MscEntityListTag *entityList,
+ struct MscArcListTag *arcList)
+{
+ struct MscTag *m = malloc_s(sizeof(struct MscTag));
+
+ /* Copy the lists */
+ m->optList = optList;
+ m->entityList = entityList;
+ m->arcList = arcList;
+
+ /* Reset the iterators */
+ MscResetEntityIterator(m);
+ MscResetArcIterator(m);
+
+ return m;
+}
+
+void MscFree(struct MscTag *m)
+{
+ struct MscOptTag *opt = m->optList;
+ struct MscEntityTag *entity = m->entityList->head;
+ struct MscArcTag *arc = m->arcList->head;
+
+ while(opt)
+ {
+ struct MscOptTag *next = opt->next;
+
+ free(opt->value);
+ free(opt);
+
+ opt = next;
+ }
+
+ while(entity)
+ {
+ struct MscEntityTag *next = entity->next;
+
+ freeAttribList(entity->attr);
+ free(entity->label);
+ free(entity);
+
+ entity = next;
+ }
+
+ while(arc)
+ {
+ struct MscArcTag *next = arc->next;
+
+ freeAttribList(arc->attr);
+ free(arc->dst);
+ free(arc->src);
+ free(arc);
+
+ arc = next;
+ }
+
+ free(m->entityList);
+ free(m->arcList);
+ free(m);
+}
+
+void MscPrint(struct MscTag *m)
+{
+ printf("Option list (%d options)\n", MscGetNumOpts(m));
+ MscPrintOptList(m->optList);
+
+ printf("Entity list (%d entities, %d parallel)\n",
+ MscGetNumEntities(m), MscGetNumParallelArcs(m));
+ MscPrintEntityList(m->entityList);
+
+ printf("\nArc list (%d arcs)\n", MscGetNumArcs(m));
+ MscPrintArcList(m->arcList);
+}
+
+unsigned int MscGetNumEntities(struct MscTag *m)
+{
+ return m->entityList->elements;
+}
+
+unsigned int MscGetNumArcs(Msc m)
+{
+ return m->arcList->elements;
+}
+
+unsigned int MscGetNumParallelArcs(Msc m)
+{
+ return m->arcList->parElements;
+}
+
+unsigned int MscGetNumOpts(Msc m)
+{
+ struct MscOptTag *elem = m->optList;
+ unsigned int count = 0;
+
+ while(elem)
+ {
+ count++;
+ elem = elem->next;
+ }
+
+ return count;
+}
+
+int MscGetEntityIndex(struct MscTag *m, const char *label)
+{
+ struct MscEntityTag *entity = m->entityList->head;
+ int c = 0;
+
+ assert(label);
+
+ while(entity != NULL && strcmp(entity->label, label) != 0)
+ {
+ entity = entity->next;
+ c++;
+ }
+
+ if(entity == NULL)
+ {
+ return -1;
+ }
+ else
+ {
+ return c;
+ }
+}
+
+void MscResetEntityIterator(struct MscTag *m)
+{
+ m->nextEntity = m->entityList->head;
+}
+
+Boolean MscNextEntity(struct MscTag *m)
+{
+ if(m->nextEntity->next != NULL)
+ {
+ m->nextEntity = m->nextEntity->next;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+const char *MscGetCurrentEntAttrib(struct MscTag *m, MscAttribType a)
+{
+ const char *r;
+
+ if(!m->nextEntity)
+ {
+ return NULL;
+ }
+
+ r = findAttrib(m->nextEntity->attr, a);
+
+ /* If the entity label was sought but not found, return entity name */
+ if(r == NULL && a == MSC_ATTR_LABEL)
+ {
+ return m->nextEntity->label;
+ }
+ else
+ {
+ return r;
+ }
+}
+
+
+const char *MscGetEntAttrib(Msc m, unsigned int entIdx, MscAttribType a)
+{
+ struct MscEntityTag *entity;
+ const char *r;
+
+ /* Find the entity */
+ entity = m->entityList->head;
+ while(entIdx > 0 && entity != NULL)
+ {
+ entity = entity->next;
+ entIdx--;
+ }
+
+ /* Search the attribute list if the entity was found */
+ if(entity)
+ {
+ r = findAttrib(entity->attr, a);
+
+ /* If the entity label was sought but not found, return entity name */
+ if(r == NULL && a == MSC_ATTR_LABEL)
+ {
+ return m->nextEntity->label;
+ }
+ else
+ {
+ return r;
+ }
+ }
+ else
+ {
+ /* Entity was not found */
+ return NULL;
+ }
+}
+
+
+void MscResetArcIterator(struct MscTag *m)
+{
+ m->nextArc = m->arcList->head;
+}
+
+Boolean MscNextArc(struct MscTag *m)
+{
+ if(m->nextArc->next != NULL)
+ {
+ m->nextArc = m->nextArc->next;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+const char *MscGetCurrentArcSource(struct MscTag *m)
+{
+ return m->nextArc ? m->nextArc->src : NULL;
+}
+
+const char *MscGetCurrentArcDest(struct MscTag *m)
+{
+ return m->nextArc ? m->nextArc->dst : NULL;
+}
+
+MscArcType MscGetCurrentArcType(struct MscTag *m)
+{
+ return m->nextArc ? m->nextArc->type : MSC_INVALID_ARC_TYPE;
+}
+
+const char *MscGetCurrentArcAttrib(struct MscTag *m, MscAttribType a)
+{
+ struct MscAttribTag *attr;
+
+ if(!m->nextArc)
+ {
+ return NULL;
+ }
+
+ attr = m->nextArc->attr;
+
+ while(attr != NULL && attr->type != a)
+ {
+ attr = attr->next;
+ }
+
+ if(attr != NULL)
+ {
+ return attr->value;
+ }
+ else
+ {
+ return NULL;
+ }
+
+}
+
+Boolean MscGetOptAsFloat(struct MscTag *m, MscOptType type, float *const f)
+{
+ struct MscOptTag *opt = MscFindOpt(m->optList, type);
+
+ if(opt != NULL)
+ {
+ *f = (float)atof(opt->value);
+ return *f != 0.0f;
+ }
+
+ return FALSE;
+}
+
+unsigned int MscGetCurrentArcInputLine(struct MscTag *m)
+{
+ if(m->nextArc)
+ {
+ return m->nextArc->inputLine;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+Boolean MscGetOptAsBoolean(struct MscTag *m, MscOptType type, Boolean *const b)
+{
+ struct MscOptTag *opt = MscFindOpt(m->optList, type);
+
+ if(opt != NULL)
+ {
+ const char *v = opt->value;
+
+ if(strcasecmp(v, "true") == 0 || strcasecmp(v, "yes") == 0 ||
+ strcasecmp(v, "on") == 0 || strcasecmp(v, "1") == 0)
+ {
+ *b = TRUE;
+ return TRUE;
+ }
+ else if(strcasecmp(v, "false") == 0 || strcasecmp(v, "no") == 0 ||
+ strcasecmp(v, "off") == 0 || strcasecmp(v, "0") == 0)
+ {
+ *b = FALSE;
+ return TRUE;
+ }
+ else
+ {
+ fprintf(stderr, "Warning: Unrecognised boolean option value '%s'. Valid values are 'true',\n"
+ " 'false', 'yes', 'no', 'on', 'off', '1' and '0'.\n",
+ v);
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+/* END OF FILE */
+
diff --git a/libmscgen/mscgen_msc.h b/libmscgen/mscgen_msc.h
new file mode 100644
index 0000000..2c75131
--- /dev/null
+++ b/libmscgen/mscgen_msc.h
@@ -0,0 +1,299 @@
+/***************************************************************************
+ *
+ * $Id: msc.h 175 2011-02-06 21:07:43Z Michael.McTernan $
+ *
+ * The message sequence parser API.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ ***************************************************************************/
+
+#ifndef MSCGEN_MSC_H
+#define MSCGEN_MSC_H
+
+#include "mscgen_bool.h"
+
+/***************************************************************************
+ * Types
+ ***************************************************************************/
+
+/** Msc Options.
+ */
+typedef enum MscOptTypeTag
+{
+ MSC_OPT_HSCALE,
+ MSC_OPT_WIDTH,
+ MSC_OPT_ARCGRADIENT,
+ MSC_OPT_WORDWRAPARCS
+}
+MscOptType;
+
+
+/** Arc attributes.
+ * An arc may have one or more attributes listed in square brackets after
+ * the declaration. This gives an enumerated type for each permissible
+ * attribute.
+ */
+typedef enum MscAttribTypeTag
+{
+ MSC_ATTR_LABEL,
+ MSC_ATTR_ID,
+ MSC_ATTR_URL,
+ MSC_ATTR_IDURL,
+ MSC_ATTR_LINE_COLOUR,
+ MSC_ATTR_TEXT_COLOUR,
+ MSC_ATTR_TEXT_BGCOLOUR,
+ MSC_ATTR_ARC_LINE_COLOUR,
+ MSC_ATTR_ARC_TEXT_COLOUR,
+ MSC_ATTR_ARC_TEXT_BGCOLOUR,
+ MSC_ATTR_NO_ARROWS,
+ MSC_ATTR_BI_ARROWS,
+ MSC_ATTR_ARC_SKIP
+}
+MscAttribType;
+
+
+typedef enum
+{
+ MSC_ARC_METHOD,
+ MSC_ARC_RETVAL,
+ MSC_ARC_SIGNAL,
+ MSC_ARC_CALLBACK,
+ MSC_ARC_DOUBLE,
+ MSC_ARC_DISCO, /* ... Discontinuity in time line */
+ MSC_ARC_DIVIDER, /* --- Divider */
+ MSC_ARC_SPACE, /* ||| */
+ MSC_ARC_PARALLEL, /* Comma instead of semicolon */
+ MSC_ARC_BOX,
+ MSC_ARC_ABOX,
+ MSC_ARC_RBOX,
+ MSC_ARC_NOTE,
+ MSC_ARC_LOSS, /* -x or x- */
+
+ MSC_INVALID_ARC_TYPE
+}
+MscArcType;
+
+
+/***************************************************************************
+ * Abstract types
+ ***************************************************************************/
+
+typedef struct MscTag *Msc;
+
+typedef struct MscOptTag *MscOpt;
+
+typedef struct MscEntityTag *MscEntity;
+
+typedef struct MscEntityListTag *MscEntityList;
+
+typedef struct MscArcTag *MscArc;
+
+typedef struct MscArcListTag *MscArcList;
+
+typedef struct MscAttribTag *MscAttrib;
+
+
+/***************************************************************************
+ * MSC Building Functions
+ ***************************************************************************/
+
+/** Parse some input to build a message sequence chart.
+ * This will parse characters from \a in and build a message sequence chart
+ * ADT.
+ * \retval Msc The message sequence chart, which may equal \a NULL is a
+ * parse error occurred.
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+Msc MscParse(FILE *in);
+
+MscEntity MscAllocEntity(char *entityName);
+
+MscEntityList MscLinkEntity(MscEntityList list, MscEntity elem);
+
+void MscPrintEntityList(MscEntityList list);
+
+MscOpt MscAllocOpt(MscOptType type,
+ char *value);
+
+MscOpt MscLinkOpt(MscOpt head,
+ MscOpt newHead);
+
+MscArc MscAllocArc(char *srcEntity,
+ char *dstEntity,
+ MscArcType type,
+ unsigned int inputLine);
+
+MscArcList MscLinkArc (MscArcList list,
+ MscArc elem);
+
+void MscPrintArcList(struct MscArcListTag *list);
+
+MscAttrib MscAllocAttrib(MscAttribType type,
+ char *value);
+
+MscAttrib MscLinkAttrib(MscAttrib head,
+ MscAttrib newHead);
+
+void MscArcLinkAttrib(MscArc arc,
+ MscAttrib att);
+
+void MscEntityLinkAttrib(MscEntity ent,
+ MscAttrib att);
+
+void MscPrintAttrib(const struct MscAttribTag *att);
+
+const char *MscPrettyAttribType(MscAttribType t);
+
+Msc MscAlloc(MscOpt optList,
+ MscEntityList entityList,
+ MscArcList arcList);
+
+void MscFree(struct MscTag *m);
+
+/** Print the passed msc in textual form to stdout.
+ * This prints a human readable format of the parsed msc to stdout. This
+ * is primarily of use in debugging the parser.
+ */
+void MscPrint(Msc m);
+
+unsigned int MscGetNumEntities(Msc m);
+
+unsigned int MscGetNumArcs(Msc m);
+
+unsigned int MscGetNumParallelArcs(Msc m);
+
+unsigned int MscGetNumOpts(Msc m);
+
+/** Get an MSC option, returning the value as a float.
+ *
+ * \param[in] m The MSC to analyse.
+ * \param[in] type The option type to retrieve.
+ * \param[in,out] f Pointer to be filled with parsed value.
+ * \retval TRUE If the option was found and parsed successfully.
+ */
+Boolean MscGetOptAsFloat(struct MscTag *m, MscOptType type, float *const f);
+
+/** Get an MSC option, returning the value as a Boolean.
+ *
+ * \param[in] m The MSC to analyse.
+ * \param[in] type The option type to retrieve.
+ * \param[in,out] b Pointer to be filled with parsed value.
+ * \retval TRUE If the option was found and parsed successfully,
+ * otherwise FALSE in which case *b is unmodified.
+ *
+ */
+Boolean MscGetOptAsBoolean(struct MscTag *m, MscOptType type, Boolean *const b);
+
+/** Get the index of some entity.
+ * This returns the column index for the entity identified by the passed
+ * label.
+ *
+ * \param m The MSC to analyse.
+ * \param label The label to find.
+ * \retval -1 If the label was not found, otherwise the columnn index.
+ */
+int MscGetEntityIndex(struct MscTag *m, const char *label);
+
+/***************************************************************************
+ * Entity processing functions
+ ***************************************************************************/
+
+/** \defgroup EntityFuncs Entity handling functions
+ * @{
+ */
+
+/** Reset the entity interator.
+ * This moves the pointer to the current entity to the head of the list.
+ */
+void MscResetEntityIterator(Msc m);
+
+/** Move to the next entity in the MSC.
+ * \retval TRUE if there is another entity, otherwise FALSE if the end of the
+ * list has been reached.
+ */
+Boolean MscNextEntity(struct MscTag *m);
+
+/** Get the value of some attribute for the current entity.
+ * \retval The attribute string, or NULL if unset.
+ */
+const char *MscGetCurrentEntAttrib(Msc m, MscAttribType a);
+
+/** Get an attribute associated with some entity.
+ * \param[in] entIdx The index of the entity.
+ * \retval The attribute string, or NULL if unset.
+ */
+const char *MscGetEntAttrib(Msc m, unsigned int entIdx, MscAttribType a);
+
+/** @} */
+
+/***************************************************************************
+ * Arc processing functions
+ ***************************************************************************/
+
+/** \defgroup ArcFuncs Arc handling functions
+ * @{
+ */
+
+/** Reset the arc interator.
+ * This moves the pointer to the current arc to the head of the list.
+ */
+void MscResetArcIterator (Msc m);
+
+/** Move to the next arc in the MSC.
+ * \retval TRUE if there is another arc, otherwise FALSE if the end of the
+ * list has been reached.
+ */
+Boolean MscNextArc(struct MscTag *m);
+
+
+/** Get the name of the entity from which the current arc originates.
+ * \retval The label for the entity from which the current arc starts.
+ * The returned string must not be modified.
+ */
+const char *MscGetCurrentArcSource(Msc m);
+
+
+/** Get the name of the entity at which the current arc terminates.
+ * \retval The label for the entity at which the current arc stops.
+ * The returned string must not be modified.
+ */
+const char *MscGetCurrentArcDest(Msc m);
+
+/** Get the type for some arc.
+ *
+ */
+MscArcType MscGetCurrentArcType(struct MscTag *m);
+
+/** Get the value of some attribute for the current arc.
+ * \retval The attribute string, or NULL if unset.
+ */
+const char *MscGetCurrentArcAttrib(Msc m, MscAttribType a);
+
+/** Get the line of the input file at which the current arc was defined.
+ * \retval The line number of the input file.
+ */
+unsigned int MscGetCurrentArcInputLine(Msc m);
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MSCGEN_MSC_H */
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_null_out.c b/libmscgen/mscgen_null_out.c
new file mode 100644
index 0000000..4607c71
--- /dev/null
+++ b/libmscgen/mscgen_null_out.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+ *
+ * $Id: null_out.c 112 2010-08-18 12:59:54Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "mscgen_adraw_int.h"
+
+/***************************************************************************
+ * API Functions
+ ***************************************************************************/
+
+static unsigned int NullTextWidth(struct ADrawTag *ctx UNUSED,
+ const char *string UNUSED)
+{
+ return 0;
+}
+
+
+static int NullTextHeight(struct ADrawTag *ctx UNUSED)
+{
+ return 0;
+}
+
+
+static void NullLine(struct ADrawTag *ctx UNUSED,
+ unsigned int x1 UNUSED,
+ unsigned int y1 UNUSED,
+ unsigned int x2 UNUSED,
+ unsigned int y2 UNUSED)
+{
+}
+
+
+static void NullDottedLine(struct ADrawTag *ctx UNUSED,
+ unsigned int x1 UNUSED,
+ unsigned int y1 UNUSED,
+ unsigned int x2 UNUSED,
+ unsigned int y2 UNUSED)
+{
+}
+
+
+static void NullTextR(struct ADrawTag *ctx UNUSED,
+ unsigned int x UNUSED,
+ unsigned int y UNUSED,
+ const char *string UNUSED)
+{
+}
+
+
+static void NullTextL(struct ADrawTag *ctx UNUSED,
+ unsigned int x UNUSED,
+ unsigned int y UNUSED,
+ const char *string UNUSED)
+{
+}
+
+
+static void NullTextC(struct ADrawTag *ctx UNUSED,
+ unsigned int x UNUSED,
+ unsigned int y UNUSED,
+ const char *string UNUSED)
+{
+}
+
+
+static void NullFilledRectangle(struct ADrawTag *ctx UNUSED,
+ unsigned int x1 UNUSED,
+ unsigned int y1 UNUSED,
+ unsigned int x2 UNUSED,
+ unsigned int y2 UNUSED)
+{
+}
+
+
+static void NullFilledTriangle(struct ADrawTag *ctx UNUSED,
+ unsigned int x1 UNUSED,
+ unsigned int y1 UNUSED,
+ unsigned int x2 UNUSED,
+ unsigned int y2 UNUSED,
+ unsigned int x3 UNUSED,
+ unsigned int y3 UNUSED)
+{
+}
+
+
+static void NullArc(struct ADrawTag *ctx UNUSED,
+ unsigned int cx UNUSED,
+ unsigned int cy UNUSED,
+ unsigned int w UNUSED,
+ unsigned int h UNUSED,
+ unsigned int s UNUSED,
+ unsigned int e UNUSED)
+{
+}
+
+
+static void NullDottedArc(struct ADrawTag *ctx UNUSED,
+ unsigned int cx UNUSED,
+ unsigned int cy UNUSED,
+ unsigned int w UNUSED,
+ unsigned int h UNUSED,
+ unsigned int s UNUSED,
+ unsigned int e UNUSED)
+{
+}
+
+
+static void NullSetPen (struct ADrawTag *ctx UNUSED,
+ ADrawColour col UNUSED)
+{
+}
+
+
+static void NullSetFontSize(struct ADrawTag *ctx UNUSED,
+ ADrawFontSize size UNUSED)
+{
+}
+
+
+static Boolean NullClose(struct ADrawTag *ctx UNUSED)
+{
+ return TRUE;
+}
+
+
+Boolean NullInit(struct ADrawTag *outContext)
+{
+ /* Fill in the function pointers */
+ outContext->line = NullLine;
+ outContext->dottedLine = NullDottedLine;
+ outContext->textL = NullTextL;
+ outContext->textC = NullTextC;
+ outContext->textR = NullTextR;
+ outContext->textWidth = NullTextWidth;
+ outContext->textHeight = NullTextHeight;
+ outContext->filledRectangle = NullFilledRectangle;
+ outContext->filledTriangle = NullFilledTriangle;
+ outContext->arc = NullArc;
+ outContext->dottedArc = NullDottedArc;
+ outContext->setPen = NullSetPen;
+ outContext->setBgPen = NullSetPen;
+ outContext->setFontSize = NullSetFontSize;
+ outContext->close = NullClose;
+
+ return TRUE;
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_ps_out.c b/libmscgen/mscgen_ps_out.c
new file mode 100644
index 0000000..32f9eae
--- /dev/null
+++ b/libmscgen/mscgen_ps_out.c
@@ -0,0 +1,595 @@
+/***************************************************************************
+ *
+ * $Id: ps_out.c 186 2011-03-01 21:18:19Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#include "mscgen_config.h"
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "mscgen_adraw_int.h"
+#include "mscgen_utf8.h"
+#include "mscgen_safe.h"
+
+/***************************************************************************
+ * Manifest Constants
+ ***************************************************************************/
+
+/** Overall scaling of the Postscript output.
+ */
+#define PS_OUT_SCALE 0.7f
+
+/***************************************************************************
+ * Local types
+ ***************************************************************************/
+
+typedef struct PsContextTag
+{
+ /** Output file. */
+ FILE *of;
+
+ /** Point size of the current font. */
+ int fontPoints;
+
+ /** Current pen colour. */
+ ADrawColour penColour;
+
+ /** Background colour for the pen. */
+ ADrawColour penBgColour;
+}
+PsContext;
+
+typedef struct
+{
+ int capheight, xheight, ascender, descender;
+ int widths[256];
+}
+PsCharMetric;
+
+/** Helvetica character widths.
+ * This gives the width of each character is 1/1000ths of a point.
+ * The values are taken from the Adobe Font Metric file for Hevletica.
+ */
+static const PsCharMetric PsHelvetica =
+{
+ 718, 523, 718, -207,
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 278, 278, 355, 556, 556, 889, 667, 222,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 278, 278, 584, 584, 584, 556,
+ 1015, 667, 667, 722, 722, 667, 611, 778,
+ 722, 278, 500, 667, 556, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 278, 278, 278, 469, 556,
+ 222, 556, 556, 500, 556, 556, 278, 556,
+ 556, 222, 222, 500, 222, 833, 556, 556,
+ 556, 556, 333, 500, 278, 556, 500, 722,
+ 500, 500, 500, 334, 260, 334, 584, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 333, 556, 556, 167, 556, 556, 556,
+ 556, 191, 333, 556, 333, 333, 500, 500,
+ -1, 556, 556, 556, 278, -1, 537, 350,
+ 222, 333, 333, 556, 1000, 1000, -1, 611,
+ -1, 333, 333, 333, 333, 333, 333, 333,
+ 333, -1, 333, 333, -1, 333, 333, 333,
+ 1000, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 1000, -1, 370, -1, -1, -1, -1,
+ 556, 778, 1000, 365, -1, -1, -1, -1,
+ -1, 889, -1, -1, -1, 278, -1, -1,
+ 222, 611, 944, 611, -1, -1, -1, -1
+ }
+};
+
+/***************************************************************************
+ * Helper functions
+ ***************************************************************************/
+
+
+/** Get the context pointer from an ADraw structure.
+ */
+static PsContext *getPsCtx(struct ADrawTag *ctx)
+{
+ return (PsContext *)ctx->internal;
+}
+
+/** Get the context pointer from an ADraw structure.
+ */
+static FILE *getPsFile(struct ADrawTag *ctx)
+{
+ return getPsCtx(ctx)->of;
+}
+
+/** Given a font metric measurement, return device dependent units.
+ * Font metric data is stored as 1/1000th of a point, and therefore
+ * needs to be multiplied by the font point size and divided by
+ * 1000 to give a value in device dependent units.
+ */
+static int getSpace(struct ADrawTag *ctx, long thousanths)
+{
+ return ((thousanths * getPsCtx(ctx)->fontPoints) + 500) / 1000;
+}
+
+/** Write out a line of text, escaping special characters.
+ */
+static void writeEscaped(struct ADrawTag *ctx, const char *string)
+{
+ FILE *f = getPsFile(ctx);
+
+ while(*string != '\0')
+ {
+ unsigned int code, bytes;
+
+ switch(*string)
+ {
+ case '(': fprintf(f, "\\("); break;
+ case ')': fprintf(f, "\\)"); break;
+ default:
+ if(Utf8Decode(string, &code, &bytes))
+ {
+ fprintf(f, "\\%o", code);
+ string += bytes - 1;
+ }
+ else
+ {
+ fputc(*string, f);
+ }
+ break;
+ }
+
+ string++;
+ }
+}
+
+static void setColour(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ float r, g, b;
+
+ /* Extract RGB values */
+ r = (float)((col & 0xff0000) >> 16);
+ g = (float)((col & 0x00ff00) >> 8);
+ b = (float)((col & 0x0000ff) >> 0);
+
+ /* Normalise */
+ r /= 255.0f;
+ g /= 255.0f;
+ b /= 255.0f;
+
+ /* Generate output command */
+ fprintf(getPsFile(ctx), "%f %f %f setrgbcolor\n", r ,g ,b);
+}
+
+/***************************************************************************
+ * API Functions
+ ***************************************************************************/
+
+unsigned int PsTextWidth(struct ADrawTag *ctx,
+ const char *string)
+{
+ unsigned long width = 0;
+
+ while(*string != '\0')
+ {
+ int i = *string & 0xff;
+ unsigned long w = PsHelvetica.widths[i];
+
+ /* Ignore undefined characters */
+ width += w > 0 ? w : 0;
+
+ string++;
+ }
+
+ return getSpace(ctx, width);
+}
+
+
+int PsTextHeight(struct ADrawTag *ctx)
+{
+ return getSpace(ctx, PsHelvetica.ascender - PsHelvetica.descender);
+}
+
+
+void PsLine(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ fprintf(getPsFile(ctx),
+ "newpath %d %d moveto %d %d lineto stroke\n",
+ x1, 0-y1, x2, 0-y2);
+
+}
+
+
+void PsDottedLine(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ fprintf(getPsFile(ctx), "[2] 0 setdash\n");
+ PsLine(ctx, x1, y1, x2, y2);
+ fprintf(getPsFile(ctx), "[] 0 setdash\n");
+}
+
+
+void PsFilledRectangle(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ fprintf(getPsFile(ctx),
+ "newpath "
+ "%d %d moveto "
+ "%d %d lineto "
+ "%d %d lineto "
+ "%d %d lineto "
+ "closepath "
+ "fill\n",
+ x1, 0-y1,
+ x2, 0-y1,
+ x2, 0-y2,
+ x1, 0-y2);
+}
+
+
+void PsTextR(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ /* Push the string and get its width */
+ fprintf(getPsFile(ctx), "(");
+ writeEscaped(ctx, string);
+ fprintf(getPsFile(ctx), ") dup stringwidth\n");
+
+ /* Draw the background box */
+ setColour(ctx, context->penBgColour);
+ fprintf(getPsFile(ctx), "pop " /* Ignore y-value */
+ "dup " /* Duplicate string width */
+ "newpath "
+ "%d %d moveto " /* Bottom left of the box */
+ "0 rlineto " /* Move to bottom right of the box */
+ "0 %d rlineto " /* To top right */
+ "neg 0 rlineto " /* Back to bottom left */
+ "closepath fill\n", /* Done */
+ x, 0-y - getSpace(ctx, PsHelvetica.descender),
+ getSpace(ctx, PsHelvetica.ascender));
+
+ /* Restore pen and show the string */
+ setColour(ctx, context->penColour);
+ fprintf(getPsFile(ctx), "%d %d moveto show\n",
+ x, 0-y - getSpace(ctx, PsHelvetica.descender));
+}
+
+
+void PsTextL(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ /* Draw the background box */
+ setColour(ctx, context->penBgColour);
+ PsFilledRectangle(ctx, x, 0-y, x + 10, 0-y + 10);
+ setColour(ctx, context->penColour);
+
+ fprintf(getPsFile(ctx),
+ "%d %d moveto "
+ "(",
+ x, 0-y - getSpace(ctx, PsHelvetica.descender));
+ writeEscaped(ctx, string);
+ fprintf(getPsFile(ctx),
+ ") dup stringwidth "
+ "pop " /* Ignore y value */
+ "neg " /* Invert x value */
+ "0 "
+ "rmoveto "
+ "show\n");
+}
+
+
+void PsTextC(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ /* Push the string and get its width */
+ fprintf(getPsFile(ctx), "(");
+ writeEscaped(ctx, string);
+ fprintf(getPsFile(ctx), ") dup stringwidth\n");
+
+ /* Draw the background box */
+ setColour(ctx, context->penBgColour);
+ fprintf(getPsFile(ctx), "pop " /* Ignore y-value */
+ "dup dup " /* Duplicate string width twice */
+ "newpath "
+ "%d %d moveto " /* Starting point, centre bottom of box */
+ "2 div neg 0 rmoveto " /* Move to bottom left */
+ "0 rlineto " /* Move to bottom right of the box */
+ "0 %d rlineto " /* To top right */
+ "neg 0 rlineto " /* Back to bottom left */
+ "closepath fill\n", /* Done */
+ x, 0-y,
+ getSpace(ctx, PsHelvetica.ascender));
+
+ /* Restore pen and show the string */
+ setColour(ctx, context->penColour);
+ fprintf(getPsFile(ctx), "%d %d moveto dup stringwidth pop 2 div neg 0 rmoveto show\n",
+ x, 0-y - getSpace(ctx, PsHelvetica.descender));
+}
+
+
+void PsFilledTriangle(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2,
+ unsigned int x3,
+ unsigned int y3)
+{
+ fprintf(getPsFile(ctx),
+ "newpath "
+ "%d %d moveto "
+ "%d %d lineto "
+ "%d %d lineto "
+ "closepath "
+ "fill\n",
+ x1, 0-y1,
+ x2, 0-y2,
+ x3, 0-y3);
+}
+
+
+void PsFilledCircle(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ unsigned int r)
+{
+ fprintf(getPsFile(ctx),
+ "newpath "
+ "%d %d %d 0 360 arc "
+ "closepath "
+ "fill\n",
+ x, 0-y, r);
+}
+
+
+void PsArc(struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e)
+{
+ fprintf(getPsFile(ctx),
+ "newpath "
+ "%d %d %d %d %d %d ellipse "
+ "stroke\n",
+ cx, 0-cy, w, h, s, e);
+}
+
+
+void PsDottedArc(struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e)
+{
+ fprintf(getPsFile(ctx), "[2] 0 setdash\n");
+ PsArc(ctx, cx, cy, w, h, s, e);
+ fprintf(getPsFile(ctx), "[] 0 setdash\n");
+}
+
+
+void PsSetPen(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ assert(col != ADRAW_COL_INVALID);
+
+ /* Check if the pen colour has changed */
+ if(context->penColour != col)
+ {
+ setColour(ctx, col);
+
+ /* Store the pen colour */
+ context->penColour = col;
+ }
+}
+
+
+void PsSetBgPen(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ context->penBgColour = col;
+}
+
+
+void PsSetFontSize(struct ADrawTag *ctx,
+ ADrawFontSize size)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ switch(size)
+ {
+ case ADRAW_FONT_TINY:
+ getPsCtx(ctx)->fontPoints = 8;
+ break;
+
+ case ADRAW_FONT_SMALL:
+ getPsCtx(ctx)->fontPoints = 12;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ fprintf(context->of, "/Helvetica findfont\n");
+ fprintf(context->of, "%d scalefont\n", getPsCtx(ctx)->fontPoints);
+ fprintf(context->of, "setfont\n");
+}
+
+
+Boolean PsClose(struct ADrawTag *ctx)
+{
+ PsContext *context = getPsCtx(ctx);
+
+ /* Close the output file */
+ if(context->of != stdout)
+ {
+ fclose(context->of);
+ }
+
+ /* Free and destroy context */
+ free(context);
+ ctx->internal = NULL;
+
+ return TRUE;
+}
+
+
+
+Boolean PsInit(unsigned int w,
+ unsigned int h,
+ const char *file,
+ struct ADrawTag *outContext)
+{
+ PsContext *context;
+
+ /* Create context */
+ context = outContext->internal = malloc_s(sizeof(PsContext));
+ if(context == NULL)
+ {
+ return FALSE;
+ }
+
+ /* Open the output file */
+ if(strcmp(file, "-") == 0)
+ {
+ context->of = stdout;
+ }
+ else
+ {
+ context->of = fopen(file, "wb");
+ if(!context->of)
+ {
+ fprintf(stderr, "PsInit: Failed to open output file '%s': %s\n", file, strerror(errno));
+ return FALSE;
+ }
+ }
+
+ /* Write the header */
+ fprintf(context->of, "%%!PS-Adobe-3.0 EPSF-2.0\n"
+ "%%%%BoundingBox: 0 0 %.0f %.0f\n", w * PS_OUT_SCALE, h * PS_OUT_SCALE);
+ fprintf(context->of, "%%%%Creator: mscgen %s\n", PACKAGE_VERSION);
+ fprintf(context->of, "%%%%EndComments\n");
+
+ /* Shrink everything by 70% */
+ fprintf(context->of, "%f %f scale\n", PS_OUT_SCALE, PS_OUT_SCALE);
+
+ /* Create clipping rectangle to constrain dimensions */
+ fprintf(context->of, "0 0 moveto\n");
+ fprintf(context->of, "0 %u lineto\n", h);
+ fprintf(context->of, "%u %u lineto\n", w, h);
+ fprintf(context->of, "%u 0 lineto\n", w);
+ fprintf(context->of, "closepath\n");
+ fprintf(context->of, "clip\n");
+ fprintf(context->of, "%%PageTrailer\n");
+ fprintf(context->of, "%%Page: 1 1\n");
+
+ /* Set default font */
+ fprintf(context->of, "/Helvetica findfont\n");
+ fprintf(context->of, "10 scalefont\n");
+ fprintf(context->of, "setfont\n");
+
+ /* Get the default font size */
+ PsSetFontSize(outContext, ADRAW_FONT_SMALL);
+
+ /* Translate up by the height, y-axis will be inverted */
+ fprintf(context->of, "0 %d translate\n", h);
+
+ /* Arc drawing function */
+ fprintf(context->of, "/mtrx matrix def\n"
+ "/ellipse\n"
+ " { /endangle exch def\n"
+ " /startangle exch def\n"
+ " /ydia exch def\n"
+ " /xdia exch def\n"
+ " /y exch def\n"
+ " /x exch def\n"
+ " /savematrix mtrx currentmatrix def\n"
+ " x y translate\n"
+ " xdia 2 div ydia 2 div scale\n"
+ " 1 -1 scale\n"
+ " 0 0 1 startangle endangle arc\n"
+ " savematrix setmatrix\n"
+ "} def\n");
+
+ /* Set the current pen colours */
+ context->penColour = ADRAW_COL_BLACK;
+ context->penBgColour = ADRAW_COL_WHITE;
+
+ /* Now fill in the function pointers */
+ outContext->line = PsLine;
+ outContext->dottedLine = PsDottedLine;
+ outContext->textL = PsTextL;
+ outContext->textC = PsTextC;
+ outContext->textR = PsTextR;
+ outContext->textWidth = PsTextWidth;
+ outContext->textHeight = PsTextHeight;
+ outContext->filledRectangle = PsFilledRectangle;
+ outContext->filledTriangle = PsFilledTriangle;
+ outContext->filledCircle = PsFilledCircle;
+ outContext->arc = PsArc;
+ outContext->dottedArc = PsDottedArc;
+ outContext->setPen = PsSetPen;
+ outContext->setBgPen = PsSetBgPen;
+ outContext->setFontSize = PsSetFontSize;
+ outContext->close = PsClose;
+
+ return TRUE;
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_safe.c b/libmscgen/mscgen_safe.c
new file mode 100644
index 0000000..c657110
--- /dev/null
+++ b/libmscgen/mscgen_safe.c
@@ -0,0 +1,119 @@
+/***************************************************************************
+ *
+ * $Id: safe.c 152 2010-10-10 14:17:37Z Michael.McTernan $
+ *
+ * This file is part of timgen, a timing diagram renderer.
+ * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#define FILE_NAME SAFE
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "mscgen_config.h"
+#include "mscgen_safe.h"
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Local Variable Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Local Function Definitions
+ *****************************************************************************/
+
+static void checkNotNull(void *p, const char *message)
+{
+ if(!p)
+ {
+ fprintf(stderr, "Fatal error: %s\n", message);
+ exit(EXIT_FAILURE);
+ }
+}
+
+/*****************************************************************************
+ * Global Function Definitions
+ *****************************************************************************/
+
+void *realloc_s(void *ptr, size_t size)
+{
+ void *r = realloc(ptr, size);
+
+ checkNotNull(r, "realloc() failed");
+
+ return r;
+}
+
+void *malloc_s(size_t size)
+{
+ void *r = malloc(size);
+
+ checkNotNull(r, "malloc() failed");
+
+ return r;
+}
+
+void *zalloc_s(size_t size)
+{
+ void *r = malloc(size);
+
+ checkNotNull(r, "malloc() failed");
+ memset(r, 0, size);
+
+ return r;
+}
+
+char *strdup_s(const char *s)
+{
+ char *r = strdup(s);
+
+ checkNotNull(r, "strdup() failed");
+
+ return r;
+}
+
+const char *mscgen_getenv_s(const char *name)
+{
+ char *r = getenv(name);
+
+ if(r == NULL) r = "";
+
+ return r;
+}
+
+/*****************************************************************************
+ * Unit Test Support
+ *****************************************************************************/
+
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_safe.h b/libmscgen/mscgen_safe.h
new file mode 100644
index 0000000..894c4c8
--- /dev/null
+++ b/libmscgen/mscgen_safe.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *
+ * $Id: safe.h 152 2010-10-10 14:17:37Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#ifndef MSCGEN_SAFE_H
+#define MSCGEN_SAFE_H
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Declarations
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Function Declarations
+ *****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void *realloc_s(void *ptr, size_t size);
+void *malloc_s(size_t size);
+void *zalloc_s(size_t size);
+char *strdup_s(const char *s);
+const char *mscgen_getenv_s(const char *name);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* MSCGEN_SAFE_H */
diff --git a/libmscgen/mscgen_svg_out.c b/libmscgen/mscgen_svg_out.c
new file mode 100644
index 0000000..73378be
--- /dev/null
+++ b/libmscgen/mscgen_svg_out.c
@@ -0,0 +1,585 @@
+/***************************************************************************
+ *
+ * $Id: svg_out.c 186 2011-03-01 21:18:19Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#include "mscgen_config.h"
+#include <math.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "mscgen_adraw_int.h"
+#include "mscgen_safe.h"
+#include "mscgen_utf8.h"
+
+/***************************************************************************
+ * Local types
+ ***************************************************************************/
+
+typedef struct SvgContextTag
+{
+ /** Output file. */
+ FILE *of;
+
+ /** Current pen colour name. */
+ const char *penColName;
+
+ /** Current background pen colour name. */
+ const char *penBgColName;
+
+ int fontPoints;
+}
+SvgContext;
+
+typedef struct
+{
+ int capheight, xheight, ascender, descender;
+ int widths[256];
+}
+SvgCharMetric;
+
+/** Helvetica character widths.
+ * This gives the width of each character is 1/1000ths of a point.
+ * The values are taken from the Adobe Font Metric file for Hevletica.
+ */
+static const SvgCharMetric SvgHelvetica =
+{
+ 718, 523, 718, -207,
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 278, 278, 355, 556, 556, 889, 667, 222,
+ 333, 333, 389, 584, 278, 333, 278, 278,
+ 556, 556, 556, 556, 556, 556, 556, 556,
+ 556, 556, 278, 278, 584, 584, 584, 556,
+ 1015, 667, 667, 722, 722, 667, 611, 778,
+ 722, 278, 500, 667, 556, 833, 722, 778,
+ 667, 778, 722, 667, 611, 722, 667, 944,
+ 667, 667, 611, 278, 278, 278, 469, 556,
+ 222, 556, 556, 500, 556, 556, 278, 556,
+ 556, 222, 222, 500, 222, 833, 556, 556,
+ 556, 556, 333, 500, 278, 556, 500, 722,
+ 500, 500, 500, 334, 260, 334, 584, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 333, 556, 556, 167, 556, 556, 556,
+ 556, 191, 333, 556, 333, 333, 500, 500,
+ -1, 556, 556, 556, 278, -1, 537, 350,
+ 222, 333, 333, 556, 1000, 1000, -1, 611,
+ -1, 333, 333, 333, 333, 333, 333, 333,
+ 333, -1, 333, 333, -1, 333, 333, 333,
+ 1000, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 1000, -1, 370, -1, -1, -1, -1,
+ 556, 778, 1000, 365, -1, -1, -1, -1,
+ -1, 889, -1, -1, -1, 278, -1, -1,
+ 222, 611, 944, 611, -1, -1, -1, -1
+ }
+};
+
+/***************************************************************************
+ * Helper functions
+ ***************************************************************************/
+
+
+/** Get the context pointer from an ADraw structure.
+ */
+static SvgContext *getSvgCtx(struct ADrawTag *ctx)
+{
+ return (SvgContext *)ctx->internal;
+}
+
+/** Get the context pointer from an ADraw structure.
+ */
+static FILE *getSvgFile(struct ADrawTag *ctx)
+{
+ return getSvgCtx(ctx)->of;
+}
+
+static const char *getSvgPen(struct ADrawTag *ctx)
+{
+ return getSvgCtx(ctx)->penColName;
+}
+
+static const char *getSvgBgPen(struct ADrawTag *ctx)
+{
+ return getSvgCtx(ctx)->penBgColName;
+}
+
+/** Given a font metric measurement, return device dependent units.
+ * Font metric data is stored as 1/1000th of a point, and therefore
+ * needs to be multiplied by the font point size and divided by
+ * 1000 to give a value in device dependent units.
+ */
+static int getSpace(struct ADrawTag *ctx, long thousanths)
+{
+ return ((thousanths * getSvgCtx(ctx)->fontPoints) + 500) / 1000;
+}
+
+
+/** Compute a point on an ellipse.
+ * This computes the point on an ellipse.
+ *
+ * \param[in] cx,cy Center of the ellipse.
+ * \param[in] w,h Ellipse width and height.
+ * \param[in] a Angle in degrees.
+ * \param[in,out] x,y Pointer to be populated with result co-ordinates.
+ */
+static void arcPoint(float cx,
+ float cy,
+ float w,
+ float h,
+ float a,
+ unsigned int *x,
+ unsigned int *y)
+{
+ float rad = (float)((a * M_PI) / 180.0f);
+
+ /* Compute point, noting this is for SVG co-ordinate system */
+ *x = (unsigned int)round(cx + ((w / 2.0f) * cos(rad)));
+ *y = (unsigned int)round(cy + ((h / 2.0f) * sin(rad)));
+}
+
+
+/** Write out a line of text, escaping special characters.
+ */
+static void writeEscaped(struct ADrawTag *ctx, const char *string)
+{
+ FILE *f = getSvgFile(ctx);
+
+ while(*string != '\0')
+ {
+ unsigned int code, bytes;
+
+ switch(*string)
+ {
+ case '<': fprintf(f, "&lt;"); break;
+ case '>': fprintf(f, "&gt;"); break;
+ case '"': fprintf(f, "&quot;"); break;
+ case '&': fprintf(f, "&amp;"); break;
+ default:
+ if(Utf8Decode(string, &code, &bytes))
+ {
+ fprintf(f, "&#x%x;", code);
+ string += bytes - 1;
+ }
+ else
+ {
+ fputc(*string, f);
+ }
+ break;
+
+ }
+
+ string++;
+ }
+}
+
+
+
+static void svgRect(struct ADrawTag *ctx,
+ const char *colour,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ fprintf(getSvgFile(ctx),
+ "<polygon fill=\"%s\" points=\"%u,%u %u,%u %u,%u %u,%u\"/>\n",
+ colour,
+ x1, y1,
+ x2, y1,
+ x2, y2,
+ x1, y2);
+}
+
+static const char *svgColour(ADrawColour col)
+{
+ switch(col)
+ {
+ case ADRAW_COL_WHITE:
+ return "white";
+
+ case ADRAW_COL_BLACK:
+ return "black";
+
+ case ADRAW_COL_BLUE:
+ return "blue";
+
+ case ADRAW_COL_RED:
+ return "red";
+
+ case ADRAW_COL_GREEN:
+ return "green";
+
+ default:
+ return NULL;
+ }
+}
+
+
+/***************************************************************************
+ * API Functions
+ ***************************************************************************/
+
+unsigned int SvgTextWidth(struct ADrawTag *ctx,
+ const char *string)
+{
+ unsigned long width = 0;
+
+ while(*string != '\0')
+ {
+ int i = *string & 0xff;
+ unsigned long w = SvgHelvetica.widths[i];
+
+ /* Ignore undefined characters */
+ width += w > 0 ? w : 0;
+
+ string++;
+ }
+
+ return getSpace(ctx, width);
+}
+
+
+int SvgTextHeight(struct ADrawTag *ctx)
+{
+ return getSpace(ctx, SvgHelvetica.ascender - SvgHelvetica.descender);
+}
+
+
+void SvgLine(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ fprintf(getSvgFile(ctx),
+ "<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" stroke=\"%s\"/>\n",
+ x1, y1, x2, y2, getSvgPen(ctx));
+
+}
+
+
+void SvgDottedLine(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ fprintf(getSvgFile(ctx),
+ "<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" stroke=\"%s\" stroke-dasharray=\"2,2\"/>\n",
+ x1, y1, x2, y2, getSvgPen(ctx));
+}
+
+
+void SvgTextR(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ SvgContext *context = getSvgCtx(ctx);
+
+ svgRect(ctx, getSvgBgPen(ctx), x - 2, y - SvgTextHeight(ctx) + 1, x + SvgTextWidth(ctx, string), y - 1);
+
+ y += getSpace(ctx, SvgHelvetica.descender);
+
+ fprintf(getSvgFile(ctx),
+ "<text x=\"%u\" y=\"%u\" textLength=\"%u\" font-family=\"Helvetica\" font-size=\"%u\" fill=\"%s\">\n",
+ x - 1, y, SvgTextWidth(ctx, string), context->fontPoints, context->penColName);
+ writeEscaped(ctx, string);
+ fprintf(getSvgFile(ctx), "\n</text>\n");
+}
+
+
+void SvgTextL(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ SvgContext *context = getSvgCtx(ctx);
+
+ svgRect(ctx, getSvgBgPen(ctx), x - (SvgTextWidth(ctx, string) + 2), y - SvgTextHeight(ctx) + 1, x, y - 1);
+
+ y += getSpace(ctx, SvgHelvetica.descender);
+
+ fprintf(getSvgFile(ctx),
+ "<text x=\"%u\" y=\"%u\" textLength=\"%u\" font-family=\"Helvetica\" font-size=\"%u\" fill=\"%s\" text-anchor=\"end\">\n",
+ x, y, SvgTextWidth(ctx, string), context->fontPoints, context->penColName);
+ writeEscaped(ctx, string);
+ fprintf(getSvgFile(ctx), "\n</text>\n");
+
+
+}
+
+
+void SvgTextC(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ const char *string)
+{
+ SvgContext *context = getSvgCtx(ctx);
+ unsigned int hw = SvgTextWidth(ctx, string) / 2;
+
+ svgRect(ctx, getSvgBgPen(ctx), x - (hw + 2), y - SvgTextHeight(ctx) + 1, x + hw, y - 1);
+
+ y += getSpace(ctx, SvgHelvetica.descender);
+
+ fprintf(getSvgFile(ctx),
+ "<text x=\"%u\" y=\"%u\" textLength=\"%u\" font-family=\"Helvetica\" font-size=\"%u\" fill=\"%s\" text-anchor=\"middle\">\n\n",
+ x, y, SvgTextWidth(ctx, string), context->fontPoints, context->penColName);
+ writeEscaped(ctx, string);
+ fprintf(getSvgFile(ctx), "\n</text>\n");
+}
+
+
+void SvgFilledTriangle(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2,
+ unsigned int x3,
+ unsigned int y3)
+{
+
+ fprintf(getSvgFile(ctx),
+ "<polygon fill=\"%s\" points=\"%u,%u %u,%u %u,%u\"/>\n",
+ getSvgPen(ctx),
+ x1, y1,
+ x2, y2,
+ x3, y3);
+}
+
+
+void SvgFilledCircle(struct ADrawTag *ctx,
+ unsigned int x,
+ unsigned int y,
+ unsigned int r)
+{
+ fprintf(getSvgFile(ctx),
+ "<circle fill=\"%s\" cx=\"%u\" cy=\"%u\" r=\"%u\"/>\n",
+ getSvgPen(ctx),
+ x, y, r);
+}
+
+
+void SvgFilledRectangle(struct ADrawTag *ctx,
+ unsigned int x1,
+ unsigned int y1,
+ unsigned int x2,
+ unsigned int y2)
+{
+ svgRect(ctx, getSvgPen(ctx), x1, y1, x2, y2);
+}
+
+
+void SvgArc(struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e)
+{
+ unsigned int sx, sy, ex, ey;
+
+ /* Get start and end x,y */
+ arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)s, &sx, &sy);
+ arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)e, &ex, &ey);
+
+ fprintf(getSvgFile(ctx),
+ "<path d=\"M %u %u A%u,%u 0 0,1 %u,%u\" stroke=\"%s\" fill=\"none\"/>",
+ sx, sy, w / 2, h / 2, ex, ey, getSvgPen(ctx));
+}
+
+
+void SvgDottedArc(struct ADrawTag *ctx,
+ unsigned int cx,
+ unsigned int cy,
+ unsigned int w,
+ unsigned int h,
+ unsigned int s,
+ unsigned int e)
+{
+ unsigned int sx, sy, ex, ey;
+
+ /* Get start and end x,y */
+ arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)s, &sx, &sy);
+ arcPoint((float)cx, (float)cy, (float)w, (float)h, (float)e, &ex, &ey);
+
+
+ fprintf(getSvgFile(ctx),
+ "<path d=\"M %u %u A%u,%u 0 0,1 %u,%u\" stroke=\"%s\" fill=\"none\" stroke-dasharray=\"2,2\"/>",
+ sx, sy, w / 2, h / 2, ex, ey, getSvgPen(ctx));
+}
+
+
+void SvgSetPen(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ static char colCmd[10];
+
+ getSvgCtx(ctx)->penColName = svgColour(col);
+ if(getSvgCtx(ctx)->penColName == NULL)
+ {
+ /* Print the RGB value into the local storage */
+ sprintf(colCmd, "#%06X", col);
+
+ /* Now set the colour name to the local store */
+ getSvgCtx(ctx)->penColName = colCmd;
+ }
+}
+
+
+void SvgSetBgPen(struct ADrawTag *ctx,
+ ADrawColour col)
+{
+ static char colCmd[10];
+
+ getSvgCtx(ctx)->penBgColName = svgColour(col);
+ if(getSvgCtx(ctx)->penBgColName == NULL)
+ {
+ /* Print the RGB value into the local storage */
+ sprintf(colCmd, "#%06X", col);
+
+ /* Now set the colour name to the local store */
+ getSvgCtx(ctx)->penBgColName = colCmd;
+ }
+}
+
+
+void SvgSetFontSize(struct ADrawTag *ctx,
+ ADrawFontSize size)
+{
+ SvgContext *context = getSvgCtx(ctx);
+
+ switch(size)
+ {
+ case ADRAW_FONT_TINY:
+ context->fontPoints = 8;
+ break;
+
+ case ADRAW_FONT_SMALL:
+ context->fontPoints = 12;
+ break;
+
+ default:
+ assert(0);
+ }
+
+}
+
+
+Boolean SvgClose(struct ADrawTag *ctx)
+{
+ SvgContext *context = getSvgCtx(ctx);
+
+ /* Close the SVG */
+ fprintf(context->of, "</svg>\n");
+
+ /* Close the output file */
+ if(context->of != stdout)
+ {
+ fclose(context->of);
+ }
+
+ /* Free and destroy context */
+ free(context);
+ ctx->internal = NULL;
+
+ return TRUE;
+}
+
+
+
+Boolean SvgInit(unsigned int w,
+ unsigned int h,
+ const char *file,
+ struct ADrawTag *outContext)
+{
+ SvgContext *context;
+
+ /* Create context */
+ context = outContext->internal = malloc_s(sizeof(SvgContext));
+ if(context == NULL)
+ {
+ return FALSE;
+ }
+
+ /* Open the output file */
+ if(strcmp(file, "-") == 0)
+ {
+ context->of = stdout;
+ }
+ else
+ {
+ context->of = fopen(file, "wb");
+ if(!context->of)
+ {
+ fprintf(stderr, "SvgInit: Failed to open output file '%s': %s\n", file, strerror(errno));
+ return FALSE;
+ }
+ }
+
+ /* Set the initial pen state */
+ SvgSetPen(outContext, ADRAW_COL_BLACK);
+ SvgSetBgPen(outContext, ADRAW_COL_WHITE);
+
+ /* Default to small font */
+ SvgSetFontSize(outContext, ADRAW_FONT_SMALL);
+
+ fprintf(context->of, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
+ " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+
+ fprintf(context->of, "<svg version=\"1.1\"\n"
+ " width=\"%upx\" height=\"%upx\"\n"
+ " viewBox=\"0 0 %u %u\"\n"
+ " xmlns=\"http://www.w3.org/2000/svg\" shape-rendering=\"crispEdges\"\n"
+ " stroke-width=\"1\" text-rendering=\"geometricPrecision\">\n",
+ w, h, w, h);
+
+ /* Now fill in the function pointers */
+ outContext->line = SvgLine;
+ outContext->dottedLine = SvgDottedLine;
+ outContext->textL = SvgTextL;
+ outContext->textC = SvgTextC;
+ outContext->textR = SvgTextR;
+ outContext->textWidth = SvgTextWidth;
+ outContext->textHeight = SvgTextHeight;
+ outContext->filledRectangle = SvgFilledRectangle;
+ outContext->filledTriangle = SvgFilledTriangle;
+ outContext->filledCircle = SvgFilledCircle;
+ outContext->arc = SvgArc;
+ outContext->dottedArc = SvgDottedArc;
+ outContext->setPen = SvgSetPen;
+ outContext->setBgPen = SvgSetBgPen;
+ outContext->setFontSize = SvgSetFontSize;
+ outContext->close = SvgClose;
+
+ return TRUE;
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_usage.c b/libmscgen/mscgen_usage.c
new file mode 100644
index 0000000..2126d44
--- /dev/null
+++ b/libmscgen/mscgen_usage.c
@@ -0,0 +1,111 @@
+/***************************************************************************
+ *
+ * $Id: main.c 75 2009-07-26 14:45:59Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+/***************************************************************************
+ * Include Files
+ ***************************************************************************/
+
+#include "mscgen_config.h"
+#include <stdio.h>
+#include "mscgen_usage.h"
+
+/***************************************************************************
+ * Types
+ ***************************************************************************/
+
+/***************************************************************************
+ * Local Variables.
+ ***************************************************************************/
+
+/***************************************************************************
+ * Functions
+ ***************************************************************************/
+
+/** Print program usage and return.
+ */
+void Usage(void)
+{
+ printf(
+"Usage: mscgen -T <type> [-o <file>] [-i] <infile>\n"
+" mscgen -l\n"
+"\n"
+"Where:\n"
+" -T <type> Specifies the output file type, which maybe one of 'png', 'eps',\n"
+" 'svg' or 'ismap'\n"
+" -i <infile> The file from which to read input. If omitted or specified as\n"
+" '-', input will be read from stdin. The '-i' flag maybe\n"
+" omitted if <infile> is specified as the last option on the\n"
+" command line.\n"
+" -o <file> Write output to the named file. This option must be specified if \n"
+" input is taken from stdin, otherwise the output filename\n"
+" defaults to <infile>.<type>. This may also be specified as '-'\n"
+" to write output directly to stdout.\n"
+#ifdef USE_FREETYPE
+" -F <font> Use specified font for PNG output. This must be a font specifier\n"
+" compatbile with fontconfig (see 'fc-list'), and overrides the\n"
+" MSCGEN_FONT environment variable if also set.\n"
+#endif
+" -p Print parsed msc output (for parser debug).\n"
+" -l Display program licence and exit.\n"
+"\n"
+"Mscgen version %s, Copyright (C) 2010 Michael C McTernan,\n"
+" Michael.McTernan.2001@cs.bris.ac.uk\n"
+"Mscgen comes with ABSOLUTELY NO WARRANTY. This is free software, and you are\n"
+"welcome to redistribute it under certain conditions; type `mscgen -l' for\n"
+"details.\n"
+"\n"
+"PNG rendering by libgd, www.libgd.org\n"
+"\n",
+PACKAGE_VERSION);
+}
+
+
+/** Print program licence and return.
+ */
+void Licence(void)
+{
+ printf(
+"Mscgen, a message sequence chart renderer.\n"
+"Copyright (C) 2010 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk\n"
+"\n"
+"TTPCom Ltd., hereby disclaims all copyright interest in the program `mscgen'\n"
+"(which renders message sequence charts) written by Michael McTernan.\n"
+"\n"
+"Rob Meades of TTPCom Ltd, 1 August 2005\n"
+"Rob Meades, director of Software\n"
+"\n"
+"This program is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 2 of the License, or\n"
+"(at your option) any later version.\n"
+"\n"
+"This program is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n"
+"\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this program; if not, write to the Free Software\n"
+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\n");
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_usage.h b/libmscgen/mscgen_usage.h
new file mode 100644
index 0000000..0aab946
--- /dev/null
+++ b/libmscgen/mscgen_usage.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *
+ * $Id: safe.h 59 2009-07-18 17:31:50Z Michael.McTernan $
+ *
+ * This file is part of mscgen, a message sequence chart renderer.
+ * Copyright (C) 2005 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+#ifndef MSCGEN_USAGE_H
+#define MSCGEN_USAGE_H
+
+/*****************************************************************************
+ * Header Files
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preprocessor Macros & Constants
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Typedefs
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Variable Declarations
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Global Function Declarations
+ *****************************************************************************/
+
+void Usage(void);
+void Licence(void);
+
+#endif /* MSCGEN_USAGE_H */
diff --git a/libmscgen/mscgen_utf8.c b/libmscgen/mscgen_utf8.c
new file mode 100644
index 0000000..9614c47
--- /dev/null
+++ b/libmscgen/mscgen_utf8.c
@@ -0,0 +1,103 @@
+/***************************************************************************
+ *
+ * $Id: utf8.c 93 2009-08-24 20:57:31Z Michael.McTernan $
+ *
+ * UTF8 decode routine.
+ * Copyright (C) 2008 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ **************************************************************************/
+
+/**************************************************************************
+ * Includes
+ **************************************************************************/
+
+#include "mscgen_utf8.h"
+
+/**************************************************************************
+ * Manfest Constants
+ **************************************************************************/
+
+/**************************************************************************
+ * Macros
+ **************************************************************************/
+
+/**************************************************************************
+ * Types
+ **************************************************************************/
+
+/**************************************************************************
+ * Local Variables
+ **************************************************************************/
+
+/**************************************************************************
+ * Local Functions
+ **************************************************************************/
+
+/** Count leading ones from the MSB.
+ */
+static unsigned int clo(char c)
+{
+ unsigned int t = 0;
+
+ while((c & (0x80 >> t)) != 0 && t < 8)
+ {
+ t++;
+ }
+
+ return t;
+}
+
+/**************************************************************************
+ * Global Functions
+ **************************************************************************/
+
+Boolean Utf8Decode(const char *s, unsigned int *r, unsigned int *bytes)
+{
+ if((*s & 0x80) == 0)
+ {
+ return FALSE;
+ }
+ else
+ {
+ unsigned int t;
+
+ /* Set default return values */
+ *bytes = clo(*s);
+ *r = 0;
+
+ /* Loop through string, checking for null termination */
+ for(t = 0; t < *bytes && s[t] != '\0'; t++)
+ {
+ /* Shift up previous bits */
+ *r <<= 6;
+
+ /* Add the required bits */
+ if(t == 0)
+ {
+ *r |= s[t] & (0xff >> (*bytes + 1));
+ }
+ else
+ {
+ *r |= s[t] & 0x3f;
+ }
+ }
+
+ /* Success if no NULL was encoutered */
+ return t == *bytes;
+ }
+}
+
+/* END OF FILE */
diff --git a/libmscgen/mscgen_utf8.h b/libmscgen/mscgen_utf8.h
new file mode 100644
index 0000000..a0ea954
--- /dev/null
+++ b/libmscgen/mscgen_utf8.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *
+ * $Id: utf8.h 93 2009-08-24 20:57:31Z Michael.McTernan $
+ *
+ * UTF8 decode routine interface.
+ * Copyright (C) 2009 Michael C McTernan, Michael.McTernan.2001@cs.bris.ac.uk
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ***************************************************************************/
+
+#ifndef MSCGEN_UTF8_H
+#define MSCGEN_UTF8_H
+
+/**************************************************************************
+ * Includes
+ **************************************************************************/
+
+#include "mscgen_bool.h"
+
+/**************************************************************************
+ * Macros
+ **************************************************************************/
+
+/**************************************************************************
+ * Types
+ **************************************************************************/
+
+/**************************************************************************
+ * Prototypes
+ **************************************************************************/
+
+Boolean Utf8Decode(const char *s, unsigned int *r, unsigned int *bytes);
+
+#endif
+
+/* END OF FILE */
diff --git a/libversion/CMakeLists.txt b/libversion/CMakeLists.txt
new file mode 100644
index 0000000..1a430fd
--- /dev/null
+++ b/libversion/CMakeLists.txt
@@ -0,0 +1,27 @@
+# vim:ts=4:sw=4:expandtab:autoindent:
+
+# setup information for doxygen version handling
+set(PRE_CONFIGURE_DOXYGEN_VERSION_FILE "${CMAKE_SOURCE_DIR}/libversion/doxyversion.cpp.in")
+set(POST_CONFIGURE_DOXYGEN_VERSION_FILE "${GENERATED_SRC}/doxyversion.cpp")
+
+# setup information for git version handling
+set(PRE_CONFIGURE_GIT_VERSION_FILE "${CMAKE_SOURCE_DIR}/libversion/gitversion.cpp.in")
+set(POST_CONFIGURE_GIT_VERSION_FILE "${GENERATED_SRC}/gitversion.cpp")
+
+include(${CMAKE_SOURCE_DIR}/cmake/git_watcher.cmake)
+include(${CMAKE_SOURCE_DIR}/cmake/doxygen_version.cmake)
+
+include_directories(
+ .
+)
+
+add_library(version STATIC
+ ${POST_CONFIGURE_DOXYGEN_VERSION_FILE}
+ ${POST_CONFIGURE_GIT_VERSION_FILE}
+)
+
+add_dependencies( version check_git_repository )
+add_dependencies( version check_doxygen_version )
+
+set_source_files_properties(${POST_CONFIGURE_GIT_VERSION_FILE} PROPERTIES GENERATED 1)
+set_source_files_properties(${POST_CONFIGURE_DOXYGEN_VERSION_FILE} PROPERTIES GENERATED 1)
diff --git a/libversion/doxyversion.cpp.in b/libversion/doxyversion.cpp.in
new file mode 100644
index 0000000..11bca8d
--- /dev/null
+++ b/libversion/doxyversion.cpp.in
@@ -0,0 +1,7 @@
+#include "version.h"
+
+char *getVersion(void)
+{
+ static char versionString[] = "@DOXYGEN_VERSION@";
+ return versionString;
+}
diff --git a/libversion/gitversion.cpp.in b/libversion/gitversion.cpp.in
new file mode 100644
index 0000000..164b50b
--- /dev/null
+++ b/libversion/gitversion.cpp.in
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <version.h>
+
+/* - On some systems git is not installed or
+ * installed on a place where FindGit.cmake cannot find it
+ * - No git information is present (no .git directory)
+ * in those cases clear the gitVersionString (would have string GIT-NOTFOUND).
+ */
+char *getGitVersion(void)
+{
+ static char gitVersionString[100];
+ strcpy(gitVersionString,"@GIT_HEAD_SHA1@");
+ strcat(gitVersionString,!strcmp("@GIT_IS_DIRTY@","true")?"*":"");
+ if (!strcmp("@GIT_HEAD_SHA1@", "GIT-NOTFOUND")) gitVersionString[0] = '\0';
+ return gitVersionString;
+}
diff --git a/addon/doxywizard/version.h b/libversion/version.h
index 16bf9df..a656e74 100644
--- a/addon/doxywizard/version.h
+++ b/libversion/version.h
@@ -17,7 +17,6 @@
#ifndef VERSION_H
#define VERSION_H
-
-extern char versionString[];
-
+char *getVersion(void);
+char *getGitVersion(void);
#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 37a21ff..06e0e44 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -3,7 +3,10 @@
include_directories(
${CMAKE_SOURCE_DIR}/qtools
${CMAKE_SOURCE_DIR}/libmd5
- ${CMAKE_SOURCE_DIR}/vhdlparser/
+ ${CMAKE_SOURCE_DIR}/liblodepng
+ ${CMAKE_SOURCE_DIR}/libmscgen
+ ${CMAKE_SOURCE_DIR}/libversion
+ ${CMAKE_SOURCE_DIR}/vhdlparser
${CMAKE_SOURCE_DIR}/src
${CLANG_INCLUDEDIR}
${GENERATED_SRC}
@@ -14,7 +17,7 @@ file(MAKE_DIRECTORY ${GENERATED_SRC})
file(GLOB LANGUAGE_FILES "${CMAKE_SOURCE_DIR}/src/translator_??.h")
# instead of increasebuffer.py
-add_definitions(-DYY_BUF_SIZE=262144 -DYY_READ_BUF_SIZE=262144)
+add_definitions(-DYY_BUF_SIZE=${enlarge_lex_buffers} -DYY_READ_BUF_SIZE=${enlarge_lex_buffers})
# generate settings.h
file(GENERATE OUTPUT ${GENERATED_SRC}/settings.h
@@ -30,12 +33,6 @@ CONTENT "#ifndef SETTINGS_H
set_source_files_properties(${GENERATED_SRC}/settings.h PROPERTIES GENERATED 1)
-# generate version.cpp
-file(GENERATE OUTPUT ${GENERATED_SRC}/version.cpp
- CONTENT "char versionString[]=\"${VERSION}\";"
-)
-set_source_files_properties(${GENERATED_SRC}/version.cpp PROPERTIES GENERATED 1)
-
# configvalues.h
add_custom_command(
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/src/configgen.py -maph ${CMAKE_SOURCE_DIR}/src/config.xml > ${GENERATED_SRC}/configvalues.h
@@ -140,7 +137,6 @@ add_library(_doxygen STATIC
${GENERATED_SRC}/lang_cfg.h
${GENERATED_SRC}/settings.h
${GENERATED_SRC}/layout_default.xml.h
- ${GENERATED_SRC}/version.cpp
${GENERATED_SRC}/ce_parse.h
${GENERATED_SRC}/configvalues.h
${GENERATED_SRC}/resources.cpp
@@ -185,6 +181,16 @@ add_library(_doxygen STATIC
docparser.cpp
docsets.cpp
dot.cpp
+ dotcallgraph.cpp
+ dotclassgraph.cpp
+ dotdirdeps.cpp
+ dotfilepatcher.cpp
+ dotgfxhierarchytable.cpp
+ dotgraph.cpp
+ dotgroupcollaboration.cpp
+ dotincldepgraph.cpp
+ dotnode.cpp
+ dotrunner.cpp
doxygen.cpp
eclipsehelp.cpp
emoji.cpp
@@ -207,7 +213,6 @@ add_library(_doxygen STATIC
latexdocvisitor.cpp
latexgen.cpp
layout.cpp
- lodepng.cpp
mandocvisitor.cpp
mangen.cpp
sqlite3gen.cpp
@@ -243,6 +248,7 @@ add_library(_doxygen STATIC
xmlgen.cpp
docbookvisitor.cpp
docbookgen.cpp
+ docgroup.cpp
)
add_executable(doxygen main.cpp)
@@ -272,6 +278,9 @@ target_link_libraries(doxygen
doxycfg
qtools
md5
+ lodepng
+ mscgen
+ version
vhdlparser
${SQLITE3_LIBRARIES}
${ICONV_LIBRARIES}
diff --git a/src/classdef.cpp b/src/classdef.cpp
index 8f04505..856ab05 100644
--- a/src/classdef.cpp
+++ b/src/classdef.cpp
@@ -33,6 +33,8 @@
#include "example.h"
#include "outputlist.h"
#include "dot.h"
+#include "dotclassgraph.h"
+#include "dotrunner.h"
#include "defargs.h"
#include "debug.h"
#include "docparser.h"
@@ -1717,8 +1719,12 @@ void ClassDefImpl::writeInheritanceGraph(OutputList &ol) const
(Config_getBool(CLASS_DIAGRAMS) || Config_getBool(CLASS_GRAPH)))
// write class diagram using dot
{
- DotClassGraph inheritanceGraph(this,DotNode::Inheritance);
- if (!inheritanceGraph.isTrivial() && !inheritanceGraph.isTooBig())
+ DotClassGraph inheritanceGraph(this,Inheritance);
+ if (inheritanceGraph.isTooBig())
+ {
+ warn_uncond("Inheritance graph for '%s' not generated, too many nodes. Consider increasing DOT_GRAPH_MAX_NODES.\n",name().data());
+ }
+ else if (!inheritanceGraph.isTrivial())
{
ol.pushGeneratorState();
ol.disable(OutputGenerator::Man);
@@ -1836,7 +1842,7 @@ void ClassDefImpl::writeCollaborationGraph(OutputList &ol) const
{
if (Config_getBool(HAVE_DOT) /*&& Config_getBool(COLLABORATION_GRAPH)*/)
{
- DotClassGraph usageImplGraph(this,DotNode::Collaboration);
+ DotClassGraph usageImplGraph(this,Collaboration);
if (!usageImplGraph.isTrivial())
{
ol.pushGeneratorState();
@@ -3324,7 +3330,7 @@ void ClassDefImpl::addTypeConstraint(const QCString &typeConstraint,const QCStri
//printf("addTypeContraint(%s,%s)\n",type.data(),typeConstraint.data());
static bool hideUndocRelation = Config_getBool(HIDE_UNDOC_RELATIONS);
if (typeConstraint.isEmpty() || type.isEmpty()) return;
- ClassDef *cd = getResolvedClass(this,getFileDef(),typeConstraint);
+ ClassDef *cd = const_cast<ClassDef*>(getResolvedClass(this,getFileDef(),typeConstraint));
if (cd==0 && !hideUndocRelation)
{
cd = new ClassDefImpl(getDefFileName(),getDefLine(),getDefColumn(),typeConstraint,ClassDef::Class);
@@ -3450,7 +3456,7 @@ bool ClassDefImpl::hasNonReferenceSuperClass() const
void ClassDefImpl::writeDeclaration(OutputList &ol,const MemberDef *md,bool inGroup,
const ClassDef *inheritedFrom,const char *inheritId) const
{
- //printf("ClassName=`%s' inGroup=%d\n",name().data(),inGroup);
+ //printf("ClassName='%s' inGroup=%d\n",name().data(),inGroup);
ol.docify(compoundTypeString());
QCString cn = displayName(FALSE);
@@ -3564,8 +3570,8 @@ bool ClassDefImpl::hasDocumentation() const
//----------------------------------------------------------------------
// recursive function:
-// returns TRUE iff class definition `bcd' represents an (in)direct base
-// class of class definition `cd'.
+// returns TRUE iff class definition 'bcd' represents an (in)direct base
+// class of class definition 'cd'.
bool ClassDefImpl::isBaseClass(const ClassDef *bcd, bool followInstances,int level) const
{
@@ -3630,7 +3636,7 @@ static bool isStandardFunc(MemberDef *md)
}
/*!
- * recursively merges the `all members' lists of a class base
+ * recursively merges the 'all members' lists of a class base
* with that of this class. Must only be called for classes without
* subclasses!
*/
@@ -3775,7 +3781,7 @@ void ClassDefImpl::mergeMembers()
{
if (!isStandardFunc(srcMd))
{
- //printf(" insertMember `%s'\n",srcMd->name().data());
+ //printf(" insertMember '%s'\n",srcMd->name().data());
internalInsertMember(srcMd,prot,FALSE);
}
}
@@ -3852,7 +3858,7 @@ void ClassDefImpl::mergeMembers()
{
if (!isStandardFunc(mi->memberDef))
{
- //printf(" insertMember `%s'\n",mi->memberDef->name().data());
+ //printf(" insertMember '%s'\n",mi->memberDef->name().data());
internalInsertMember(mi->memberDef,prot,FALSE);
}
}
@@ -4113,7 +4119,7 @@ void ClassDefImpl::determineImplUsageRelation()
if (md->isVariable()) // for each member variable in this class
{
QCString type=removeRedundantWhiteSpace(md->typeString());
- //printf("in class %s found var type=`%s' name=`%s'\n",
+ //printf("in class %s found var type='%s' name='%s'\n",
// name().data(),type.data(),md->name().data());
int pos=0;
QCString usedClassName;
@@ -4121,7 +4127,7 @@ void ClassDefImpl::determineImplUsageRelation()
bool found=FALSE;
while (extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1 && !found)
{
- //printf("usedClassName=`%s' templSpec=%s\n",usedClassName.data(),templSpec.data());
+ //printf("usedClassName='%s' templSpec=%s\n",usedClassName.data(),templSpec.data());
// check if usedClassName is a template argument of its class
ClassDef *cd=md->getClassDef();
if (cd && cd->templateArguments())
@@ -4233,11 +4239,11 @@ void ClassDefImpl::addUsedInterfaceClasses(MemberDef *md,const char *typeStr)
{
ucd = new UsesClassDef(cd);
m_impl->usesIntfClassDict->insert(cd->name(),ucd);
- //printf("in class `%s' adding used intf class `%s'\n",
+ //printf("in class '%s' adding used intf class '%s'\n",
// name().data(),cd->name().data());
}
ucd->addAccessor(md->name());
- //printf("in class `%s' adding accessor `%s' to class `%s'\n",
+ //printf("in class '%s' adding accessor '%s' to class '%s'\n",
// name().data(),md->name().data(),ucd->classDef->name().data());
}
p=i+l;
@@ -4476,7 +4482,7 @@ ClassDef *ClassDefImpl::insertTemplateInstance(const QCString &fileName,
ClassDef *templateClass=m_impl->templateInstances->find(templSpec);
if (templateClass==0)
{
- Debug::print(Debug::Classes,0," New template instance class `%s'`%s'\n",qPrint(name()),qPrint(templSpec));
+ Debug::print(Debug::Classes,0," New template instance class '%s''%s'\n",qPrint(name()),qPrint(templSpec));
QCString tcname = removeRedundantWhiteSpace(localName()+templSpec);
templateClass = new ClassDefImpl(
fileName,startLine,startColumn,tcname,ClassDef::Class);
@@ -4499,7 +4505,7 @@ ClassDef *ClassDefImpl::getVariableInstance(const char *templSpec) const
ClassDef *templateClass=m_impl->variableInstances->find(templSpec);
if (templateClass==0)
{
- Debug::print(Debug::Classes,0," New template variable instance class `%s'`%s'\n",qPrint(name()),qPrint(templSpec));
+ Debug::print(Debug::Classes,0," New template variable instance class '%s' '%s'\n",qPrint(name()),qPrint(templSpec));
QCString tcname = removeRedundantWhiteSpace(name()+templSpec);
templateClass = new ClassDefImpl("<code>",1,1,tcname,
ClassDef::Class,0,0,FALSE);
diff --git a/src/cmdmapper.cpp b/src/cmdmapper.cpp
index 55f8214..b4d35d4 100644
--- a/src/cmdmapper.cpp
+++ b/src/cmdmapper.cpp
@@ -197,6 +197,8 @@ CommandMap htmlTagMap[] =
{ "blockquote", HTML_BLOCKQUOTE },
{ "strike", HTML_STRIKE },
{ "u", HTML_UNDERLINE },
+ { "ins", HTML_INS },
+ { "del", HTML_DEL },
{ "c", XML_C },
// { "code", XML_CODE }, <= ambiguous <code> is also a HTML tag
diff --git a/src/cmdmapper.h b/src/cmdmapper.h
index 8c49b3f..d670cd4 100644
--- a/src/cmdmapper.h
+++ b/src/cmdmapper.h
@@ -179,6 +179,8 @@ enum HtmlTagType
HTML_BLOCKQUOTE= 33,
HTML_STRIKE = 34,
HTML_UNDERLINE = 35,
+ HTML_INS = 36,
+ HTML_DEL = 37,
XML_CmdMask = 0x100,
diff --git a/src/code.l b/src/code.l
index ad39e0e..b932a43 100644
--- a/src/code.l
+++ b/src/code.l
@@ -139,9 +139,9 @@ struct ObjCCallCtx
QCString methodName;
QCString objectTypeOrName;
QGString comment;
- ClassDef *objectType;
- MemberDef *objectVar;
- MemberDef *method;
+ const ClassDef *objectType;
+ const MemberDef *objectVar;
+ const MemberDef *method;
QCString format;
int lexState;
int braceCount;
@@ -252,7 +252,7 @@ void VariableContext::addVariable(const QCString &type,const QCString &name)
DBG_CTX((stderr,"** addVariable trying: type='%s' name='%s' g_currentDefinition=%s\n",
ltype.data(),lname.data(),g_currentDefinition?g_currentDefinition->name().data():"<none>"));
Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
- ClassDef *varType;
+ const ClassDef *varType;
int i=0;
if (
(varType=g_codeClassSDict->find(ltype)) || // look for class definitions inside the code block
@@ -268,7 +268,7 @@ void VariableContext::addVariable(const QCString &type,const QCString &name)
QCString typeName(ltype.left(i));
ClassDef* newDef = 0;
QCString templateArgs(ltype.right(ltype.length() - i));
- if (
+ if ( !typeName.isEmpty() &&
( // look for class definitions inside the code block
(varType=g_codeClassSDict->find(typeName)) ||
// otherwise look for global class definitions
@@ -338,15 +338,15 @@ class CallContext
public:
struct Ctx
{
- Ctx() : name(g_name), type(g_type), d(0) {}
+ Ctx(QCString _name, QCString _type) : name(_name), type(_type), d(0) {}
QCString name;
QCString type;
const Definition *d;
};
- CallContext()
+ CallContext()
{
- m_defList.append(new Ctx);
+ m_defList.append(new Ctx("",""));
m_defList.setAutoDelete(TRUE);
}
virtual ~CallContext() {}
@@ -359,12 +359,12 @@ class CallContext
ctx->d=d;
}
}
- void pushScope()
+ void pushScope(QCString _name, QCString _type)
{
- m_defList.append(new Ctx);
+ m_defList.append(new Ctx(_name,_type));
DBG_CTX((stderr,"** Push call context %d\n",m_defList.count()));
}
- void popScope()
+ void popScope(QCString &_name, QCString &_type)
{
if (m_defList.count()>1)
{
@@ -372,8 +372,8 @@ class CallContext
Ctx *ctx = m_defList.getLast();
if (ctx)
{
- g_name = ctx->name;
- g_type = ctx->type;
+ _name = ctx->name;
+ _type = ctx->type;
}
m_defList.removeLast();
}
@@ -386,7 +386,7 @@ class CallContext
{
DBG_CTX((stderr,"** Clear call context\n"));
m_defList.clear();
- m_defList.append(new Ctx);
+ m_defList.append(new Ctx("",""));
}
const Definition *getScope() const
{
@@ -415,7 +415,7 @@ static void pushScope(const char *s)
g_classScope += "::";
g_classScope += s;
}
- //printf("pushScope(%s) result: `%s'\n",s,g_classScope.data());
+ //printf("pushScope(%s) result: '%s'\n",s,g_classScope.data());
}
/*! remove the top class/namespace name from the scope */
@@ -431,7 +431,7 @@ static void popScope()
{
//err("Too many end of scopes found!\n");
}
- //printf("popScope() result: `%s'\n",g_classScope.data());
+ //printf("popScope() result: '%s'\n",g_classScope.data());
}
static void setCurrentDoc(const QCString &anchor)
@@ -482,7 +482,7 @@ static void setClassScope(const QCString &name)
n = n.mid(i+2);
}
pushScope(n);
- //printf("--->New class scope `%s'\n",g_classScope.data());
+ //printf("--->New class scope '%s'\n",g_classScope.data());
}
/*! start a new line of code, inserting a line number if g_sourceFileDef
@@ -513,7 +513,7 @@ static void startCodeLine()
g_args.resize(0);
g_parmType.resize(0);
g_parmName.resize(0);
- //printf("Real scope: `%s'\n",g_realScope.data());
+ //printf("Real scope: '%s'\n",g_realScope.data());
g_bodyCurlyCount = 0;
QCString lineAnchor;
lineAnchor.sprintf("l%05d",g_yyLineNr);
@@ -567,7 +567,7 @@ static void nextCodeLine()
}
}
-/*! write a code fragment `text' that may span multiple lines, inserting
+/*! write a code fragment 'text' that may span multiple lines, inserting
* line numbers for each line.
*/
static void codifyLines(const char *text)
@@ -695,7 +695,7 @@ static void setParameterList(const MemberDef *md)
}
}
-static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
+static const ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
{
int pos=0;
QCString type = s;
@@ -704,7 +704,7 @@ static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
{
QCString clName=className+templSpec;
- ClassDef *cd=0;
+ const ClassDef *cd=0;
if (!g_classScope.isEmpty())
{
cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName);
@@ -713,7 +713,7 @@ static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
{
cd=getResolvedClass(d,g_sourceFileDef,clName);
}
- //printf("stripClass trying `%s' = %p\n",clName.data(),cd);
+ //printf("stripClass trying '%s' = %p\n",clName.data(),cd);
if (cd)
{
return cd;
@@ -768,7 +768,7 @@ static MemberDef *setCallContextForVar(const QCString &name)
DBG_CTX((stderr,"local variable?\n"));
if (mcd!=VariableContext::dummyContext)
{
- DBG_CTX((stderr,"local var `%s' mcd=%s\n",name.data(),mcd->name().data()));
+ DBG_CTX((stderr,"local var '%s' mcd=%s\n",name.data(),mcd->name().data()));
g_theCallContext.setScope(mcd);
}
}
@@ -786,7 +786,7 @@ static MemberDef *setCallContextForVar(const QCString &name)
DBG_CTX((stderr,"Found member %s\n",md->name().data()));
if (g_scopeStack.top()!=CLASSBLOCK)
{
- DBG_CTX((stderr,"class member `%s' mcd=%s\n",name.data(),mcd->name().data()));
+ DBG_CTX((stderr,"class member '%s' mcd=%s\n",name.data(),mcd->name().data()));
g_theCallContext.setScope(stripClassName(md->typeString(),md->getOuterScope()));
}
return md;
@@ -797,7 +797,7 @@ static MemberDef *setCallContextForVar(const QCString &name)
// look for a global member
if ((mn=Doxygen::functionNameSDict->find(name)))
{
- //printf("global var `%s'\n",name.data());
+ //printf("global var '%s'\n",name.data());
if (mn->count()==1) // global defined only once
{
MemberDef *md=mn->getFirst();
@@ -843,7 +843,7 @@ static void updateCallContextForSmartPointer()
MemberDef *md;
if (d && d->definitionType()==Definition::TypeClass && (md=(dynamic_cast<const ClassDef*>(d))->isSmartPointer()))
{
- ClassDef *ncd = stripClassName(md->typeString(),md->getOuterScope());
+ const ClassDef *ncd = stripClassName(md->typeString(),md->getOuterScope());
if (ncd)
{
g_theCallContext.setScope(ncd);
@@ -865,7 +865,7 @@ static bool getLinkInScope(const QCString &c, // scope
const FileDef *fd = 0;
const NamespaceDef *nd = 0;
const GroupDef *gd = 0;
- DBG_CTX((stderr,"getLinkInScope: trying `%s'::`%s' varOnly=%d\n",c.data(),m.data(),varOnly));
+ DBG_CTX((stderr,"getLinkInScope: trying '%s'::'%s' varOnly=%d\n",c.data(),m.data(),varOnly));
if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef,FALSE,g_forceTagReference) &&
(!varOnly || md->isVariable()))
{
@@ -899,7 +899,7 @@ static bool getLinkInScope(const QCString &c, // scope
{
addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(md));
}
- //printf("d->getReference()=`%s' d->getOutputBase()=`%s' name=`%s' member name=`%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data());
+ //printf("d->getReference()='%s' d->getOutputBase()='%s' name='%s' member name='%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data());
writeMultiLineCodeLink(ol,md, text ? text : memberText);
addToSearchIndex(text ? text : memberText);
@@ -961,8 +961,8 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName
{
className = substitute(className,".","::"); // for PHP namespaces
}
- ClassDef *cd=0,*lcd=0;
- MemberDef *md=0;
+ const ClassDef *cd=0,*lcd=0;
+ const MemberDef *md=0;
bool isLocal=FALSE;
//printf("generateClassOrGlobalLink(className=%s)\n",className.data());
@@ -1033,7 +1033,7 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName
anchor.sprintf("_a%d",g_anchorCount);
//printf("addExampleClass(%s,%s,%s)\n",anchor.data(),g_exampleName.data(),
// g_exampleFile.data());
- if (cd->addExample(anchor,g_exampleName,g_exampleFile))
+ if (const_cast<ClassDef*>(cd)->addExample(anchor,g_exampleName,g_exampleFile))
{
ol.writeCodeAnchor(anchor);
g_anchorCount++;
@@ -1050,7 +1050,7 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName
if (d && d->isLinkable() && md->isLinkable() &&
g_currentMemberDef && g_collectXRefs)
{
- addDocCrossReference(g_currentMemberDef,md);
+ addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(md));
}
}
}
@@ -1092,8 +1092,8 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName
}
text+=getLanguageSpecificSeparator(md->getLanguage());
text+=clName;
- md->setName(text);
- md->setLocalName(text);
+ const_cast<MemberDef*>(md)->setName(text);
+ const_cast<MemberDef*>(md)->setLocalName(text);
}
else // normal reference
{
@@ -1103,7 +1103,7 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,const char *clName
addToSearchIndex(clName);
if (g_currentMemberDef && g_collectXRefs)
{
- addDocCrossReference(g_currentMemberDef,md);
+ addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(md));
}
return;
}
@@ -1122,7 +1122,7 @@ static bool generateClassMemberLink(CodeOutputInterface &ol,MemberDef *xmd,const
// extract class definition of the return type in order to resolve
// a->b()->c() like call chains
- //printf("type=`%s' args=`%s' class=%s\n",
+ //printf("type='%s' args='%s' class=%s\n",
// xmd->typeString(),xmd->argsString(),
// xmd->getClassDef()->name().data());
@@ -1139,7 +1139,7 @@ static bool generateClassMemberLink(CodeOutputInterface &ol,MemberDef *xmd,const
}
}
- ClassDef *typeClass = stripClassName(removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
+ const ClassDef *typeClass = stripClassName(removeAnonymousScopes(xmd->typeString()),xmd->getOuterScope());
DBG_CTX((stderr,"%s -> typeName=%p\n",xmd->typeString(),typeClass));
g_theCallContext.setScope(typeClass);
@@ -1220,7 +1220,7 @@ static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName,
if (varName.isEmpty()) return;
// look for the variable in the current context
- ClassDef *vcd = g_theVarContext.findVariable(varName);
+ const ClassDef *vcd = g_theVarContext.findVariable(varName);
if (vcd)
{
if (vcd!=VariableContext::dummyContext)
@@ -1250,7 +1250,7 @@ static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName,
vcd = getResolvedClass(g_currentDefinition,g_sourceFileDef,g_classScope);
if (vcd && vcd->isLinkable())
{
- //printf("Found class %s for variable `%s'\n",g_classScope.data(),varName.data());
+ //printf("Found class %s for variable '%s'\n",g_classScope.data(),varName.data());
MemberName *vmn=Doxygen::memberNameSDict->find(varName);
if (vmn==0)
{
@@ -1261,18 +1261,18 @@ static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName,
ClassDef *jcd = getClass(vn.left(vi));
vn=vn.right(vn.length()-vi-2);
vmn=Doxygen::memberNameSDict->find(vn);
- //printf("Trying name `%s' scope=%s\n",vn.data(),scope.data());
+ //printf("Trying name '%s' scope=%s\n",vn.data(),scope.data());
if (vmn)
{
MemberNameIterator vmni(*vmn);
- MemberDef *vmd;
+ const MemberDef *vmd;
for (;(vmd=vmni.current());++vmni)
{
if (/*(vmd->isVariable() || vmd->isFunction()) && */
vmd->getClassDef()==jcd)
{
//printf("Found variable type=%s\n",vmd->typeString());
- ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope());
+ const ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope());
if (mcd && mcd->isLinkable())
{
if (generateClassMemberLink(ol,mcd,memName)) return;
@@ -1284,16 +1284,16 @@ static void generateMemberLink(CodeOutputInterface &ol,const QCString &varName,
}
if (vmn)
{
- //printf("There is a variable with name `%s'\n",varName);
+ //printf("There is a variable with name '%s'\n",varName);
MemberNameIterator vmni(*vmn);
- MemberDef *vmd;
+ const MemberDef *vmd;
for (;(vmd=vmni.current());++vmni)
{
if (/*(vmd->isVariable() || vmd->isFunction()) && */
vmd->getClassDef()==vcd)
{
//printf("Found variable type=%s\n",vmd->typeString());
- ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope());
+ const ClassDef *mcd=stripClassName(vmd->typeString(),vmd->getOuterScope());
if (mcd && mcd->isLinkable())
{
if (generateClassMemberLink(ol,mcd,memName)) return;
@@ -1513,7 +1513,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
{
ctx->objectType = stripClassName(ctx->objectVar->typeString());
//printf(" ctx->objectType=%p\n",ctx->objectType);
- if (ctx->objectType)
+ if (ctx->objectType && !ctx->methodName.isEmpty())
{
ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
//printf(" ctx->method=%p\n",ctx->method);
@@ -1525,7 +1525,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
else // local variable
{
//printf(" object is local variable\n");
- if (cd!=VariableContext::dummyContext)
+ if (cd!=VariableContext::dummyContext && !ctx->methodName.isEmpty())
{
ctx->method = cd->getMemberByName(ctx->methodName);
//printf(" class=%p method=%p\n",cd,ctx->method);
@@ -1561,7 +1561,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
writeMultiLineCodeLink(*g_code,ctx->method,pName->data());
if (g_currentMemberDef && g_collectXRefs)
{
- addDocCrossReference(g_currentMemberDef,ctx->method);
+ addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(ctx->method));
}
}
else
@@ -1594,7 +1594,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
{
ctx->objectType = ctx->objectType->categoryOf();
}
- if (ctx->objectType)
+ if (ctx->objectType && !ctx->methodName.isEmpty())
{
ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
}
@@ -1623,7 +1623,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
if (bclass->classDef->compoundType()!=ClassDef::Protocol)
{
ctx->objectType = bclass->classDef;
- if (ctx->objectType)
+ if (ctx->objectType && !ctx->methodName.isEmpty())
{
ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
}
@@ -1640,7 +1640,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
writeMultiLineCodeLink(*g_code,ctx->objectVar,pObject->data());
if (g_currentMemberDef && g_collectXRefs)
{
- addDocCrossReference(g_currentMemberDef,ctx->objectVar);
+ addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(ctx->objectVar));
}
}
else if (ctx->objectType &&
@@ -1648,12 +1648,12 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
ctx->objectType->isLinkable()
) // object is class name
{
- ClassDef *cd = ctx->objectType;
+ const ClassDef *cd = ctx->objectType;
writeMultiLineCodeLink(*g_code,cd,pObject->data());
}
else // object still needs to be resolved
{
- ClassDef *cd = getResolvedClass(g_currentDefinition,
+ const ClassDef *cd = getResolvedClass(g_currentDefinition,
g_sourceFileDef, *pObject);
if (cd && cd->isLinkable())
{
@@ -1701,7 +1701,7 @@ static void writeObjCMethodCall(ObjCCallCtx *ctx)
else
{
ctx->objectType = stripClassName(ictx->method->typeString());
- if (ctx->objectType)
+ if (ctx->objectType && !ctx->methodName.isEmpty())
{
ctx->method = ctx->objectType->getMemberByName(ctx->methodName);
}
@@ -2302,12 +2302,11 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
char *s=g_curClassBases.first();
while (s)
{
- ClassDef *bcd;
- bcd=g_codeClassSDict->find(s);
+ const ClassDef *bcd=g_codeClassSDict->find(s);
if (bcd==0) bcd=getResolvedClass(g_currentDefinition,g_sourceFileDef,s);
if (bcd && bcd!=ncd)
{
- ncd->insertBaseClass(bcd,s,Public,Normal);
+ ncd->insertBaseClass(const_cast<ClassDef*>(bcd),s,Public,Normal);
}
s=g_curClassBases.next();
}
@@ -2473,6 +2472,10 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
BEGIN(FuncCall);
}
<Body>{FLOWCONDITION}/{BN}*"(" {
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
startFontClass("keywordflow");
codifyLines(yytext);
endFontClass();
@@ -2490,6 +2493,10 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
}
}
<Body>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
startFontClass("keywordflow");
codifyLines(yytext);
endFontClass();
@@ -2504,13 +2511,17 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
endFontClass();
}
<Body>{FLOWCONDITION}/{B}* {
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
startFontClass("keywordflow");
codifyLines(yytext);
endFontClass();
}
<Body>"*"{B}*")" { // end of cast?
g_code->codify(yytext);
- g_theCallContext.popScope();
+ g_theCallContext.popScope(g_name, g_type);
g_bracketCount--;
g_parmType = g_name;
BEGIN(FuncCall);
@@ -2520,7 +2531,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_name.resize(0);g_type.resize(0);
if (*yytext==')')
{
- g_theCallContext.popScope();
+ g_theCallContext.popScope(g_name, g_type);
g_bracketCount--;
BEGIN(FuncCall);
}
@@ -2852,7 +2863,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
}
else if (*yytext=='[')
{
- g_theCallContext.pushScope();
+ g_theCallContext.pushScope(g_name, g_type);
}
g_args.resize(0);
g_parmType.resize(0);
@@ -2878,7 +2889,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
}
<ObjCMemberCall>"[" {
g_code->codify(yytext);
- g_theCallContext.pushScope();
+ g_theCallContext.pushScope(g_name, g_type);
}
<ObjCMemberCall2>{ID}":"? {
g_name+=yytext;
@@ -2900,7 +2911,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
BEGIN(ObjCMemberCall3);
}
<ObjCMemberCall2,ObjCMemberCall3>"]" {
- g_theCallContext.popScope();
+ g_theCallContext.popScope(g_name, g_type);
g_code->codify(yytext);
BEGIN(Body);
}
@@ -2990,7 +3001,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
<ObjCCall,ObjCMName,ObjCSkipStr>\n { g_currentCtx->format+=*yytext; }
<Body>"]" {
- g_theCallContext.popScope();
+ g_theCallContext.popScope(g_name, g_type);
g_code->codify(yytext);
// TODO: nested arrays like: a[b[0]->func()]->func()
g_name = g_saveName.copy();
@@ -3039,6 +3050,10 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
endFontClass();
}
<MemberCall2,FuncCall>{FLOWCONDITION}/([^a-z_A-Z0-9]) {
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
addParmType();
g_parmName=yytext;
startFontClass("keywordflow");
@@ -3093,7 +3108,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_parmType.resize(0);g_parmName.resize(0);
g_code->codify(yytext);
g_bracketCount++;
- g_theCallContext.pushScope();
+ g_theCallContext.pushScope(g_name, g_type);
if (YY_START==FuncCall && !g_insideBody)
{
g_theVarContext.pushScope();
@@ -3127,7 +3142,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_parmName.resize(0);
g_theVarContext.addVariable(g_parmType,g_parmName);
}
- g_theCallContext.popScope();
+ g_theCallContext.popScope(g_name, g_type);
g_inForEachExpression = FALSE;
//g_theCallContext.setClass(0); // commented out, otherwise a()->b() does not work for b().
g_code->codify(yytext);
@@ -3184,7 +3199,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_theVarContext.pushScope();
}
g_theVarContext.addVariable(g_parmType,g_parmName);
- //g_theCallContext.popScope();
+ //g_theCallContext.popScope(g_name, g_type);
g_parmType.resize(0);g_parmName.resize(0);
int index = g_name.findRev("::");
DBG_CTX((stderr,"g_name=%s\n",g_name.data()));
@@ -3192,7 +3207,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
{
QCString scope = g_name.left(index);
if (!g_classScope.isEmpty()) scope.prepend(g_classScope+"::");
- ClassDef *cd=getResolvedClass(Doxygen::globalScope,g_sourceFileDef,scope);
+ const ClassDef *cd=getResolvedClass(Doxygen::globalScope,g_sourceFileDef,scope);
if (cd)
{
setClassScope(cd->name());
@@ -3644,11 +3659,11 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
}
<*>"("|"[" {
g_code->codify(yytext);
- g_theCallContext.pushScope();
+ g_theCallContext.pushScope(g_name, g_type);
}
<*>")"|"]" {
g_code->codify(yytext);
- g_theCallContext.popScope();
+ g_theCallContext.popScope(g_name, g_type);
}
<*>\n {
g_yyColNr++;
diff --git a/src/commentcnv.l b/src/commentcnv.l
index 0ea5ff7..a5dd0af 100644
--- a/src/commentcnv.l
+++ b/src/commentcnv.l
@@ -266,7 +266,7 @@ void replaceComment(int offset);
else
{
g_pythonDocString = TRUE;
- g_nestingCount=0;
+ g_nestingCount=1;
g_commentStack.clear(); /* to be on the save side */
copyToOutput(yytext,(int)yyleng);
BEGIN(CComment);
@@ -281,7 +281,7 @@ void replaceComment(int offset);
else
{
copyToOutput(yytext,(int)yyleng);
- g_nestingCount=0;
+ g_nestingCount=0; // Fortran doesn't have an end comment
g_commentStack.clear(); /* to be on the save side */
BEGIN(CComment);
g_commentStack.push(new CommentCtx(g_lineNr));
@@ -298,7 +298,7 @@ void replaceComment(int offset);
if (isFixedForm && (g_col == 0))
{
copyToOutput(yytext,(int)yyleng);
- g_nestingCount=0;
+ g_nestingCount=0; // Fortran doesn't have an end comment
g_commentStack.clear(); /* to be on the safe side */
BEGIN(CComment);
g_commentStack.push(new CommentCtx(g_lineNr));
@@ -404,7 +404,7 @@ void replaceComment(int offset);
REJECT;
}
g_specialComment=(int)yyleng==3;
- g_nestingCount=0;
+ g_nestingCount=1;
g_commentStack.clear(); /* to be on the save side */
copyToOutput(yytext,(int)yyleng);
BEGIN(CComment);
@@ -418,7 +418,7 @@ void replaceComment(int offset);
else
{
copyToOutput(yytext,(int)yyleng);
- g_nestingCount=0;
+ g_nestingCount=0; // Python doesn't have an end comment for #
g_commentStack.clear(); /* to be on the save side */
BEGIN(CComment);
g_commentStack.push(new CommentCtx(g_lineNr));
@@ -433,7 +433,7 @@ void replaceComment(int offset);
{
g_vhdl = TRUE;
copyToOutput(yytext,(int)yyleng);
- g_nestingCount=0;
+ g_nestingCount=0; // VHDL doesn't have an end comment
g_commentStack.clear(); /* to be on the save side */
BEGIN(CComment);
g_commentStack.push(new CommentCtx(g_lineNr));
@@ -447,7 +447,7 @@ void replaceComment(int offset);
else
{
copyToOutput(yytext,(int)yyleng);
- g_nestingCount=0;
+ g_nestingCount=0; // Fortran doesn't have an end comment
g_commentStack.clear(); /* to be on the save side */
BEGIN(CComment);
g_commentStack.push(new CommentCtx(g_lineNr));
@@ -650,6 +650,7 @@ void replaceComment(int offset);
}
else
{
+ g_nestingCount--;
g_pythonDocString = FALSE;
copyToOutput(yytext,(int)yyleng);
BEGIN(Scan);
@@ -680,13 +681,14 @@ void replaceComment(int offset);
else
{
copyToOutput(yytext,(int)yyleng);
+ g_nestingCount--;
if (g_nestingCount<=0)
{
BEGIN(Scan);
}
else
{
- g_nestingCount--;
+ //g_nestingCount--;
delete g_commentStack.pop();
}
}
@@ -1119,7 +1121,7 @@ void convertCppComments(BufStr *inBuf,BufStr *outBuf,const char *fileName)
}
tmp += ")";
warn(g_fileName,g_lineNr,"Reached end of file while still inside a (nested) comment. "
- "Nesting level %d %s",g_nestingCount+1,tmp.data()); // add one for "normal" expected end of comment
+ "Nesting level %d %s",g_nestingCount,tmp.data());
}
g_commentStack.clear();
g_nestingCount = 0;
diff --git a/src/commentscan.h b/src/commentscan.h
index 75cd99f..7d2189f 100644
--- a/src/commentscan.h
+++ b/src/commentscan.h
@@ -85,13 +85,5 @@ bool parseCommentBlock(ParserInterface *parser,
bool &newEntryNeeded
);
-void groupEnterFile(const char *file,int line);
-void groupLeaveFile(const char *file,int line);
-void groupLeaveCompound(const char *file,int line,const char *name);
-void groupEnterCompound(const char *file,int line,const char *name);
-void openGroup(Entry *e,const char *file,int line);
-void closeGroup(Entry *,const char *file,int line,bool foundInline=FALSE);
-void initGroupInfo(Entry *e);
-
#endif
diff --git a/src/commentscan.l b/src/commentscan.l
index eb1629e..a495c5e 100644
--- a/src/commentscan.l
+++ b/src/commentscan.l
@@ -386,11 +386,6 @@ class GuardedSection
bool m_parentVisible;
};
-void openGroup(Entry *e,const char *file,int line);
-void closeGroup(Entry *e,const char *file,int line,bool foundInline=FALSE);
-void initGroupInfo(Entry *e);
-static void groupAddDocs(Entry *e);
-
/* -----------------------------------------------------------------
*
* statics
@@ -451,20 +446,11 @@ static bool g_insideParBlock;
//-----------------------------------------------------------------------------
-static QStack<Grouping> g_autoGroupStack;
-static int g_memberGroupId = DOX_NOGROUP;
-static QCString g_memberGroupHeader;
-static QCString g_memberGroupDocs;
-static QCString g_memberGroupRelates;
-static QCString g_compoundName;
-
-//-----------------------------------------------------------------------------
-
static void initParser()
{
g_sectionLabel.resize(0);
g_sectionTitle.resize(0);
- g_memberGroupHeader.resize(0);
+ Doxygen::docGroup.clearHeader();
g_insideParBlock = FALSE;
}
@@ -826,6 +812,10 @@ static inline void setOutput(OutputContext ctx)
}
else
{
+ if (!current->doc.isEmpty()) // when appending parts add a new line
+ {
+ current->doc += "\n";
+ }
pOutputString = &current->doc;
inContext = OutputDoc; // need to switch to detailed docs, see bug 631380
}
@@ -1218,12 +1208,12 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
}
<Comment>{B}*{CMD}"{" { // begin of a group
//langParser->handleGroupStartCommand(g_memberGroupHeader);
- openGroup(current,yyFileName,yyLineNr);
+ Doxygen::docGroup.open(current,yyFileName,yyLineNr);
}
<Comment>{B}*{CMD}"}" { // end of a group
//langParser->handleGroupEndCommand();
- closeGroup(current,yyFileName,yyLineNr,TRUE);
- g_memberGroupHeader.resize(0);
+ Doxygen::docGroup.close(current,yyFileName,yyLineNr,TRUE);
+ Doxygen::docGroup.clearHeader();
parseMore=TRUE;
needNewEntry = TRUE;
#if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33))
@@ -1576,7 +1566,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
yyLineNr++;
addOutput('\n');
}
-<GroupDocArg2>[^\n\*]+ { // title (stored in type)
+<GroupDocArg2>[^\n\\]+ { // title (stored in type)
current->type += yytext;
current->type = current->type.stripWhiteSpace();
}
@@ -1594,11 +1584,16 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
addOutput('\n');
BEGIN( Comment );
}
+<GroupDocArg2>. { // title (stored in type)
+ current->type += yytext;
+ current->type = current->type.stripWhiteSpace();
+ }
/* --------- handle arguments of page/mainpage command ------------------- */
<PageDocArg1>{FILE} { // first argument; page name
current->name = stripQuotes(yytext);
+ current->args = "";
BEGIN( PageDocArg2 );
}
<PageDocArg1>{LC} { yyLineNr++;
@@ -1615,17 +1610,21 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
}
<PageDocArg1>. { // ignore other stuff
}
-<PageDocArg2>.*"\n" { // second argument; page title
- yyLineNr++;
+<PageDocArg2>{DOCNL} { // second argument; page title
+ if (*yytext=='\n') yyLineNr++;
+ addOutput('\n');
+ BEGIN( Comment );
+ }
+<PageDocArg2>{CMD}[<>] {
// bug 748927
QCString tmp = yytext;
tmp = substitute(substitute(tmp,"@<","&lt;"),"@>","&gt;");
tmp = substitute(substitute(tmp,"\\<","&lt;"),"\\>","&gt;");
- current->args = tmp;
- addOutput('\n');
- BEGIN( Comment );
+ current->args += tmp;
}
-
+<PageDocArg2>. {
+ current->args += yytext;
+ }
/* --------- handle arguments of the param command ------------ */
<ParamArg1>{ID}/{B}*"," {
addOutput(yytext);
@@ -1895,17 +1894,20 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
addOutput('\n');
}
<FormatBlock>"/*" { // start of a C-comment
- g_commentCount++;
+ if (!(blockName=="code" || blockName=="verbatim")) g_commentCount++;
addOutput(yytext);
}
<FormatBlock>"*/" { // end of a C-comment
addOutput(yytext);
- g_commentCount--;
- if (g_commentCount<0 && blockName!="verbatim")
- {
- warn(yyFileName,yyLineNr,
+ if (!(blockName=="code" || blockName=="verbatim"))
+ {
+ g_commentCount--;
+ if (g_commentCount<0)
+ {
+ warn(yyFileName,yyLineNr,
"found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",blockName.data(),blockName.data());
- }
+ }
+ }
}
<FormatBlock>. {
addOutput(*yytext);
@@ -1965,6 +1967,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
addOutput(*yytext);
}
<GuardParamEnd>{B}*{DOCNL} {
+ lineCount();
g_spaceBeforeIf.resize(0);
BEGIN(Comment);
}
@@ -2119,10 +2122,10 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
<NameParam>{LC} { // line continuation
yyLineNr++;
addOutput('\n');
- g_memberGroupHeader+=' ';
+ Doxygen::docGroup.appendHeader(' ');
}
<NameParam>. { // ignore other stuff
- g_memberGroupHeader+=*yytext;
+ Doxygen::docGroup.appendHeader(*yytext);
current->name+=*yytext;
}
@@ -2298,7 +2301,7 @@ RCSTAG "$"{ID}":"[^\n$]+"$"
if (*yytext=='\n') yyLineNr++;
addOutput('\n');
setOutput(OutputDoc);
- addOutput("\\copydetails ");
+ addOutput(" \\copydetails ");
addOutput(g_copyDocArg);
addOutput("\n");
BEGIN(Comment);
@@ -2359,6 +2362,7 @@ static bool handleDefGroup(const QCString &, const QCStringList &)
{
bool stop=makeStructuralIndicator(Entry::GROUPDOC_SEC);
current->groupDocType = Entry::GROUPDOC_NORMAL;
+ setOutput(OutputBrief);
BEGIN( GroupDocArg1 );
return stop;
}
@@ -2462,6 +2466,7 @@ static bool handleMainpage(const QCString &, const QCStringList &)
{
current->name = "mainpage";
}
+ current->name = "";
BEGIN( PageDocArg2 );
return stop;
}
@@ -2540,11 +2545,11 @@ static bool handleName(const QCString &, const QCStringList &)
bool stop=makeStructuralIndicator(Entry::MEMBERGRP_SEC);
if (!stop)
{
- g_memberGroupHeader.resize(0);
+ Doxygen::docGroup.clearHeader();
BEGIN( NameParam );
- if (g_memberGroupId!=DOX_NOGROUP) // end of previous member group
+ if (!Doxygen::docGroup.isEmpty()) // end of previous member group
{
- closeGroup(current,yyFileName,yyLineNr,TRUE);
+ Doxygen::docGroup.close(current,yyFileName,yyLineNr,TRUE,true);
}
}
return stop;
@@ -2972,7 +2977,7 @@ static bool handleToc(const QCString &, const QCStringList &optList)
{
if (sscanf(opt.right(opt.length() - i - 1).data(),"%d%c",&level,&dum) != 1)
{
- warn(yyFileName,yyLineNr,"Unknown option:level specified with \\tableofcontents: `%s'", (*it).stripWhiteSpace().data());
+ warn(yyFileName,yyLineNr,"Unknown option:level specified with \\tableofcontents: '%s'", (*it).stripWhiteSpace().data());
opt = "";
}
else
@@ -3002,7 +3007,7 @@ static bool handleToc(const QCString &, const QCStringList &optList)
}
else
{
- warn(yyFileName,yyLineNr,"Unknown option specified with \\tableofcontents: `%s'", (*it).stripWhiteSpace().data());
+ warn(yyFileName,yyLineNr,"Unknown option specified with \\tableofcontents: '%s'", (*it).stripWhiteSpace().data());
}
}
}
@@ -3145,6 +3150,10 @@ bool parseCommentBlock(/* in */ ParserInterface *parser,
parseMore = FALSE;
inBody = isInbody;
outputXRef.resize(0);
+ if (!isBrief && !isAutoBriefOn && !current->doc.isEmpty())
+ { // add newline separator between detailed comment blocks
+ current->doc += '\n';
+ }
setOutput( isBrief || isAutoBriefOn ? OutputBrief : OutputDoc );
briefEndsAtDot = isAutoBriefOn;
g_condCount = 0;
@@ -3192,9 +3201,9 @@ bool parseCommentBlock(/* in */ ParserInterface *parser,
}
if (current->section==Entry::MEMBERGRP_SEC &&
- g_memberGroupId==DOX_NOGROUP) // @name section but no group started yet
+ Doxygen::docGroup.isEmpty()) // @name section but no group started yet
{
- openGroup(current,yyFileName,yyLineNr);
+ Doxygen::docGroup.open(current,yyFileName,yyLineNr,true);
}
Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\noutput=[\n"
@@ -3208,7 +3217,7 @@ bool parseCommentBlock(/* in */ ParserInterface *parser,
checkFormula();
prot = protection;
- groupAddDocs(curEntry);
+ Doxygen::docGroup.addDocs(curEntry);
newEntryNeeded = needNewEntry;
@@ -3227,185 +3236,6 @@ bool parseCommentBlock(/* in */ ParserInterface *parser,
return parseMore;
}
-//---------------------------------------------------------------------------
-
-void groupEnterFile(const char *fileName,int)
-{
- g_autoGroupStack.setAutoDelete(TRUE);
- g_autoGroupStack.clear();
- g_memberGroupId = DOX_NOGROUP;
- g_memberGroupDocs.resize(0);
- g_memberGroupRelates.resize(0);
- g_compoundName=fileName;
-}
-
-void groupLeaveFile(const char *fileName,int line)
-{
- //if (g_memberGroupId!=DOX_NOGROUP)
- //{
- // warn(fileName,line,"end of file while inside a member group\n");
- //}
- g_memberGroupId=DOX_NOGROUP;
- g_memberGroupRelates.resize(0);
- g_memberGroupDocs.resize(0);
- if (!g_autoGroupStack.isEmpty())
- {
- warn(fileName,line,"end of file while inside a group\n");
- }
-}
-
-void groupEnterCompound(const char *fileName,int line,const char *name)
-{
- if (g_memberGroupId!=DOX_NOGROUP)
- {
- warn(fileName,line,"try to put compound %s inside a member group\n",name);
- }
- g_memberGroupId=DOX_NOGROUP;
- g_memberGroupRelates.resize(0);
- g_memberGroupDocs.resize(0);
- g_compoundName = name;
- int i = g_compoundName.find('(');
- if (i!=-1)
- {
- g_compoundName=g_compoundName.left(i); // strip category (Obj-C)
- }
- if (g_compoundName.isEmpty())
- {
- g_compoundName=fileName;
- }
- //printf("groupEnterCompound(%s)\n",name);
-}
-
-void groupLeaveCompound(const char *,int,const char * /*name*/)
-{
- //printf("groupLeaveCompound(%s)\n",name);
- //if (g_memberGroupId!=DOX_NOGROUP)
- //{
- // warn(fileName,line,"end of compound %s while inside a member group\n",name);
- //}
- g_memberGroupId=DOX_NOGROUP;
- g_memberGroupRelates.resize(0);
- g_memberGroupDocs.resize(0);
- g_compoundName.resize(0);
-}
-
-static int findExistingGroup(int &groupId,const MemberGroupInfo *info)
-{
- //printf("findExistingGroup %s:%s\n",info->header.data(),info->compoundName.data());
- QIntDictIterator<MemberGroupInfo> di(Doxygen::memGrpInfoDict);
- MemberGroupInfo *mi;
- for (di.toFirst();(mi=di.current());++di)
- {
- if (g_compoundName==mi->compoundName && // same file or scope
- !mi->header.isEmpty() && // not a nameless group
- qstricmp(mi->header,info->header)==0 // same header name
- )
- {
- //printf("Found it!\n");
- return (int)di.currentKey(); // put the item in this group
- }
- }
- groupId++; // start new group
- return groupId;
-}
-
-void openGroup(Entry *e,const char *,int)
-{
- //printf("==> openGroup(name=%s,sec=%x) g_autoGroupStack=%d\n",
- // e->name.data(),e->section,g_autoGroupStack.count());
- if (e->section==Entry::GROUPDOC_SEC) // auto group
- {
- g_autoGroupStack.push(new Grouping(e->name,e->groupingPri()));
- }
- else // start of a member group
- {
- //printf(" membergroup id=%d %s\n",g_memberGroupId,g_memberGroupHeader.data());
- if (g_memberGroupId==DOX_NOGROUP) // no group started yet
- {
- static int curGroupId=0;
-
- MemberGroupInfo *info = new MemberGroupInfo;
- info->header = g_memberGroupHeader.stripWhiteSpace();
- info->compoundName = g_compoundName;
- g_memberGroupId = findExistingGroup(curGroupId,info);
- //printf(" use membergroup %d\n",g_memberGroupId);
- Doxygen::memGrpInfoDict.insert(g_memberGroupId,info);
-
- g_memberGroupRelates = e->relates;
- e->mGrpId = g_memberGroupId;
- }
- }
-}
-
-void closeGroup(Entry *e,const char *fileName,int line,bool foundInline)
-{
- //printf("==> closeGroup(name=%s,sec=%x,file=%s,line=%d) g_autoGroupStack=%d\n",
- // e->name.data(),e->section,fileName,line,g_autoGroupStack.count());
- if (g_memberGroupId!=DOX_NOGROUP) // end of member group
- {
- MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
- if (info) // known group
- {
- info->doc = g_memberGroupDocs;
- info->docFile = fileName;
- info->docLine = line;
- }
- g_memberGroupId=DOX_NOGROUP;
- g_memberGroupRelates.resize(0);
- g_memberGroupDocs.resize(0);
- if (!foundInline) e->mGrpId=DOX_NOGROUP;
- //printf("new group id=%d\n",g_memberGroupId);
- }
- else if (!g_autoGroupStack.isEmpty()) // end of auto group
- {
- Grouping *grp = g_autoGroupStack.pop();
- // see bug577005: we should not remove the last group for e
- if (!foundInline) e->groups->removeLast();
- //printf("Removing %s e=%p\n",grp->groupname.data(),e);
- delete grp;
- if (!foundInline) initGroupInfo(e);
- }
-}
-
-void initGroupInfo(Entry *e)
-{
- //printf("==> initGroup(id=%d,related=%s,e=%p)\n",g_memberGroupId,
- // g_memberGroupRelates.data(),e);
- e->mGrpId = g_memberGroupId;
- e->relates = g_memberGroupRelates;
- if (!g_autoGroupStack.isEmpty())
- {
- //printf("Appending group %s to %s: count=%d entry=%p\n",
- // g_autoGroupStack.top()->groupname.data(),
- // e->name.data(),e->groups->count(),e);
- e->groups->append(new Grouping(*g_autoGroupStack.top()));
- }
-}
-
-static void groupAddDocs(Entry *e)
-{
- if (e->section==Entry::MEMBERGRP_SEC)
- {
- g_memberGroupDocs=e->brief.stripWhiteSpace();
- e->doc = stripLeadingAndTrailingEmptyLines(e->doc,e->docLine);
- if (!g_memberGroupDocs.isEmpty() && !e->doc.isEmpty())
- {
- g_memberGroupDocs+="\n\n";
- }
- g_memberGroupDocs+=e->doc;
- MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(g_memberGroupId);
- if (info)
- {
- info->doc = g_memberGroupDocs;
- info->docFile = e->docFile;
- info->docLine = e->docLine;
- info->setRefItems(e->sli);
- }
- e->doc.resize(0);
- e->brief.resize(0);
- }
-}
-
static void handleGuard(const QCString &expr)
{
CondParser prs;
diff --git a/src/config.xml b/src/config.xml
index 0bf34a8..966072f 100644
--- a/src/config.xml
+++ b/src/config.xml
@@ -482,7 +482,7 @@ Go to the <a href="commands.html">next</a> section or return to the
<docs>
<![CDATA[
If the \c JAVADOC_BANNER tag is set to \c YES then doxygen
- will interpret a line such as "/***************" as being the
+ will interpret a line such as \verbatim /***************\endverbatim as being the
beginning of a Javadoc-style comment "banner". If set to \c NO, the
Javadoc-style will behave just like regular comments and it will
not be interpreted by doxygen.
@@ -960,8 +960,8 @@ Go to the <a href="commands.html">next</a> section or return to the
will only generate file names in lower-case letters. If set to
\c YES, upper-case letters are also allowed. This is useful if you have
classes or files whose names only differ in case and if your file system
- supports case sensitive file names. Windows and Mac users are advised to set this
- option to \c NO.
+ supports case sensitive file names. Windows (including Cygwin) ands
+ Mac users are advised to set this option to \c NO.
]]>
</docs>
</option>
@@ -3251,17 +3251,6 @@ where `loc1` and `loc2` can be relative or absolute paths or URLs.
]]>
</docs>
</option>
- <option type='string' id='MSCGEN_PATH' format='dir' defval=''>
- <docs>
-<![CDATA[
- You can define message sequence charts within doxygen comments using the \ref cmdmsc "\\msc"
- command. Doxygen will then run the <a href="http://www.mcternan.me.uk/mscgen/">mscgen tool</a>) to
- produce the chart and insert it in the documentation. The <code>MSCGEN_PATH</code> tag allows you to
- specify the directory where the \c mscgen tool resides. If left empty the tool is assumed to
- be found in the default search path.
-]]>
- </docs>
- </option>
<option type='string' id='DIA_PATH' format='dir' defval=''>
<docs>
<![CDATA[
@@ -3641,5 +3630,6 @@ remove the intermediate dot files that are used to generate the various graphs.
<option type='obsolete' id='XML_SCHEMA'/>
<option type='obsolete' id='XML_DTD'/>
<option type='obsolete' id='PERL_PATH'/>
+ <option type='obsolete' id='MSCGEN_PATH'/>
</group>
</doxygenconfig>
diff --git a/src/configgen.py b/src/configgen.py
index ca2a5d1..dbba264 100755
--- a/src/configgen.py
+++ b/src/configgen.py
@@ -717,6 +717,10 @@ def main():
print("")
print("void ConfigValues::init()")
print("{")
+ print(" static bool first = TRUE;")
+ print(" if (!first) return;")
+ print(" first = FALSE;")
+ print("")
for n in elem.childNodes:
if n.nodeType == Node.ELEMENT_NODE:
if (n.nodeName == "group"):
diff --git a/src/configimpl.l b/src/configimpl.l
index d114b4a..bcb5a8c 100644
--- a/src/configimpl.l
+++ b/src/configimpl.l
@@ -174,7 +174,7 @@ void ConfigInt::convertStrToVal()
int val = m_valueString.toInt(&ok);
if (!ok || val<m_minVal || val>m_maxVal)
{
- config_warn("argument `%s' for option %s is not a valid number in the range [%d..%d]!\n"
+ config_warn("argument '%s' for option %s is not a valid number in the range [%d..%d]!\n"
"Using the default: %d!\n",m_valueString.data(),m_name.data(),m_minVal,m_maxVal,m_value);
}
else
@@ -199,7 +199,7 @@ void ConfigBool::convertStrToVal()
}
else
{
- config_warn("argument `%s' for option %s is not a valid boolean value\n"
+ config_warn("argument '%s' for option %s is not a valid boolean value\n"
"Using the default: %s!\n",m_valueString.data(),m_name.data(),m_value?"YES":"NO");
}
}
@@ -711,7 +711,7 @@ static void readIncludeFile(const char *incName)
ConfigOption *option = config->get(cmd);
if (option==0) // oops not known
{
- config_warn("ignoring unsupported tag `%s' at line %d, file %s\n",
+ config_warn("ignoring unsupported tag '%s' at line %d, file %s\n",
cmd.data(),yyLineNr,yyFileName.data());
BEGIN(SkipInvalid);
}
@@ -754,12 +754,12 @@ static void readIncludeFile(const char *incName)
case ConfigOption::O_Obsolete:
if (config_upd)
{
- config_warn("Tag `%s' at line %d of file `%s' has become obsolete.\n"
+ config_warn("Tag '%s' at line %d of file '%s' has become obsolete.\n"
" This tag has been removed.\n", cmd.data(),yyLineNr,yyFileName.data());
}
else
{
- config_warn("Tag `%s' at line %d of file `%s' has become obsolete.\n"
+ config_warn("Tag '%s' at line %d of file '%s' has become obsolete.\n"
" To avoid this warning please remove this line from your configuration "
"file or upgrade it using \"doxygen -u\"\n", cmd.data(),yyLineNr,yyFileName.data());
}
@@ -768,12 +768,12 @@ static void readIncludeFile(const char *incName)
case ConfigOption::O_Disabled:
if (config_upd)
{
- config_warn("Tag `%s' at line %d of file `%s' belongs to an option that was not enabled at compile time.\n"
+ config_warn("Tag '%s' at line %d of file '%s' belongs to an option that was not enabled at compile time.\n"
" This tag has been removed.\n", cmd.data(),yyLineNr,yyFileName.data());
}
else
{
- config_warn("Tag `%s' at line %d of file `%s' belongs to an option that was not enabled at compile time.\n"
+ config_warn("Tag '%s' at line %d of file '%s' belongs to an option that was not enabled at compile time.\n"
" To avoid this warning please remove this line from your configuration "
"file or upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),yyLineNr,yyFileName.data());
}
@@ -787,7 +787,7 @@ static void readIncludeFile(const char *incName)
ConfigOption *option = config->get(cmd);
if (option==0) // oops not known
{
- config_warn("ignoring unsupported tag `%s' at line %d, file %s\n",
+ config_warn("ignoring unsupported tag '%s' at line %d, file %s\n",
cmd.data(),yyLineNr,yyFileName.data());
BEGIN(SkipInvalid);
}
@@ -809,18 +809,18 @@ static void readIncludeFile(const char *incName)
case ConfigOption::O_String:
case ConfigOption::O_Int:
case ConfigOption::O_Bool:
- config_warn("operator += not supported for `%s'. Ignoring line at line %d, file %s\n",
+ config_warn("operator += not supported for '%s'. Ignoring line at line %d, file %s\n",
yytext,yyLineNr,yyFileName.data());
BEGIN(SkipInvalid);
break;
case ConfigOption::O_Obsolete:
- config_warn("Tag `%s' at line %d of file %s has become obsolete.\n"
+ config_warn("Tag '%s' at line %d of file %s has become obsolete.\n"
"To avoid this warning please update your configuration "
"file using \"doxygen -u\"\n", cmd.data(),yyLineNr,yyFileName.data());
BEGIN(SkipInvalid);
break;
case ConfigOption::O_Disabled:
- config_warn("Tag `%s' at line %d of file %s belongs to an option that was not enabled at compile time.\n"
+ config_warn("Tag '%s' at line %d of file %s belongs to an option that was not enabled at compile time.\n"
"To avoid this warning please remove this line from your configuration "
"file, upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),yyLineNr,yyFileName.data());
BEGIN(SkipInvalid);
@@ -857,13 +857,13 @@ static void readIncludeFile(const char *incName)
}
}
-<Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag `%s' at line %d, file %s\n",yytext,yyLineNr,yyFileName.data()); }
+<Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag '%s' at line %d, file %s\n",yytext,yyLineNr,yyFileName.data()); }
<GetString,GetBool,SkipInvalid>\n { yyLineNr++; BEGIN(Start); }
<GetStrList>\n {
yyLineNr++;
if (!elemStr.isEmpty())
{
- //printf("elemStr1=`%s'\n",elemStr.data());
+ //printf("elemStr1='%s'\n",elemStr.data());
l->append(elemStr);
}
BEGIN(Start);
@@ -871,7 +871,7 @@ static void readIncludeFile(const char *incName)
<GetStrList>[ \t,]+ {
if (!elemStr.isEmpty())
{
- //printf("elemStr2=`%s'\n",elemStr.data());
+ //printf("elemStr2='%s'\n",elemStr.data());
l->append(elemStr);
}
elemStr.resize(0);
@@ -886,7 +886,7 @@ static void readIncludeFile(const char *incName)
<GetQuotedString>"\""|"\n" {
// we add a bogus space to signal that the string was quoted. This space will be stripped later on.
tmpString+=" ";
- //printf("Quoted String = `%s'\n",tmpString.data());
+ //printf("Quoted String = '%s'\n",tmpString.data());
if (lastState==GetString)
{
(*s)+=configStringRecode(tmpString,encoding,"UTF-8");
@@ -917,7 +917,7 @@ static void readIncludeFile(const char *incName)
else
{
*b=FALSE;
- config_warn("Invalid value `%s' for "
+ config_warn("Invalid value '%s' for "
"boolean tag in line %d, file %s; use YES or NO\n",
bs.data(),yyLineNr,yyFileName.data());
}
@@ -943,7 +943,7 @@ void ConfigImpl::writeTemplate(FTextStream &t,bool sl,bool upd)
{
t << takeStartComment() << endl;
}
- t << "# Doxyfile " << versionString << endl << endl;
+ t << "# Doxyfile " << getVersion() << endl << endl;
if (!sl)
{
t << convertToComment(m_header,"");
@@ -964,7 +964,12 @@ void ConfigImpl::writeTemplate(FTextStream &t,bool sl,bool upd)
void ConfigImpl::compareDoxyfile(FTextStream &t)
{
- t << "# Difference with default Doxyfile " << versionString << endl;
+ t << "# Difference with default Doxyfile " << getVersion();
+ if (strlen(getGitVersion()))
+ {
+ t << " (" << getGitVersion() << ")";
+ }
+ t << endl;
QListIterator<ConfigOption> it = iterator();
ConfigOption *option;
for (;(option=it.current());++it)
@@ -1003,7 +1008,7 @@ static void substEnvVarsInString(QCString &s)
//printf("substEnvVarInString(%s) start\n",s.data());
while ((i=re.match(s,p,&l))!=-1 || (i=re2.match(s,p,&l))!=-1)
{
- //printf("Found environment var s.mid(%d,%d)=`%s'\n",i+2,l-3,s.mid(i+2,l-3).data());
+ //printf("Found environment var s.mid(%d,%d)='%s'\n",i+2,l-3,s.mid(i+2,l-3).data());
QCString env=portable_getenv(s.mid(i+2,l-3));
substEnvVarsInString(env); // recursively expand variables if needed.
s = s.left(i)+env+s.right(s.length()-i-l);
@@ -1200,7 +1205,7 @@ static QCString configFileToString(const char *name)
QFileInfo fi(name);
if (!fi.exists() || !fi.isFile())
{
- config_err("file `%s' not found\n",name);
+ config_err("file '%s' not found\n",name);
return "";
}
f.setName(name);
@@ -1221,7 +1226,7 @@ static QCString configFileToString(const char *name)
}
if (!fileOpened)
{
- config_err("cannot open file `%s' for reading\n",name);
+ config_err("cannot open file '%s' for reading\n",name);
exit(1);
}
return "";
@@ -1316,7 +1321,9 @@ void Config::init()
void Config::checkAndCorrect()
{
- QCString &warnFormat = ConfigImpl_getString("WARN_FORMAT");
+ ConfigValues::instance().init();
+
+ QCString &warnFormat = Config_getString(WARN_FORMAT);
if (warnFormat.stripWhiteSpace().isEmpty())
{
warnFormat="$file:$line $text";
@@ -1338,7 +1345,7 @@ void Config::checkAndCorrect()
}
}
- QCString &manExtension = ConfigImpl_getString("MAN_EXTENSION");
+ QCString &manExtension = Config_getString(MAN_EXTENSION);
// set default man page extension if non is given by the user
if (manExtension.isEmpty())
@@ -1346,7 +1353,7 @@ void Config::checkAndCorrect()
manExtension=".3";
}
- QCString &paperType = ConfigImpl_getEnum("PAPER_TYPE");
+ QCString &paperType = Config_getEnum(PAPER_TYPE);
paperType=paperType.lower().stripWhiteSpace();
if (paperType.isEmpty() || paperType=="a4wide")
{
@@ -1359,14 +1366,14 @@ void Config::checkAndCorrect()
paperType="a4";
}
- QCString &outputLanguage=ConfigImpl_getEnum("OUTPUT_LANGUAGE");
+ QCString &outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
outputLanguage=outputLanguage.stripWhiteSpace();
if (outputLanguage.isEmpty())
{
outputLanguage = "English";
}
- QCString &htmlFileExtension=ConfigImpl_getString("HTML_FILE_EXTENSION");
+ QCString &htmlFileExtension=Config_getString(HTML_FILE_EXTENSION);
htmlFileExtension=htmlFileExtension.stripWhiteSpace();
if (htmlFileExtension.isEmpty())
{
@@ -1374,7 +1381,7 @@ void Config::checkAndCorrect()
}
// expand the relative stripFromPath values
- QStrList &stripFromPath = ConfigImpl_getList("STRIP_FROM_PATH");
+ QStrList &stripFromPath = Config_getList(STRIP_FROM_PATH);
char *sfp = stripFromPath.first();
if (sfp==0) // by default use the current path
{
@@ -1389,49 +1396,49 @@ void Config::checkAndCorrect()
}
// expand the relative stripFromPath values
- QStrList &stripFromIncPath = ConfigImpl_getList("STRIP_FROM_INC_PATH");
+ QStrList &stripFromIncPath = Config_getList(STRIP_FROM_INC_PATH);
cleanUpPaths(stripFromIncPath);
// Test to see if HTML header is valid
- QCString &headerFile = ConfigImpl_getString("HTML_HEADER");
+ QCString &headerFile = Config_getString(HTML_HEADER);
if (!headerFile.isEmpty())
{
QFileInfo fi(headerFile);
if (!fi.exists())
{
- err("tag HTML_HEADER: header file `%s' "
+ err("tag HTML_HEADER: header file '%s' "
"does not exist\n",headerFile.data());
exit(1);
}
}
// Test to see if HTML footer is valid
- QCString &footerFile = ConfigImpl_getString("HTML_FOOTER");
+ QCString &footerFile = Config_getString(HTML_FOOTER);
if (!footerFile.isEmpty())
{
QFileInfo fi(footerFile);
if (!fi.exists())
{
- err("tag HTML_FOOTER: footer file `%s' "
+ err("tag HTML_FOOTER: footer file '%s' "
"does not exist\n",footerFile.data());
exit(1);
}
}
// Test to see if MathJax code file is valid
- if (ConfigImpl_getBool("USE_MATHJAX"))
+ if (Config_getBool(USE_MATHJAX))
{
- QCString &MathJaxCodefile = ConfigImpl_getString("MATHJAX_CODEFILE");
+ QCString &MathJaxCodefile = Config_getString(MATHJAX_CODEFILE);
if (!MathJaxCodefile.isEmpty())
{
QFileInfo fi(MathJaxCodefile);
if (!fi.exists())
{
- err("tag MATHJAX_CODEFILE file `%s' "
+ err("tag MATHJAX_CODEFILE file '%s' "
"does not exist\n",MathJaxCodefile.data());
exit(1);
}
}
- QCString &path = ConfigImpl_getString("MATHJAX_RELPATH");
+ QCString &path = Config_getString(MATHJAX_RELPATH);
if (!path.isEmpty() && path.at(path.length()-1)!='/')
{
path+="/";
@@ -1440,43 +1447,43 @@ void Config::checkAndCorrect()
}
// Test to see if LaTeX header is valid
- QCString &latexHeaderFile = ConfigImpl_getString("LATEX_HEADER");
+ QCString &latexHeaderFile = Config_getString(LATEX_HEADER);
if (!latexHeaderFile.isEmpty())
{
QFileInfo fi(latexHeaderFile);
if (!fi.exists())
{
- err("tag LATEX_HEADER: header file `%s' "
+ err("tag LATEX_HEADER: header file '%s' "
"does not exist\n",latexHeaderFile.data());
exit(1);
}
}
// Test to see if LaTeX footer is valid
- QCString &latexFooterFile = ConfigImpl_getString("LATEX_FOOTER");
+ QCString &latexFooterFile = Config_getString(LATEX_FOOTER);
if (!latexFooterFile.isEmpty())
{
QFileInfo fi(latexFooterFile);
if (!fi.exists())
{
- err("tag LATEX_FOOTER: footer file `%s' "
+ err("tag LATEX_FOOTER: footer file '%s' "
"does not exist\n",latexFooterFile.data());
exit(1);
}
}
// check include path
- QStrList &includePath = ConfigImpl_getList("INCLUDE_PATH");
+ QStrList &includePath = Config_getList(INCLUDE_PATH);
char *s=includePath.first();
while (s)
{
QFileInfo fi(s);
- if (!fi.exists()) warn_uncond("tag INCLUDE_PATH: include path `%s' "
+ if (!fi.exists()) warn_uncond("tag INCLUDE_PATH: include path '%s' "
"does not exist\n",s);
s=includePath.next();
}
// check aliases
- QStrList &aliasList = ConfigImpl_getList("ALIASES");
+ QStrList &aliasList = Config_getList(ALIASES);
s=aliasList.first();
while (s)
{
@@ -1486,33 +1493,33 @@ void Config::checkAndCorrect()
alias=alias.stripWhiteSpace();
if (alias.find(re1)!=0 && alias.find(re2)!=0)
{
- err("Illegal alias format `%s'. Use \"name=value\" or \"name(n)=value\", where n is the number of arguments\n",
+ err("Illegal alias format '%s'. Use \"name=value\" or \"name(n)=value\", where n is the number of arguments\n",
alias.data());
}
s=aliasList.next();
}
// check if GENERATE_TREEVIEW and GENERATE_HTMLHELP are both enabled
- if (ConfigImpl_getBool("GENERATE_TREEVIEW") && ConfigImpl_getBool("GENERATE_HTMLHELP"))
+ if (Config_getBool(GENERATE_TREEVIEW) && Config_getBool(GENERATE_HTMLHELP))
{
err("When enabling GENERATE_HTMLHELP the tree view (GENERATE_TREEVIEW) should be disabled. I'll do it for you.\n");
- ConfigImpl_getBool("GENERATE_TREEVIEW")=FALSE;
+ Config_getBool(GENERATE_TREEVIEW)=FALSE;
}
- if (ConfigImpl_getBool("SEARCHENGINE") && ConfigImpl_getBool("GENERATE_HTMLHELP"))
+ if (Config_getBool(SEARCHENGINE) && Config_getBool(GENERATE_HTMLHELP))
{
err("When enabling GENERATE_HTMLHELP the search engine (SEARCHENGINE) should be disabled. I'll do it for you.\n");
- ConfigImpl_getBool("SEARCHENGINE")=FALSE;
+ Config_getBool(SEARCHENGINE)=FALSE;
}
// check if SEPARATE_MEMBER_PAGES and INLINE_GROUPED_CLASSES are both enabled
- if (ConfigImpl_getBool("SEPARATE_MEMBER_PAGES") && ConfigImpl_getBool("INLINE_GROUPED_CLASSES"))
+ if (Config_getBool(SEPARATE_MEMBER_PAGES) && Config_getBool(INLINE_GROUPED_CLASSES))
{
err("When enabling INLINE_GROUPED_CLASSES the SEPARATE_MEMBER_PAGES option should be disabled. I'll do it for you.\n");
- ConfigImpl_getBool("SEPARATE_MEMBER_PAGES")=FALSE;
+ Config_getBool(SEPARATE_MEMBER_PAGES)=FALSE;
}
// check dot image format
- QCString &dotImageFormat=ConfigImpl_getEnum("DOT_IMAGE_FORMAT");
+ QCString &dotImageFormat=Config_getEnum(DOT_IMAGE_FORMAT);
dotImageFormat=dotImageFormat.stripWhiteSpace();
if (dotImageFormat.isEmpty())
{
@@ -1520,11 +1527,11 @@ void Config::checkAndCorrect()
}
//else if (dotImageFormat!="gif" && dotImageFormat!="png" && dotImageFormat!="jpg")
//{
- // err("Invalid value for DOT_IMAGE_FORMAT: `%s'. Using the default.\n",dotImageFormat.data());
+ // err("Invalid value for DOT_IMAGE_FORMAT: '%s'. Using the default.\n",dotImageFormat.data());
// dotImageFormat = "png";
//}
- QCString &dotFontName=ConfigImpl_getString("DOT_FONTNAME");
+ QCString &dotFontName=Config_getString(DOT_FONTNAME);
if (dotFontName=="FreeSans" || dotFontName=="FreeSans.ttf")
{
warn_uncond("doxygen no longer ships with the FreeSans font.\n"
@@ -1534,7 +1541,7 @@ void Config::checkAndCorrect()
// check dot path
- QCString &dotPath = ConfigImpl_getString("DOT_PATH");
+ QCString &dotPath = Config_getString(DOT_PATH);
if (!dotPath.isEmpty())
{
QFileInfo fi(dotPath);
@@ -1565,32 +1572,8 @@ void Config::checkAndCorrect()
dotPath="";
}
- // check mscgen path
- QCString &mscgenPath = ConfigImpl_getString("MSCGEN_PATH");
- if (!mscgenPath.isEmpty())
- {
- QFileInfo dp(mscgenPath+"/mscgen"+portable_commandExtension());
- if (!dp.exists() || !dp.isFile())
- {
- warn_uncond("the mscgen tool could not be found at %s\n",mscgenPath.data());
- mscgenPath="";
- }
- else
- {
- mscgenPath=dp.dirPath(TRUE).utf8()+"/";
-#if defined(_WIN32) // convert slashes
- uint i=0,l=mscgenPath.length();
- for (i=0;i<l;i++) if (mscgenPath.at(i)=='/') mscgenPath.at(i)='\\';
-#endif
- }
- }
- else // make sure the string is empty but not null!
- {
- mscgenPath="";
- }
-
// check plantuml path
- QCString &plantumlJarPath = ConfigImpl_getString("PLANTUML_JAR_PATH");
+ QCString &plantumlJarPath = Config_getString(PLANTUML_JAR_PATH);
if (!plantumlJarPath.isEmpty())
{
QFileInfo pu(plantumlJarPath);
@@ -1621,7 +1604,7 @@ void Config::checkAndCorrect()
}
// check dia path
- QCString &diaPath = ConfigImpl_getString("DIA_PATH");
+ QCString &diaPath = Config_getString(DIA_PATH);
if (!diaPath.isEmpty())
{
QFileInfo dp(diaPath+"/dia"+portable_commandExtension());
@@ -1645,7 +1628,7 @@ void Config::checkAndCorrect()
}
// check input
- QStrList &inputSources=ConfigImpl_getList("INPUT");
+ QStrList &inputSources=Config_getList(INPUT);
if (inputSources.count()==0)
{
// use current dir as the default
@@ -1659,14 +1642,14 @@ void Config::checkAndCorrect()
QFileInfo fi(s);
if (!fi.exists())
{
- warn_uncond("tag INPUT: input source `%s' does not exist\n",s);
+ warn_uncond("tag INPUT: input source '%s' does not exist\n",s);
}
s=inputSources.next();
}
}
// add default file patterns if needed
- QStrList &filePatternList = ConfigImpl_getList("FILE_PATTERNS");
+ QStrList &filePatternList = Config_getList(FILE_PATTERNS);
if (filePatternList.isEmpty())
{
ConfigOption * opt = ConfigImpl::instance()->get("FILE_PATTERNS");
@@ -1677,65 +1660,65 @@ void Config::checkAndCorrect()
}
// add default pattern if needed
- QStrList &examplePatternList = ConfigImpl_getList("EXAMPLE_PATTERNS");
+ QStrList &examplePatternList = Config_getList(EXAMPLE_PATTERNS);
if (examplePatternList.isEmpty())
{
examplePatternList.append("*");
}
// if no output format is enabled, warn the user
- if (!ConfigImpl_getBool("GENERATE_HTML") &&
- !ConfigImpl_getBool("GENERATE_LATEX") &&
- !ConfigImpl_getBool("GENERATE_MAN") &&
- !ConfigImpl_getBool("GENERATE_RTF") &&
- !ConfigImpl_getBool("GENERATE_XML") &&
- !ConfigImpl_getBool("GENERATE_PERLMOD") &&
- !ConfigImpl_getBool("GENERATE_RTF") &&
- !ConfigImpl_getBool("GENERATE_DOCBOOK") &&
- !ConfigImpl_getBool("GENERATE_AUTOGEN_DEF") &&
- ConfigImpl_getString("GENERATE_TAGFILE").isEmpty()
+ if (!Config_getBool(GENERATE_HTML) &&
+ !Config_getBool(GENERATE_LATEX) &&
+ !Config_getBool(GENERATE_MAN) &&
+ !Config_getBool(GENERATE_RTF) &&
+ !Config_getBool(GENERATE_XML) &&
+ !Config_getBool(GENERATE_PERLMOD) &&
+ !Config_getBool(GENERATE_RTF) &&
+ !Config_getBool(GENERATE_DOCBOOK) &&
+ !Config_getBool(GENERATE_AUTOGEN_DEF) &&
+ Config_getString(GENERATE_TAGFILE).isEmpty()
)
{
warn_uncond("No output formats selected! Set at least one of the main GENERATE_* options to YES.\n");
}
// check HTMLHELP creation requirements
- if (!ConfigImpl_getBool("GENERATE_HTML") &&
- ConfigImpl_getBool("GENERATE_HTMLHELP"))
+ if (!Config_getBool(GENERATE_HTML) &&
+ Config_getBool(GENERATE_HTMLHELP))
{
warn_uncond("GENERATE_HTMLHELP=YES requires GENERATE_HTML=YES.\n");
}
// check QHP creation requirements
- if (ConfigImpl_getBool("GENERATE_QHP"))
+ if (Config_getBool(GENERATE_QHP))
{
- if (ConfigImpl_getString("QHP_NAMESPACE").isEmpty())
+ if (Config_getString(QHP_NAMESPACE).isEmpty())
{
err("GENERATE_QHP=YES requires QHP_NAMESPACE to be set. Using 'org.doxygen.doc' as default!.\n");
- ConfigImpl_getString("QHP_NAMESPACE")="org.doxygen.doc";
+ Config_getString(QHP_NAMESPACE)="org.doxygen.doc";
}
- if (ConfigImpl_getString("QHP_VIRTUAL_FOLDER").isEmpty())
+ if (Config_getString(QHP_VIRTUAL_FOLDER).isEmpty())
{
err("GENERATE_QHP=YES requires QHP_VIRTUAL_FOLDER to be set. Using 'doc' as default!\n");
- ConfigImpl_getString("QHP_VIRTUAL_FOLDER")="doc";
+ Config_getString(QHP_VIRTUAL_FOLDER)="doc";
}
}
- if (ConfigImpl_getBool("OPTIMIZE_OUTPUT_JAVA") && ConfigImpl_getBool("INLINE_INFO"))
+ if (Config_getBool(OPTIMIZE_OUTPUT_JAVA) && Config_getBool(INLINE_INFO))
{
// don't show inline info for Java output, since Java has no inline
// concept.
- ConfigImpl_getBool("INLINE_INFO")=FALSE;
+ Config_getBool(INLINE_INFO)=FALSE;
}
- int &depth = ConfigImpl_getInt("MAX_DOT_GRAPH_DEPTH");
+ int &depth = Config_getInt(MAX_DOT_GRAPH_DEPTH);
if (depth==0)
{
depth=1000;
}
- int &hue = ConfigImpl_getInt("HTML_COLORSTYLE_HUE");
+ int &hue = Config_getInt(HTML_COLORSTYLE_HUE);
if (hue<0)
{
hue=0;
@@ -1745,7 +1728,7 @@ void Config::checkAndCorrect()
hue=hue%360;
}
- int &sat = ConfigImpl_getInt("HTML_COLORSTYLE_SAT");
+ int &sat = Config_getInt(HTML_COLORSTYLE_SAT);
if (sat<0)
{
sat=0;
@@ -1754,7 +1737,7 @@ void Config::checkAndCorrect()
{
sat=255;
}
- int &gamma = ConfigImpl_getInt("HTML_COLORSTYLE_GAMMA");
+ int &gamma = Config_getInt(HTML_COLORSTYLE_GAMMA);
if (gamma<40)
{
gamma=40;
@@ -1764,16 +1747,16 @@ void Config::checkAndCorrect()
gamma=240;
}
- QCString mathJaxFormat = ConfigImpl_getEnum("MATHJAX_FORMAT");
+ QCString mathJaxFormat = Config_getEnum(MATHJAX_FORMAT);
if (!mathJaxFormat.isEmpty() && mathJaxFormat!="HTML-CSS" &&
mathJaxFormat!="NativeMML" && mathJaxFormat!="SVG")
{
err("Unsupported value for MATHJAX_FORMAT: Should be one of HTML-CSS, NativeMML, or SVG\n");
- ConfigImpl_getEnum("MATHJAX_FORMAT")="HTML-CSS";
+ Config_getEnum(MATHJAX_FORMAT)="HTML-CSS";
}
// add default words if needed
- QStrList &annotationFromBrief = ConfigImpl_getList("ABBREVIATE_BRIEF");
+ QStrList &annotationFromBrief = Config_getList(ABBREVIATE_BRIEF);
if (annotationFromBrief.isEmpty())
{
annotationFromBrief.append("The $name class");
@@ -1790,21 +1773,21 @@ void Config::checkAndCorrect()
}
// some default settings for vhdl
- if (ConfigImpl_getBool("OPTIMIZE_OUTPUT_VHDL") &&
- (ConfigImpl_getBool("INLINE_INHERITED_MEMB") ||
- ConfigImpl_getBool("INHERIT_DOCS") ||
- !ConfigImpl_getBool("HIDE_SCOPE_NAMES") ||
- !ConfigImpl_getBool("EXTRACT_PRIVATE") ||
- !ConfigImpl_getBool("EXTRACT_PACKAGE")
+ if (Config_getBool(OPTIMIZE_OUTPUT_VHDL) &&
+ (Config_getBool(INLINE_INHERITED_MEMB) ||
+ Config_getBool(INHERIT_DOCS) ||
+ !Config_getBool(HIDE_SCOPE_NAMES) ||
+ !Config_getBool(EXTRACT_PRIVATE) ||
+ !Config_getBool(EXTRACT_PACKAGE)
)
)
{
- bool b1 = ConfigImpl_getBool("INLINE_INHERITED_MEMB");
- bool b2 = ConfigImpl_getBool("INHERIT_DOCS");
- bool b3 = ConfigImpl_getBool("HIDE_SCOPE_NAMES");
- bool b4 = ConfigImpl_getBool("EXTRACT_PRIVATE");
- bool b5 = ConfigImpl_getBool("SKIP_FUNCTION_MACROS");
- bool b6 = ConfigImpl_getBool("EXTRACT_PACKAGE");
+ bool b1 = Config_getBool(INLINE_INHERITED_MEMB);
+ bool b2 = Config_getBool(INHERIT_DOCS);
+ bool b3 = Config_getBool(HIDE_SCOPE_NAMES);
+ bool b4 = Config_getBool(EXTRACT_PRIVATE);
+ bool b5 = Config_getBool(SKIP_FUNCTION_MACROS);
+ bool b6 = Config_getBool(EXTRACT_PACKAGE);
const char *s1,*s2,*s3,*s4,*s5,*s6;
if (b1) s1=" INLINE_INHERITED_MEMB = NO (was YES)\n"; else s1="";
if (b2) s2=" INHERIT_DOCS = NO (was YES)\n"; else s2="";
@@ -1818,15 +1801,15 @@ void Config::checkAndCorrect()
"%s%s%s%s%s%s",s1,s2,s3,s4,s5,s6
);
- ConfigImpl_getBool("INLINE_INHERITED_MEMB") = FALSE;
- ConfigImpl_getBool("INHERIT_DOCS") = FALSE;
- ConfigImpl_getBool("HIDE_SCOPE_NAMES") = TRUE;
- ConfigImpl_getBool("EXTRACT_PRIVATE") = TRUE;
- ConfigImpl_getBool("ENABLE_PREPROCESSING") = FALSE;
- ConfigImpl_getBool("EXTRACT_PACKAGE") = TRUE;
+ Config_getBool(INLINE_INHERITED_MEMB) = FALSE;
+ Config_getBool(INHERIT_DOCS) = FALSE;
+ Config_getBool(HIDE_SCOPE_NAMES) = TRUE;
+ Config_getBool(EXTRACT_PRIVATE) = TRUE;
+ Config_getBool(ENABLE_PREPROCESSING) = FALSE;
+ Config_getBool(EXTRACT_PACKAGE) = TRUE;
}
- checkFileName(ConfigImpl_getString("GENERATE_TAGFILE"),"GENERATE_TAGFILE");
+ checkFileName(Config_getString(GENERATE_TAGFILE),"GENERATE_TAGFILE");
#if 0 // TODO: this breaks test 25; SOURCEBROWSER = NO and SOURCE_TOOLTIPS = YES.
// So this and other regressions should be analysed and fixed before this can be enabled
@@ -1852,7 +1835,6 @@ void Config::checkAndCorrect()
}
#endif
- ConfigValues::instance().init();
}
@@ -1882,10 +1864,10 @@ void Config::postProcess(bool clearHeaderAndFooter, bool compare)
// refers to the files that we are supposed to parse.
if (clearHeaderAndFooter)
{
- ConfigImpl_getString("HTML_HEADER")="";
- ConfigImpl_getString("HTML_FOOTER")="";
- ConfigImpl_getString("LATEX_HEADER")="";
- ConfigImpl_getString("LATEX_FOOTER")="";
+ Config_getString(HTML_HEADER)="";
+ Config_getString(HTML_FOOTER)="";
+ Config_getString(LATEX_HEADER)="";
+ Config_getString(LATEX_FOOTER)="";
}
}
diff --git a/src/constexp.l b/src/constexp.l
index bd42104..c9b984a 100644
--- a/src/constexp.l
+++ b/src/constexp.l
@@ -124,7 +124,7 @@ bool parseconstexp(const char *fileName,int lineNr,const QCString &s)
constexpYYrestart( yyin, yyscanner );
printlex(yy_flex_debug, TRUE, __FILE__, fileName);
- //printf("Expression: `%s'\n",s.data());
+ //printf("Expression: '%s'\n",s.data());
constexpYYparse(yyscanner);
diff --git a/src/context.cpp b/src/context.cpp
index 26a5b0e..49c9afa 100644
--- a/src/context.cpp
+++ b/src/context.cpp
@@ -39,6 +39,12 @@
#include "latexgen.h"
#include "latexdocvisitor.h"
#include "dot.h"
+#include "dotcallgraph.h"
+#include "dotclassgraph.h"
+#include "dotdirdeps.h"
+#include "dotgfxhierarchytable.h"
+#include "dotgroupcollaboration.h"
+#include "dotincldepgraph.h"
#include "diagram.h"
#include "example.h"
#include "membername.h"
@@ -374,7 +380,7 @@ class DoxygenContext::Private
public:
TemplateVariant version() const
{
- return versionString;
+ return getVersion();
}
TemplateVariant date() const
{
@@ -1926,7 +1932,7 @@ class ClassContext::Private : public DefinitionContext<ClassContext::Private>
Cachable &cache = getCache();
if (!cache.classGraph)
{
- cache.classGraph.reset(new DotClassGraph(m_classDef,DotNode::Inheritance));
+ cache.classGraph.reset(new DotClassGraph(m_classDef,Inheritance));
}
return cache.classGraph.get();
}
@@ -2048,7 +2054,7 @@ class ClassContext::Private : public DefinitionContext<ClassContext::Private>
Cachable &cache = getCache();
if (!cache.collaborationGraph)
{
- cache.collaborationGraph.reset(new DotClassGraph(m_classDef,DotNode::Collaboration));
+ cache.collaborationGraph.reset(new DotClassGraph(m_classDef,Collaboration));
}
return cache.collaborationGraph.get();
}
diff --git a/src/declinfo.h b/src/declinfo.h
index d226c7d..2039dca 100644
--- a/src/declinfo.h
+++ b/src/declinfo.h
@@ -20,9 +20,10 @@
#include <stdio.h>
#include <qcstring.h>
+#include "types.h"
extern void parseFuncDecl(const QCString &decl,
- bool objC,
+ const SrcLangExt lang,
QCString &clName,
QCString &type,
QCString &name,
diff --git a/src/declinfo.l b/src/declinfo.l
index d7f8743..36ef94a 100644
--- a/src/declinfo.l
+++ b/src/declinfo.l
@@ -34,6 +34,7 @@
#include "declinfo.h"
#include "util.h"
#include "message.h"
+#include "types.h"
#define YY_NO_INPUT 1
#define YY_NO_UNISTD_H 1
@@ -59,6 +60,7 @@ struct declinfoYY_state
bool funcTempListFound;
QCString exceptionString;
bool insideObjC;
+ bool insidePHP;
};
static void addType(yyscan_t yyscanner);
@@ -100,13 +102,21 @@ ID "$"?([a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*)|(@[0-9]+)
yyextra->name += yytext;
}
}
+<Start>([~!]{B}*)?{ID}{B}*"["{B}*"]" { // PHP
+ if (!yyextra->insidePHP)
+ {
+ REJECT;
+ }
+ addTypeName(yyscanner);
+ yyextra->name += removeRedundantWhiteSpace(yytext);
+ }
<Start>([~!]{B}*)?{ID}/({B}*"["{B}*"]")* { // the []'s are for Java,
// the / was add to deal with multi-
// dimensional C++ arrays like A[][15]
// the leading ~ is for a destructor
// the leading ! is for a C++/CLI finalizer (see bug 456475 and 635198)
addTypeName(yyscanner);
- yyextra->name += yytext;
+ yyextra->name += removeRedundantWhiteSpace(yytext);
}
<Start>{B}*"::"{B}* { // found a yyextra->scope specifier
if (!yyextra->scope.isEmpty())
@@ -198,7 +208,7 @@ ID "$"?([a-z_A-Z\x80-\xFF][a-z_A-Z0-9\x80-\xFF]*)|(@[0-9]+)
static void addType(yyscan_t yyscanner)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
- //printf("addType() yyextra->type=`%s' yyextra->scope=`%s' yyextra->name=`%s'\n",
+ //printf("addType() yyextra->type='%s' yyextra->scope='%s' yyextra->name='%s'\n",
// yyextra->type.data(),yyextra->scope.data(),yyextra->name.data());
if (yyextra->name.isEmpty() && yyextra->scope.isEmpty()) return;
if (!yyextra->type.isEmpty()) yyextra->type+=" ";
@@ -211,7 +221,7 @@ static void addType(yyscan_t yyscanner)
static void addTypeName(yyscan_t yyscanner)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
- //printf("addTypeName() yyextra->type=`%s' yyextra->scope=`%s' yyextra->name=`%s'\n",
+ //printf("addTypeName() yyextra->type='%s' yyextra->scope='%s' yyextra->name='%s'\n",
// yyextra->type.data(),yyextra->scope.data(),yyextra->name.data());
if (yyextra->name.isEmpty() ||
yyextra->name.at(yyextra->name.length()-1)==':') // end of Objective-C keyword => append to yyextra->name not yyextra->type
@@ -240,7 +250,7 @@ static int yyread(char *buf,int max_size, yyscan_t yyscanner)
static yyscan_t g_yyscanner;
static struct declinfoYY_state g_declinfo_extra;
-void parseFuncDecl(const QCString &decl,bool objC,QCString &cl,QCString &t,
+void parseFuncDecl(const QCString &decl,const SrcLangExt lang,QCString &cl,QCString &t,
QCString &n,QCString &a,QCString &ftl,QCString &exc)
{
if (decl.isEmpty())
@@ -256,11 +266,12 @@ void parseFuncDecl(const QCString &decl,bool objC,QCString &cl,QCString &t,
printlex(yy_flex_debug, TRUE, __FILE__, NULL);
yyextra->inputString = decl;
- //printf("Input=`%s'\n",yyextra->inputString);
+ //printf("Input='%s'\n",yyextra->inputString);
yyextra->inputPosition = 0;
yyextra->classTempListFound = FALSE;
yyextra->funcTempListFound = FALSE;
- yyextra->insideObjC = objC;
+ yyextra->insideObjC = lang==SrcLangExt_ObjC;
+ yyextra->insidePHP = lang==SrcLangExt_PHP;
yyextra->scope.resize(0);
yyextra->className.resize(0);
yyextra->classTempList.resize(0);
@@ -274,7 +285,7 @@ void parseFuncDecl(const QCString &decl,bool objC,QCString &cl,QCString &t,
BEGIN( Start );
declinfoYYlex(g_yyscanner);
- //printf("yyextra->type=`%s' class=`%s' yyextra->name=`%s' yyextra->args=`%s'\n",
+ //printf("yyextra->type='%s' class='%s' yyextra->name='%s' yyextra->args='%s'\n",
// yyextra->type.data(),yyextra->scope.data(),yyextra->name.data(),yyextra->args.data());
int nb = yyextra->name.findRev('[');
@@ -327,7 +338,7 @@ void parseFuncDecl(const QCString &decl,bool objC,QCString &cl,QCString &t,
a.prepend(")");
t=t.left(t.length()-1);
}
- //printf("yyextra->type=`%s' class=`%s' yyextra->name=`%s' yyextra->args=`%s'\n",
+ //printf("yyextra->type='%s' class='%s' yyextra->name='%s' yyextra->args='%s'\n",
// t.data(),cl.data(),n.data(),a.data());
printlex(yy_flex_debug, FALSE, __FILE__, NULL);
@@ -351,8 +362,8 @@ void dumpDecl(const char *s)
QCString funcTNames;
msg("-----------------------------------------\n");
parseFuncDecl(s,yyextra->className,classTNames,yyextra->type,yyextra->name,yyextra->args,funcTNames);
- msg("yyextra->type=`%s' class=`%s' classTempl=`%s' yyextra->name=`%s' "
- "funcTemplateNames=`%s' yyextra->args=`%s'\n",
+ msg("yyextra->type='%s' class='%s' classTempl='%s' yyextra->name='%s' "
+ "funcTemplateNames='%s' yyextra->args='%s'\n",
yyextra->type.data(),yyextra->className.data(),classTNames.data(),
yyextra->name.data(),funcTNames.data(),yyextra->args.data()
);
diff --git a/src/defargs.l b/src/defargs.l
index e49ef2e..85878c1 100644
--- a/src/defargs.l
+++ b/src/defargs.l
@@ -367,7 +367,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
{
g_curArgTypeName=removeRedundantWhiteSpace(g_curArgTypeName);
g_curArgDefValue=g_curArgDefValue.stripWhiteSpace();
- //printf("curArgType=`%s' curArgDefVal=`%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data());
+ //printf("curArgType='%s' curArgDefVal='%s'\n",g_curArgTypeName.data(),g_curArgDefValue.data());
int l=g_curArgTypeName.length();
if (l>0)
{
@@ -447,7 +447,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
a->defval = g_curArgDefValue.copy();
//printf("a->type=%s a->name=%s a->defval=\"%s\"\n",a->type.data(),a->name.data(),a->defval.data());
a->docs = g_curArgDocs.stripWhiteSpace();
- //printf("Argument `%s' `%s' adding docs=`%s'\n",a->type.data(),a->name.data(),a->docs.data());
+ //printf("Argument '%s' '%s' adding docs='%s'\n",a->type.data(),a->name.data(),a->docs.data());
g_argList->append(a);
}
g_curArgAttrib.resize(0);
@@ -479,7 +479,7 @@ RAWEND ")"[^ \t\(\)\\]{0,16}\"
g_curArgTypeName+=" []";
g_curArgArray.resize(0);
}
- //printf("resolveName `%s'->`%s'\n",yytext,name.data());
+ //printf("resolveName '%s'->'%s'\n",yytext,name.data());
g_curArgTypeName+=name;
}
<ReadFuncArgType,ReadFuncArgPtr>. {
diff --git a/src/defgen.cpp b/src/defgen.cpp
index 6601f6e..aa9a1da 100644
--- a/src/defgen.cpp
+++ b/src/defgen.cpp
@@ -27,6 +27,7 @@
#include "defargs.h"
#include "outputgen.h"
#include "dot.h"
+#include "dotclassgraph.h"
#include "arguments.h"
#include "memberlist.h"
#include "namespacedef.h"
@@ -262,7 +263,7 @@ void generateDEFForMember(MemberDef *md,
t << memPrefix << "referenceto = {" << endl;
t << refPrefix << "id = '"
<< rmd->getBodyDef()->getOutputFileBase()
- << "_1" // encoded `:' character (see util.cpp:convertNameToFile)
+ << "_1" // encoded ':' character (see util.cpp:convertNameToFile)
<< rmd->anchor() << "';" << endl;
t << refPrefix << "line = '"
@@ -295,7 +296,7 @@ void generateDEFForMember(MemberDef *md,
t << memPrefix << "referenceby = {" << endl;
t << refPrefix << "id = '"
<< rmd->getBodyDef()->getOutputFileBase()
- << "_1" // encoded `:' character (see util.cpp:convertNameToFile)
+ << "_1" // encoded ':' character (see util.cpp:convertNameToFile)
<< rmd->anchor() << "';" << endl;
t << refPrefix << "line = '"
@@ -466,14 +467,14 @@ void generateDEFForClass(ClassDef *cd,FTextStream &t)
t << " cp-documentation = <<_EnD_oF_dEf_TeXt_" << endl
<< cd->documentation() << endl << "_EnD_oF_dEf_TeXt_;" << endl;
- DotClassGraph inheritanceGraph(cd,DotNode::Inheritance);
+ DotClassGraph inheritanceGraph(cd,Inheritance);
if (!inheritanceGraph.isTrivial())
{
t << " cp-inheritancegraph = <<_EnD_oF_dEf_TeXt_" << endl;
inheritanceGraph.writeDEF(t);
t << endl << "_EnD_oF_dEf_TeXt_;" << endl;
}
- DotClassGraph collaborationGraph(cd,DotNode::Collaboration);
+ DotClassGraph collaborationGraph(cd,Collaboration);
if (!collaborationGraph.isTrivial())
{
t << " cp-collaborationgraph = <<_EnD_oF_dEf_TeXt_" << endl;
@@ -576,13 +577,13 @@ void generateDEF()
dir.setPath(QDir::currentDirPath());
if (!dir.mkdir(outputDirectory))
{
- err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
+ err("tag OUTPUT_DIRECTORY: Output directory '%s' does not "
"exist and cannot be created\n",outputDirectory.data());
exit(1);
}
else
{
- msg("Notice: Output directory `%s' does not exist. "
+ msg("Notice: Output directory '%s' does not exist. "
"I have created it for you.\n", outputDirectory.data());
}
dir.cd(outputDirectory);
diff --git a/src/definition.cpp b/src/definition.cpp
index b9c40f6..3b5fea1 100644
--- a/src/definition.cpp
+++ b/src/definition.cpp
@@ -231,7 +231,7 @@ static void addToMap(const char *name,Definition *d)
if (!vhdlOpt && index!=-1) symbolName=symbolName.mid(index+2);
if (!symbolName.isEmpty())
{
- //printf("******* adding symbol `%s' (%p)\n",symbolName.data(),d);
+ //printf("******* adding symbol '%s' (%p)\n",symbolName.data(),d);
DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
//printf(" addToMap(%p): looking for symbol %s: %p\n",d,symbolName.data(),di);
if (di==0) // new Symbol
@@ -275,7 +275,7 @@ static void removeFromMap(Definition *d)
QCString symbolName = d->_symbolName();
if (!symbolName.isEmpty())
{
- //printf("******* removing symbol `%s' (%p)\n",symbolName.data(),d);
+ //printf("******* removing symbol '%s' (%p)\n",symbolName.data(),d);
DefinitionIntf *di=Doxygen::symbolMap->find(symbolName);
if (di)
{
@@ -438,7 +438,7 @@ void DefinitionImpl::addSectionsToDefinition(QList<SectionInfo> *anchorList)
SectionInfo *si;
for (;(si=it.current());++it)
{
- //printf("Add section `%s' to definition `%s'\n",
+ //printf("Add section '%s' to definition '%s'\n",
// si->label.data(),name().data());
SectionInfo *gsi=Doxygen::sectionDict->find(si->label);
//printf("===== label=%s gsi=%p\n",si->label.data(),gsi);
@@ -594,7 +594,7 @@ void DefinitionImpl::_setDocumentation(const char *d,const char *docFile,int doc
}
if (!_docsAlreadyAdded(doc,m_impl->docSignatures))
{
- //printf("setting docs for %s: `%s'\n",name().data(),m_doc.data());
+ //printf("setting docs for %s: '%s'\n",name().data(),m_doc.data());
if (m_impl->details==0)
{
m_impl->details = new DocInfo;
@@ -913,7 +913,7 @@ bool readCodeFragment(const char *fileName,
int pc=0;
while ((c=*p++)!='{' && c!=':' && c!=0)
{
- //printf("parsing char `%c'\n",c);
+ //printf("parsing char '%c'\n",c);
if (c=='\n')
{
lineNr++,col=0;
@@ -1277,7 +1277,7 @@ void DefinitionImpl::writeInlineCode(OutputList &ol,const char *scopeName) const
// codeFragment.data(),m_impl->defFileExt.data());
ParserInterface *pIntf = Doxygen::parserManager->getParser(m_impl->defFileExt);
pIntf->resetCodeParserState();
- //printf("Read:\n`%s'\n\n",codeFragment.data());
+ //printf("Read:\n'%s'\n\n",codeFragment.data());
const MemberDef *thisMd = 0;
if (definitionType()==TypeMember) thisMd = dynamic_cast <const MemberDef*>(this);
diff --git a/src/dia.cpp b/src/dia.cpp
index 5adbc7c..8dab5b0 100644
--- a/src/dia.cpp
+++ b/src/dia.cpp
@@ -65,6 +65,8 @@ void writeDiaGraphFromFile(const char *inFile,const char *outDir,
portable_sysTimerStart();
if ((exitCode=portable_system(diaExe,diaArgs,FALSE))!=0)
{
+ err("Problems running %s. Check your installation or look typos in you dia file %s\n",
+ diaExe.data(),inFile);
portable_sysTimerStop();
goto error;
}
diff --git a/src/diagram.cpp b/src/diagram.cpp
index 06480fc..08b49ca 100644
--- a/src/diagram.cpp
+++ b/src/diagram.cpp
@@ -1165,7 +1165,7 @@ void ClassDiagram::writeFigure(FTextStream &output,const char *path,
t << " /boxwidth boxwidth str stringwidth pop max def\n";
t << "} def\n";
t << "\n";
- t << "/box % draws a box with text `arg1' at grid pos (arg2,arg3)\n";
+ t << "/box % draws a box with text 'arg1' at grid pos (arg2,arg3)\n";
t << "{ gsave\n";
t << " 2 setlinewidth\n";
t << " newpath\n";
@@ -1267,7 +1267,7 @@ void ClassDiagram::writeFigure(FTextStream &output,const char *path,
t << " stroke\n";
t << "} def\n";
t << "\n";
- t << "/conn % connections the blocks from col `arg1' to `arg2' of row `arg3'\n";
+ t << "/conn % connections the blocks from col 'arg1' to 'arg2' of row 'arg3'\n";
t << "{\n";
t << " /ys exch def\n";
t << " /xe exch def\n";
@@ -1337,7 +1337,7 @@ void ClassDiagram::writeFigure(FTextStream &output,const char *path,
QCString epstopdfArgs(4096);
epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"",
epsBaseName.data(),epsBaseName.data());
- //printf("Converting eps using `%s'\n",epstopdfArgs.data());
+ //printf("Converting eps using '%s'\n",epstopdfArgs.data());
portable_sysTimerStart();
if (portable_system("epstopdf",epstopdfArgs)!=0)
{
diff --git a/src/dirdef.cpp b/src/dirdef.cpp
index 3803335..5db8b99 100644
--- a/src/dirdef.cpp
+++ b/src/dirdef.cpp
@@ -8,6 +8,7 @@
#include "language.h"
#include "message.h"
#include "dot.h"
+#include "dotdirdeps.h"
#include "layout.h"
#include "ftextstream.h"
#include "config.h"
diff --git a/src/docbookgen.cpp b/src/docbookgen.cpp
index 8a062fc..7fe849a 100644
--- a/src/docbookgen.cpp
+++ b/src/docbookgen.cpp
@@ -33,6 +33,11 @@
#include "defargs.h"
#include "outputgen.h"
#include "dot.h"
+#include "dotcallgraph.h"
+#include "dotclassgraph.h"
+#include "dotdirdeps.h"
+#include "dotgroupcollaboration.h"
+#include "dotincldepgraph.h"
#include "pagedef.h"
#include "filename.h"
#include "version.h"
@@ -180,7 +185,7 @@ void DocbookCodeGenerator::startCodeLine(bool)
}
void DocbookCodeGenerator::endCodeLine()
{
- m_t << endl;
+ if (m_insideCodeLine) m_t << endl;
Docbook_DB(("(endCodeLine)\n"));
m_lineNumber = -1;
m_refId.resize(0);
@@ -238,7 +243,7 @@ void DocbookCodeGenerator::addWord(const char *,bool)
}
void DocbookCodeGenerator::finish()
{
- if (m_insideCodeLine) endCodeLine();
+ endCodeLine();
}
void DocbookCodeGenerator::startCodeFragment()
{
@@ -246,6 +251,9 @@ void DocbookCodeGenerator::startCodeFragment()
}
void DocbookCodeGenerator::endCodeFragment()
{
+ //endCodeLine checks is there is still an open code line, if so closes it.
+ endCodeLine();
+
m_t << "</computeroutput></literallayout>" << endl;
}
@@ -1002,6 +1010,9 @@ DB_GEN_C
void DocbookGenerator::endCodeFragment()
{
DB_GEN_C
+ //endCodeLine checks is there is still an open code line, if so closes it.
+ endCodeLine();
+
t << "</programlisting>";
}
void DocbookGenerator::startMemberTemplateParams()
@@ -1095,7 +1106,7 @@ void DocbookGenerator::startGroupCollaboration()
{
DB_GEN_C
}
-void DocbookGenerator::endGroupCollaboration(const DotGroupCollaboration &g)
+void DocbookGenerator::endGroupCollaboration(DotGroupCollaboration &g)
{
DB_GEN_C
g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,FALSE);
@@ -1104,7 +1115,7 @@ void DocbookGenerator::startDotGraph()
{
DB_GEN_C
}
-void DocbookGenerator::endDotGraph(const DotClassGraph &g)
+void DocbookGenerator::endDotGraph(DotClassGraph &g)
{
DB_GEN_C
g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT),fileName,relPath,TRUE,FALSE);
@@ -1113,7 +1124,7 @@ void DocbookGenerator::startInclDepGraph()
{
DB_GEN_C
}
-void DocbookGenerator::endInclDepGraph(const DotInclDepGraph &g)
+void DocbookGenerator::endInclDepGraph(DotInclDepGraph &g)
{
DB_GEN_C
QCString fn = g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT), fileName,relPath,FALSE);
@@ -1122,7 +1133,7 @@ void DocbookGenerator::startCallGraph()
{
DB_GEN_C
}
-void DocbookGenerator::endCallGraph(const DotCallGraph &g)
+void DocbookGenerator::endCallGraph(DotCallGraph &g)
{
DB_GEN_C
QCString fn = g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT), fileName,relPath,FALSE);
@@ -1131,7 +1142,7 @@ void DocbookGenerator::startDirDepGraph()
{
DB_GEN_C
}
-void DocbookGenerator::endDirDepGraph(const DotDirDeps &g)
+void DocbookGenerator::endDirDepGraph(DotDirDeps &g)
{
DB_GEN_C
QCString fn = g.writeGraph(t,GOF_BITMAP,EOF_DocBook,Config_getString(DOCBOOK_OUTPUT), fileName,relPath,FALSE);
diff --git a/src/docbookgen.h b/src/docbookgen.h
index 8674150..8f71722 100644
--- a/src/docbookgen.h
+++ b/src/docbookgen.h
@@ -281,16 +281,16 @@ class DocbookGenerator : public OutputGenerator
void startClassDiagram();
void endClassDiagram(const ClassDiagram &,const char *,const char *);
void startDotGraph();
- void endDotGraph(const DotClassGraph &g);
+ void endDotGraph(DotClassGraph &g);
void startInclDepGraph();
- void endInclDepGraph(const DotInclDepGraph &g);
+ void endInclDepGraph(DotInclDepGraph &g);
void startGroupCollaboration();
- void endGroupCollaboration(const DotGroupCollaboration &g);
+ void endGroupCollaboration(DotGroupCollaboration &g);
void startCallGraph();
- void endCallGraph(const DotCallGraph &g);
+ void endCallGraph(DotCallGraph &g);
void startDirDepGraph();
- void endDirDepGraph(const DotDirDeps &g);
- void writeGraphicalHierarchy(const DotGfxHierarchyTable &g){DB_GEN_NEW};
+ void endDirDepGraph(DotDirDeps &g);
+ void writeGraphicalHierarchy(DotGfxHierarchyTable &g){DB_GEN_NEW};
void startQuickIndices(){DB_GEN_EMPTY};
void endQuickIndices(){DB_GEN_EMPTY};
void writeSplitBar(const char *){DB_GEN_EMPTY};
diff --git a/src/docbookvisitor.cpp b/src/docbookvisitor.cpp
index 64425c6..a42a895 100644
--- a/src/docbookvisitor.cpp
+++ b/src/docbookvisitor.cpp
@@ -263,7 +263,9 @@ DB_VIS_C
case DocStyleChange::Small: /* XSLT Stylesheets can be used */ break;
/* HTML only */
case DocStyleChange::Strike: break;
+ case DocStyleChange::Del: break;
case DocStyleChange::Underline: break;
+ case DocStyleChange::Ins: break;
case DocStyleChange::Div: /* HTML only */ break;
case DocStyleChange::Span: /* HTML only */ break;
}
@@ -472,20 +474,22 @@ DB_VIS_C
pushEnabled();
m_hide = TRUE;
}
- SrcLangExt langExt = getLanguageFromFileName(m_langExt);
+ QCString locLangExt = getFileNameExtension(op->includeFileName());
+ if (locLangExt.isEmpty()) locLangExt = m_langExt;
+ SrcLangExt langExt = getLanguageFromFileName(locLangExt);
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide)
{
- FileDef *fd;
+ FileDef *fd = 0;
if (!op->includeFileName().isEmpty())
{
QFileInfo cfi( op->includeFileName() );
fd = createFileDef( cfi.dirPath().utf8(), cfi.fileName().utf8() );
}
- Doxygen::parserManager->getParser(m_langExt)
+ Doxygen::parserManager->getParser(locLangExt)
->parseCode(m_ci,op->context(),
op->text(),langExt,op->isExample(),
op->exampleFile(),
@@ -634,152 +638,152 @@ DB_VIS_C
case DocSimpleSect::See:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trSeeAlso() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trSeeAlso() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trSeeAlso()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trSeeAlso()) << "</title>" << endl;
}
break;
case DocSimpleSect::Return:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trReturns()<< ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trReturns()<< "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trReturns()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trReturns()) << "</title>" << endl;
}
break;
case DocSimpleSect::Author:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trAuthor(TRUE, TRUE) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trAuthor(TRUE, TRUE) << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trAuthor(TRUE, TRUE)) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trAuthor(TRUE, TRUE)) << "</title>" << endl;
}
break;
case DocSimpleSect::Authors:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trAuthor(TRUE, FALSE) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trAuthor(TRUE, FALSE) << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trAuthor(TRUE, FALSE)) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trAuthor(TRUE, FALSE)) << "</title>" << endl;
}
break;
case DocSimpleSect::Version:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trVersion() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trVersion() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trVersion()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trVersion()) << "</title>" << endl;
}
break;
case DocSimpleSect::Since:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trSince() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trSince() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trSince()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trSince()) << "</title>" << endl;
}
break;
case DocSimpleSect::Date:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trDate() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trDate() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trDate()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trDate()) << "</title>" << endl;
}
break;
case DocSimpleSect::Note:
if (m_insidePre)
{
- m_t << "<note><title>" << theTranslator->trNote() << ": </title>" << endl;
+ m_t << "<note><title>" << theTranslator->trNote() << "</title>" << endl;
}
else
{
- m_t << "<note><title>" << convertToDocBook(theTranslator->trNote()) << ": </title>" << endl;
+ m_t << "<note><title>" << convertToDocBook(theTranslator->trNote()) << "</title>" << endl;
}
break;
case DocSimpleSect::Warning:
if (m_insidePre)
{
- m_t << "<warning><title>" << theTranslator->trWarning() << ": </title>" << endl;
+ m_t << "<warning><title>" << theTranslator->trWarning() << "</title>" << endl;
}
else
{
- m_t << "<warning><title>" << convertToDocBook(theTranslator->trWarning()) << ": </title>" << endl;
+ m_t << "<warning><title>" << convertToDocBook(theTranslator->trWarning()) << "</title>" << endl;
}
break;
case DocSimpleSect::Pre:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trPrecondition() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trPrecondition() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trPrecondition()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trPrecondition()) << "</title>" << endl;
}
break;
case DocSimpleSect::Post:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trPostcondition() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trPostcondition() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trPostcondition()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trPostcondition()) << "</title>" << endl;
}
break;
case DocSimpleSect::Copyright:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trCopyright() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trCopyright() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trCopyright()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trCopyright()) << "</title>" << endl;
}
break;
case DocSimpleSect::Invar:
if (m_insidePre)
{
- m_t << "<formalpara><title>" << theTranslator->trInvariant() << ": </title>" << endl;
+ m_t << "<formalpara><title>" << theTranslator->trInvariant() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(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;
+ m_t << "<formalpara><title>" << theTranslator->trRemarks() << "</title>" << endl;
}
else
{
- m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trRemarks()) << ": </title>" << endl;
+ m_t << "<formalpara><title>" << convertToDocBook(theTranslator->trRemarks()) << "</title>" << endl;
}
break;
case DocSimpleSect::Attention:
if (m_insidePre)
{
- m_t << "<caution><title>" << theTranslator->trAttention() << ": </title>" << endl;
+ m_t << "<caution><title>" << theTranslator->trAttention() << "</title>" << endl;
}
else
{
- m_t << "<caution><title>" << convertToDocBook(theTranslator->trAttention()) << ": </title>" << endl;
+ m_t << "<caution><title>" << convertToDocBook(theTranslator->trAttention()) << "</title>" << endl;
}
break;
case DocSimpleSect::User:
@@ -1429,11 +1433,9 @@ DB_VIS_C
{
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);
@@ -1442,6 +1444,11 @@ DB_VIS_C
{
visit((DocLinkedWord*)type);
}
+ else if (type->kind()==DocNode::Kind_Sep)
+ {
+ m_t << " " << ((DocSeparator *)type)->chars() << " ";
+ }
+
}
m_t << " </entry>";
}
@@ -1521,22 +1528,6 @@ DB_VIS_C
m_t << " ";
}
-void DocbookDocVisitor::visitPre(DocCopy *)
-{
-DB_VIS_C
- if (m_hide) return;
- // TODO: to be implemented
-}
-
-
-void DocbookDocVisitor::visitPost(DocCopy *)
-{
-DB_VIS_C
- if (m_hide) return;
- // TODO: to be implemented
-}
-
-
void DocbookDocVisitor::visitPre(DocText *)
{
DB_VIS_C
diff --git a/src/docbookvisitor.h b/src/docbookvisitor.h
index 24b1fbb..47275f7 100644
--- a/src/docbookvisitor.h
+++ b/src/docbookvisitor.h
@@ -127,8 +127,6 @@ class DocbookDocVisitor : public DocVisitor
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
diff --git a/src/docgroup.cpp b/src/docgroup.cpp
new file mode 100644
index 0000000..1f4fb6d
--- /dev/null
+++ b/src/docgroup.cpp
@@ -0,0 +1,215 @@
+#include "doxygen.h"
+#include "util.h"
+#include "entry.h"
+#include "message.h"
+#include "docgroup.h"
+
+
+void DocGroup::enterFile(const char *fileName,int)
+{
+ m_openCount = 0;
+ m_autoGroupStack.setAutoDelete(TRUE);
+ m_autoGroupStack.clear();
+ m_memberGroupId = DOX_NOGROUP;
+ m_memberGroupDocs.resize(0);
+ m_memberGroupRelates.resize(0);
+ m_compoundName=fileName;
+}
+
+void DocGroup::leaveFile(const char *fileName,int line)
+{
+ //if (m_memberGroupId!=DOX_NOGROUP)
+ //{
+ // warn(fileName,line,"end of file while inside a member group\n");
+ //}
+ m_memberGroupId=DOX_NOGROUP;
+ m_memberGroupRelates.resize(0);
+ m_memberGroupDocs.resize(0);
+ if (!m_autoGroupStack.isEmpty())
+ {
+ warn(fileName,line,"end of file while inside a group");
+ }
+ else if (m_openCount > 0) // < 0 is already handled on close call
+ {
+ warn(fileName,line,"end of file with unbalanced grouping commands");
+ }
+}
+
+void DocGroup::enterCompound(const char *fileName,int line,const char *name)
+{
+ if (m_memberGroupId!=DOX_NOGROUP)
+ {
+ warn(fileName,line,"try to put compound %s inside a member group\n",name);
+ }
+ m_memberGroupId=DOX_NOGROUP;
+ m_memberGroupRelates.resize(0);
+ m_memberGroupDocs.resize(0);
+ m_compoundName = name;
+ int i = m_compoundName.find('(');
+ if (i!=-1)
+ {
+ m_compoundName=m_compoundName.left(i); // strip category (Obj-C)
+ }
+ if (m_compoundName.isEmpty())
+ {
+ m_compoundName=fileName;
+ }
+ //printf("groupEnterCompound(%s)\n",name);
+}
+
+void DocGroup::leaveCompound(const char *,int,const char * /*name*/)
+{
+ //printf("groupLeaveCompound(%s)\n",name);
+ //if (m_memberGroupId!=DOX_NOGROUP)
+ //{
+ // warn(fileName,line,"end of compound %s while inside a member group\n",name);
+ //}
+ m_memberGroupId=DOX_NOGROUP;
+ m_memberGroupRelates.resize(0);
+ m_memberGroupDocs.resize(0);
+ m_compoundName.resize(0);
+}
+
+int DocGroup::findExistingGroup(int &groupId,const MemberGroupInfo *info)
+{
+ //printf("findExistingGroup %s:%s\n",info->header.data(),info->compoundName.data());
+ QIntDictIterator<MemberGroupInfo> di(Doxygen::memGrpInfoDict);
+ MemberGroupInfo *mi;
+ for (di.toFirst();(mi=di.current());++di)
+ {
+ if (m_compoundName==mi->compoundName && // same file or scope
+ !mi->header.isEmpty() && // not a nameless group
+ qstricmp(mi->header,info->header)==0 // same header name
+ )
+ {
+ //printf("Found it!\n");
+ return (int)di.currentKey(); // put the item in this group
+ }
+ }
+ groupId++; // start new group
+ return groupId;
+}
+
+void DocGroup::open(Entry *e,const char *,int, bool implicit)
+{
+ if (!implicit) m_openCount++;
+ //printf("==> openGroup(name=%s,sec=%x) m_autoGroupStack=%d\n",
+ // e->name.data(),e->section,m_autoGroupStack.count());
+ if (e->section==Entry::GROUPDOC_SEC) // auto group
+ {
+ m_autoGroupStack.push(new Grouping(e->name,e->groupingPri()));
+ }
+ else // start of a member group
+ {
+ //printf(" membergroup id=%d %s\n",m_memberGroupId,m_memberGroupHeader.data());
+ if (m_memberGroupId==DOX_NOGROUP) // no group started yet
+ {
+ static int curGroupId=0;
+
+ MemberGroupInfo *info = new MemberGroupInfo;
+ info->header = m_memberGroupHeader.stripWhiteSpace();
+ info->compoundName = m_compoundName;
+ m_memberGroupId = findExistingGroup(curGroupId,info);
+ //printf(" use membergroup %d\n",m_memberGroupId);
+ Doxygen::memGrpInfoDict.insert(m_memberGroupId,info);
+
+ m_memberGroupRelates = e->relates;
+ e->mGrpId = m_memberGroupId;
+ }
+ }
+}
+
+void DocGroup::close(Entry *e,const char *fileName,int line,bool foundInline,bool implicit)
+{
+ if (!implicit)
+ {
+ if (m_openCount < 1)
+ {
+ warn(fileName,line,"unbalanced grouping commands");
+ }
+ else
+ {
+ m_openCount--;
+ }
+ }
+ //printf("==> closeGroup(name=%s,sec=%x,file=%s,line=%d) m_autoGroupStack=%d\n",
+ // e->name.data(),e->section,fileName,line,m_autoGroupStack.count());
+ if (m_memberGroupId!=DOX_NOGROUP) // end of member group
+ {
+ MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(m_memberGroupId);
+ if (info) // known group
+ {
+ info->doc = m_memberGroupDocs;
+ info->docFile = fileName;
+ info->docLine = line;
+ }
+ m_memberGroupId=DOX_NOGROUP;
+ m_memberGroupRelates.resize(0);
+ m_memberGroupDocs.resize(0);
+ if (!foundInline) e->mGrpId=DOX_NOGROUP;
+ //printf("new group id=%d\n",m_memberGroupId);
+ }
+ else if (!m_autoGroupStack.isEmpty()) // end of auto group
+ {
+ Grouping *grp = m_autoGroupStack.pop();
+ // see bug577005: we should not remove the last group for e
+ if (!foundInline) e->groups->removeLast();
+ //printf("Removing %s e=%p\n",grp->groupname.data(),e);
+ delete grp;
+ if (!foundInline) initGroupInfo(e);
+ }
+}
+
+void DocGroup::initGroupInfo(Entry *e)
+{
+ //printf("==> initGroup(id=%d,related=%s,e=%p)\n",m_memberGroupId,
+ // m_memberGroupRelates.data(),e);
+ e->mGrpId = m_memberGroupId;
+ e->relates = m_memberGroupRelates;
+ if (!m_autoGroupStack.isEmpty())
+ {
+ //printf("Appending group %s to %s: count=%d entry=%p\n",
+ // m_autoGroupStack.top()->groupname.data(),
+ // e->name.data(),e->groups->count(),e);
+ e->groups->append(new Grouping(*m_autoGroupStack.top()));
+ }
+}
+
+void DocGroup::addDocs(Entry *e)
+{
+ if (e->section==Entry::MEMBERGRP_SEC)
+ {
+ m_memberGroupDocs=e->brief.stripWhiteSpace();
+ e->doc = stripLeadingAndTrailingEmptyLines(e->doc,e->docLine);
+ if (!m_memberGroupDocs.isEmpty() && !e->doc.isEmpty())
+ {
+ m_memberGroupDocs+="\n\n";
+ }
+ m_memberGroupDocs+=e->doc;
+ MemberGroupInfo *info=Doxygen::memGrpInfoDict.find(m_memberGroupId);
+ if (info)
+ {
+ info->doc = m_memberGroupDocs;
+ info->docFile = e->docFile;
+ info->docLine = e->docLine;
+ info->setRefItems(e->sli);
+ }
+ e->doc.resize(0);
+ e->brief.resize(0);
+ }
+}
+
+bool DocGroup::isEmpty() const
+{
+ return (m_memberGroupId==DOX_NOGROUP);
+}
+
+void DocGroup::clearHeader()
+{
+ m_memberGroupHeader.resize(0);
+}
+
+void DocGroup::appendHeader(const char text)
+{
+ m_memberGroupHeader += text;
+}
diff --git a/src/docgroup.h b/src/docgroup.h
new file mode 100644
index 0000000..4775d90
--- /dev/null
+++ b/src/docgroup.h
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2019 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 DOCGROUP_H
+#define DOCGROUP_H
+
+#include <qstack.h>
+#include <qstring.h>
+#include "membergroup.h"
+
+class Entry;
+
+class DocGroup
+{
+ public:
+ DocGroup() {};
+
+ public:
+ void enterFile(const char *fileName,int);
+ void leaveFile(const char *fileName,int line);
+ void enterCompound(const char *fileName,int line,const char *name);
+ void leaveCompound(const char *,int,const char * /*name*/);
+ void open(Entry *e,const char *,int,bool implicit=false);
+ void close(Entry *e,const char *fileName,int line,bool foundInline,bool implicit=false);
+ void initGroupInfo(Entry *e);
+ bool isEmpty() const;
+ void clearHeader();
+ void appendHeader(const char);
+ void addDocs(Entry *e);
+
+ private:
+ int findExistingGroup(int &groupId,const MemberGroupInfo *info);
+ int m_openCount;
+ QCString m_memberGroupHeader;
+ int m_memberGroupId;
+ QCString m_memberGroupRelates;
+ QCString m_memberGroupDocs;
+ QStack<Grouping> m_autoGroupStack;
+ QCString m_compoundName;
+};
+
+#endif
diff --git a/src/docparser.cpp b/src/docparser.cpp
index 597d304..b97bf1c 100644
--- a/src/docparser.cpp
+++ b/src/docparser.cpp
@@ -101,6 +101,7 @@ static QCString g_relPath;
static bool g_hasParamCommand;
static bool g_hasReturnCommand;
+static QDict<void> g_retvalsFound;
static QDict<void> g_paramsFound;
static const MemberDef * g_memberDef;
static bool g_isExample;
@@ -136,6 +137,7 @@ struct DocParserContext
bool hasParamCommand;
bool hasReturnCommand;
const MemberDef * memberDef;
+ QDict<void> retvalsFound;
QDict<void> paramsFound;
bool isExample;
QCString exampleName;
@@ -183,6 +185,7 @@ static void docParserPushContext(bool saveParamInfo=TRUE)
ctx->hasParamCommand = g_hasParamCommand;
ctx->hasReturnCommand = g_hasReturnCommand;
ctx->paramsFound = g_paramsFound;
+ ctx->retvalsFound = g_retvalsFound;
}
ctx->memberDef = g_memberDef;
@@ -223,6 +226,7 @@ static void docParserPopContext(bool keepParamInfo=FALSE)
{
g_hasParamCommand = ctx->hasParamCommand;
g_hasReturnCommand = ctx->hasReturnCommand;
+ g_retvalsFound = ctx->retvalsFound;
g_paramsFound = ctx->paramsFound;
}
g_memberDef = ctx->memberDef;
@@ -283,7 +287,7 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type, bool
bool ambig;
FileDef *fd;
//printf("Search for %s\n",fileName);
- if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
+ if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)) && !ambig)
{
QCString inputFile = fd->absFilePath();
QFile inImage(inputFile);
@@ -374,13 +378,16 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type, bool
return baseName;
}
}
- else if (ambig && dowarn)
+ else if (ambig)
{
- QCString text;
- text.sprintf("image file name %s is ambiguous.\n",qPrint(fileName));
- text+="Possible candidates:\n";
- text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
- warn_doc_error(g_fileName,doctokenizerYYlineno,text);
+ if (dowarn)
+ {
+ QCString text;
+ text.sprintf("image file name %s is ambiguous.\n",qPrint(fileName));
+ text+="Possible candidates:\n";
+ text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
+ warn_doc_error(g_fileName,doctokenizerYYlineno,text);
+ }
}
else
{
@@ -396,13 +403,13 @@ static QCString findAndCopyImage(const char *fileName,DocImage::Type type, bool
return result;
}
-/*! Collects the parameters found with \@param or \@retval commands
- * in a global list g_paramsFound. If \a isParam is set to TRUE
- * and the parameter is not an actual parameter of the current
+/*! Collects the parameters found with \@param command
+ * in a global list g_paramsFound. If
+ * the parameter is not an actual parameter of the current
* member g_memberDef, then a warning is raised (unless warnings
* are disabled altogether).
*/
-static void checkArgumentName(const QCString &name,bool isParam)
+static void checkArgumentName(const QCString &name)
{
if (!Config_getBool(WARN_IF_DOC_ERROR)) return;
if (g_memberDef==0) return; // not a member
@@ -419,7 +426,7 @@ static void checkArgumentName(const QCString &name,bool isParam)
{
QCString aName=name.mid(i,l);
if (lang==SrcLangExt_Fortran) aName=aName.lower();
- //printf("aName=`%s'\n",aName.data());
+ //printf("aName='%s'\n",aName.data());
ArgumentListIterator ali(*al);
const Argument *a;
bool found=FALSE;
@@ -428,16 +435,16 @@ static void checkArgumentName(const QCString &name,bool isParam)
QCString argName = g_memberDef->isDefine() ? a->type : a->name;
if (lang==SrcLangExt_Fortran) argName=argName.lower();
argName=argName.stripWhiteSpace();
- //printf("argName=`%s' aName=%s\n",argName.data(),aName.data());
+ //printf("argName='%s' aName=%s\n",argName.data(),aName.data());
if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
- if (aName==argName && isParam)
+ if (aName==argName)
{
g_paramsFound.insert(aName,(void *)(0x8));
found=TRUE;
break;
}
}
- if (!found && isParam)
+ if (!found)
{
//printf("member type=%d\n",g_memberDef->memberType());
QCString scope=g_memberDef->getScopeString();
@@ -465,6 +472,23 @@ static void checkArgumentName(const QCString &name,bool isParam)
p=i+l;
}
}
+/*! Collects the return values found with \@retval command
+ * in a global list g_retvalsFound.
+ */
+static void checkRetvalName(const QCString &name)
+{
+ if (!Config_getBool(WARN_IF_DOC_ERROR)) return;
+ if (g_memberDef==0 || name.isEmpty()) return; // not a member or no valid name
+ if (g_retvalsFound.find(name))
+ {
+ warn_doc_error(g_memberDef->getDefFileName(),
+ g_memberDef->getDefLine(),
+ "return value '" + name + "' of " +
+ QCString(g_memberDef->qualifiedName()) +
+ " has multiple documentation sections");
+ }
+ g_retvalsFound.insert(name,(void *)(0x8));
+}
/*! Checks if the parameters that have been specified using \@param are
* indeed all parameters and that a parameter does not have multiple
@@ -697,7 +721,7 @@ static bool findDocsForMemberOrCompound(const char *commandName,
const GroupDef *gd=0;
const PageDef *pd=0;
bool found = getDefs(
- g_context.find('.')==-1?g_context.data():"", // `find('.') is a hack to detect files
+ g_context.find('.')==-1?g_context.data():"", // find('.') is a hack to detect files
name,
args.isEmpty()?0:args.data(),
md,cd,fd,nd,gd,FALSE,0,TRUE);
@@ -719,7 +743,7 @@ static bool findDocsForMemberOrCompound(const char *commandName,
{
fullName.prepend(g_context.left(scopeOffset)+"::");
}
- //printf("Trying fullName=`%s'\n",fullName.data());
+ //printf("Trying fullName='%s'\n",fullName.data());
// try class, namespace, group, page, file reference
cd = Doxygen::classSDict->find(fullName);
@@ -817,8 +841,8 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return tok;
}
while ((tok=doctokenizerYYlex()) &&
@@ -853,7 +877,7 @@ static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
break;
}
}
- DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(cmdName),tok));
+ DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(saveCmdName),tok));
return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
) ? tok : RetVal_OK;
}
@@ -996,7 +1020,9 @@ const char *DocStyleChange::styleString() const
case DocStyleChange::Div: return "div";
case DocStyleChange::Span: return "span";
case DocStyleChange::Strike: return "strike";
+ case DocStyleChange::Del: return "del";
case DocStyleChange::Underline: return "u";
+ case DocStyleChange::Ins: return "ins";
}
return "<invalid>";
}
@@ -1143,17 +1169,25 @@ static void handleLinkedWord(DocNode *parent,QList<DocNode> &children,bool ignor
static void handleParameterType(DocNode *parent,QList<DocNode> &children,const QCString &paramTypes)
{
- QCString name = g_token->name;
- int p=0,i;
+ QCString name = g_token->name; // save token name
+ QCString name1;
+ int p=0,i,l,ii;
while ((i=paramTypes.find('|',p))!=-1)
{
- g_token->name = paramTypes.mid(p,i-p);
+ name1 = paramTypes.mid(p,i-p);
+ ii=name1.find('[');
+ g_token->name=ii!=-1 ? name1.mid(0,ii) : name1; // take part without []
handleLinkedWord(parent,children);
+ if (ii!=-1) children.append(new DocWord(parent,name1.mid(ii))); // add [] part
p=i+1;
+ children.append(new DocSeparator(parent,"|"));
}
- g_token->name = paramTypes.mid(p);
+ name1 = paramTypes.mid(p);
+ ii=name1.find('[');
+ g_token->name=ii!=-1 ? name1.mid(0,ii) : name1;
handleLinkedWord(parent,children);
- g_token->name = name;
+ if (ii!=-1) children.append(new DocWord(parent,name1.mid(ii)));
+ g_token->name = name; // restore original token name
}
static DocInternalRef *handleInternalRef(DocNode *parent)
@@ -1163,7 +1197,7 @@ static DocInternalRef *handleInternalRef(DocNode *parent)
QCString tokenName = g_token->name;
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(tokenName));
return 0;
}
@@ -1183,7 +1217,7 @@ static DocAnchor *handleAnchor(DocNode *parent)
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));
return 0;
}
@@ -1526,6 +1560,16 @@ reparsetoken:
handleStyleLeave(parent,children,DocStyleChange::Strike,tokenName);
}
break;
+ case HTML_DEL:
+ if (!g_token->endTag)
+ {
+ handleStyleEnter(parent,children,DocStyleChange::Del,&g_token->attribs);
+ }
+ else
+ {
+ handleStyleLeave(parent,children,DocStyleChange::Del,tokenName);
+ }
+ break;
case HTML_UNDERLINE:
if (!g_token->endTag)
{
@@ -1536,6 +1580,16 @@ reparsetoken:
handleStyleLeave(parent,children,DocStyleChange::Underline,tokenName);
}
break;
+ case HTML_INS:
+ if (!g_token->endTag)
+ {
+ handleStyleEnter(parent,children,DocStyleChange::Ins,&g_token->attribs);
+ }
+ else
+ {
+ handleStyleLeave(parent,children,DocStyleChange::Ins,tokenName);
+ }
+ break;
case HTML_CODE:
case XML_C:
if (!g_token->endTag)
@@ -1792,7 +1846,7 @@ static void readTextFileByName(const QCString &file,QCString &text)
// as a fallback we also look in the exampleNameDict
bool ambig;
FileDef *fd;
- if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
+ if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)) && !ambig)
{
text = fileToString(fd->absFilePath(),Config_getBool(FILTER_SOURCE_FILES));
}
@@ -1849,6 +1903,7 @@ DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
if (id.isEmpty())
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Empty anchor label");
+ return;
}
if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix)
@@ -1861,7 +1916,7 @@ DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
}
else
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid cite anchor id `%s'",qPrint(id));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid cite anchor id '%s'",qPrint(id));
m_anchor = "invalid";
m_file = "invalid";
}
@@ -1886,7 +1941,7 @@ DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
}
else
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid anchor id `%s'",qPrint(id));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid anchor id '%s'",qPrint(id));
m_anchor = "invalid";
m_file = "invalid";
}
@@ -2099,100 +2154,6 @@ void DocIncOperator::parse()
//---------------------------------------------------------------------------
-void DocCopy::parse(QList<DocNode> &children)
-{
- QCString doc,brief;
- const Definition *def = 0;
- if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
- {
- if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
- {
- bool hasParamCommand = g_hasParamCommand;
- bool hasReturnCommand = g_hasReturnCommand;
- QDict<void> paramsFound = g_paramsFound;
- //printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
- // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
-
- docParserPushContext(FALSE);
- g_scope = def;
- if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
- {
- if (def->getOuterScope()!=Doxygen::globalScope)
- {
- g_context=def->getOuterScope()->name();
- }
- }
- else if (def!=Doxygen::globalScope)
- {
- g_context=def->name();
- }
- g_styleStack.clear();
- g_nodeStack.clear();
- g_paramsFound.clear();
- g_copyStack.append(def);
- // make sure the descriptions end with a newline, so the parser will correctly
- // handle them in all cases.
- //printf("doc='%s'\n",doc.data());
- //printf("brief='%s'\n",brief.data());
- if (m_copyBrief)
- {
- brief+='\n';
- internalValidatingParseDoc(m_parent,children,brief);
-
- //printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
- // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
- hasParamCommand = hasParamCommand || g_hasParamCommand;
- hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
- QDictIterator<void> it(g_paramsFound);
- void *item;
- for (;(item=it.current());++it)
- {
- paramsFound.insert(it.currentKey(),it.current());
- }
- }
- if (m_copyDetails)
- {
- doc+='\n';
- internalValidatingParseDoc(m_parent,children,doc);
-
- //printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
- // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
- hasParamCommand = hasParamCommand || g_hasParamCommand;
- hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
- QDictIterator<void> it(g_paramsFound);
- void *item;
- for (;(item=it.current());++it)
- {
- paramsFound.insert(it.currentKey(),it.current());
- }
- }
- g_copyStack.remove(def);
- ASSERT(g_styleStack.isEmpty());
- ASSERT(g_nodeStack.isEmpty());
- docParserPopContext(TRUE);
-
- g_hasParamCommand = hasParamCommand;
- g_hasReturnCommand = hasReturnCommand;
- g_paramsFound = paramsFound;
-
- //printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
- // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
- }
- else // oops, recursion
- {
- warn_doc_error(g_fileName,doctokenizerYYlineno,"recursive call chain of \\copydoc commands detected at %d\n",
- doctokenizerYYlineno);
- }
- }
- else
- {
- warn_doc_error(g_fileName,doctokenizerYYlineno,"target %s of \\copydoc command not found",
- qPrint(m_link));
- }
-}
-
-//---------------------------------------------------------------------------
-
DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) :
m_id(id), m_key(key), m_relPath(g_relPath)
{
@@ -2531,7 +2492,7 @@ DocRef::DocRef(DocNode *parent,const QCString &target,const QCString &context) :
}
}
m_text = target;
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to `%s' for \\ref command",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to '%s' for \\ref command",
qPrint(target));
}
@@ -2629,7 +2590,7 @@ DocCite::DocCite(DocNode *parent,const QCString &target,const QCString &) //cont
}
else if (cite==0)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to `%s' for \\cite command",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to '%s' for \\cite command",
qPrint(target));
}
else
@@ -2672,7 +2633,7 @@ DocLink::DocLink(DocNode *parent,const QCString &target)
}
// bogus link target
- warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve link to `%s' for \\link command",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve link to '%s' for \\link command",
qPrint(target));
}
@@ -2776,8 +2737,9 @@ DocDotFile::DocDotFile(DocNode *parent,const QCString &name,const QCString &cont
m_parent = parent;
}
-void DocDotFile::parse()
+bool DocDotFile::parse()
{
+ bool ok = false;
defaultHandleTitleAndSize(CMD_DOTFILE,this,m_children,m_width,m_height);
bool ambig;
@@ -2786,15 +2748,16 @@ void DocDotFile::parse()
{
fd = findFileDef(Doxygen::dotFileNameDict,m_name+".dot",ambig);
}
- if (fd)
+ if (fd && !ambig)
{
m_file = fd->absFilePath();
+ ok = true;
}
else if (ambig)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"included dot file name %s is ambiguous.\n"
"Possible candidates:\n%s",qPrint(m_name),
- qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
+ qPrint(showFileDefMatches(Doxygen::dotFileNameDict,m_name))
);
}
else
@@ -2802,6 +2765,7 @@ void DocDotFile::parse()
warn_doc_error(g_fileName,doctokenizerYYlineno,"included dot file %s is not found "
"in any of the paths specified via DOTFILE_DIRS!",qPrint(m_name));
}
+ return ok;
}
DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &context) :
@@ -2810,8 +2774,9 @@ DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &cont
m_parent = parent;
}
-void DocMscFile::parse()
+bool DocMscFile::parse()
{
+ bool ok = false;
defaultHandleTitleAndSize(CMD_MSCFILE,this,m_children,m_width,m_height);
bool ambig;
@@ -2820,15 +2785,16 @@ void DocMscFile::parse()
{
fd = findFileDef(Doxygen::mscFileNameDict,m_name+".msc",ambig);
}
- if (fd)
+ if (fd && !ambig)
{
m_file = fd->absFilePath();
+ ok = true;
}
else if (ambig)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"included msc file name %s is ambiguous.\n"
"Possible candidates:\n%s",qPrint(m_name),
- qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
+ qPrint(showFileDefMatches(Doxygen::mscFileNameDict,m_name))
);
}
else
@@ -2836,6 +2802,7 @@ void DocMscFile::parse()
warn_doc_error(g_fileName,doctokenizerYYlineno,"included msc file %s is not found "
"in any of the paths specified via MSCFILE_DIRS!",qPrint(m_name));
}
+ return ok;
}
//---------------------------------------------------------------------------
@@ -2846,8 +2813,9 @@ DocDiaFile::DocDiaFile(DocNode *parent,const QCString &name,const QCString &cont
m_parent = parent;
}
-void DocDiaFile::parse()
+bool DocDiaFile::parse()
{
+ bool ok = false;
defaultHandleTitleAndSize(CMD_DIAFILE,this,m_children,m_width,m_height);
bool ambig;
@@ -2856,15 +2824,16 @@ void DocDiaFile::parse()
{
fd = findFileDef(Doxygen::diaFileNameDict,m_name+".dia",ambig);
}
- if (fd)
+ if (fd && !ambig)
{
m_file = fd->absFilePath();
+ ok = true;
}
else if (ambig)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"included dia file name %s is ambiguous.\n"
"Possible candidates:\n%s",qPrint(m_name),
- qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
+ qPrint(showFileDefMatches(Doxygen::diaFileNameDict,m_name))
);
}
else
@@ -2872,6 +2841,7 @@ void DocDiaFile::parse()
warn_doc_error(g_fileName,doctokenizerYYlineno,"included dia file %s is not found "
"in any of the paths specified via DIAFILE_DIRS!",qPrint(m_name));
}
+ return ok;
}
//---------------------------------------------------------------------------
@@ -3258,7 +3228,7 @@ DocHtmlCaption::DocHtmlCaption(DocNode *parent,const HtmlAttribList &attribs)
HtmlAttrib *opt;
for (li.toFirst();(opt=li.current());++li)
{
- if (opt->name=="id") // interpret id attribute as an anchor
+ if (opt->name=="id" && !opt->value.isEmpty()) // interpret id attribute as an anchor
{
SectionInfo *sec = Doxygen::sectionDict->find(opt->value);
if (sec)
@@ -3275,7 +3245,7 @@ DocHtmlCaption::DocHtmlCaption(DocNode *parent,const HtmlAttribList &attribs)
}
else
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid caption id `%s'",qPrint(opt->value));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid caption id '%s'",qPrint(opt->value));
}
}
else // copy attribute
@@ -4644,8 +4614,8 @@ int DocParamList::parse(const QCString &cmdName)
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
retval=0;
goto endparamlist;
}
@@ -4661,19 +4631,19 @@ int DocParamList::parse(const QCString &cmdName)
handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator));
g_token->name = g_token->name.mid(typeSeparator+1);
g_hasParamCommand=TRUE;
- checkArgumentName(g_token->name,TRUE);
+ checkArgumentName(g_token->name);
((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE;
}
else
{
g_hasParamCommand=TRUE;
- checkArgumentName(g_token->name,TRUE);
+ checkArgumentName(g_token->name);
}
}
else if (m_type==DocParamSect::RetVal)
{
g_hasReturnCommand=TRUE;
- checkArgumentName(g_token->name,FALSE);
+ checkRetvalName(g_token->name);
}
//m_params.append(g_token->name);
handleLinkedWord(this,m_params);
@@ -4683,7 +4653,7 @@ int DocParamList::parse(const QCString &cmdName)
if (tok==0) /* premature end of comment block */
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
- "argument of command %s",qPrint(cmdName));
+ "argument of command %s",qPrint(saveCmdName));
retval=0;
goto endparamlist;
}
@@ -4718,12 +4688,12 @@ int DocParamList::parseXml(const QCString &paramName)
if (m_type==DocParamSect::Param)
{
g_hasParamCommand=TRUE;
- checkArgumentName(g_token->name,TRUE);
+ checkArgumentName(g_token->name);
}
else if (m_type==DocParamSect::RetVal)
{
g_hasReturnCommand=TRUE;
- checkArgumentName(g_token->name,FALSE);
+ checkRetvalName(g_token->name);
}
handleLinkedWord(this,m_params);
@@ -4881,7 +4851,7 @@ void DocPara::handleCite()
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("cite"));
return;
}
@@ -4913,7 +4883,7 @@ void DocPara::handleEmoji()
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("emoji"));
return;
}
@@ -4960,12 +4930,13 @@ int DocPara::handleXRefItem()
void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t)
{
- DBG(("handleIncludeOperator(%s)\n",qPrint(cmdName)));
+ QCString saveCmdName = cmdName;
+ DBG(("handleIncludeOperator(%s)\n",qPrint(saveCmdName)));
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return;
}
doctokenizerYYsetStatePattern();
@@ -4974,13 +4945,13 @@ void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
- "argument of command %s", qPrint(cmdName));
+ "argument of command %s", qPrint(saveCmdName));
return;
}
else if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
return;
}
DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
@@ -5046,7 +5017,7 @@ void DocPara::handleImage(const QCString &cmdName)
tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command with option",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command with option",
qPrint(saveCmdName));
return;
}
@@ -5054,7 +5025,7 @@ void DocPara::handleImage(const QCString &cmdName)
}
else
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
qPrint(saveCmdName));
return;
}
@@ -5069,7 +5040,7 @@ void DocPara::handleImage(const QCString &cmdName)
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(saveCmdName));
return;
}
@@ -5104,11 +5075,12 @@ void DocPara::handleImage(const QCString &cmdName)
template<class T>
void DocPara::handleFile(const QCString &cmdName)
{
+ QCString saveCmdName = cmdName;
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return;
}
doctokenizerYYsetStateFile();
@@ -5117,13 +5089,19 @@ void DocPara::handleFile(const QCString &cmdName)
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
return;
}
QCString name = g_token->name;
T *df = new T(this,name,g_context);
- m_children.append(df);
- df->parse();
+ if (df->parse())
+ {
+ m_children.append(df);
+ }
+ else
+ {
+ delete df;
+ }
}
void DocPara::handleVhdlFlow()
@@ -5135,11 +5113,12 @@ void DocPara::handleVhdlFlow()
void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
{
+ QCString saveCmdName = cmdName;
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return;
}
doctokenizerYYsetStateLink();
@@ -5147,7 +5126,7 @@ void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"%s as the argument of %s",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
return;
}
doctokenizerYYsetStatePara();
@@ -5162,12 +5141,13 @@ void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
void DocPara::handleRef(const QCString &cmdName)
{
- DBG(("handleRef(%s)\n",qPrint(cmdName)));
+ QCString saveCmdName = cmdName;
+ DBG(("handleRef(%s)\n",qPrint(saveCmdName)));
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return;
}
doctokenizerYYsetStateRef();
@@ -5176,7 +5156,7 @@ void DocPara::handleRef(const QCString &cmdName)
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
goto endref;
}
ref = new DocRef(this,g_token->name,g_context);
@@ -5189,6 +5169,7 @@ endref:
void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
{
DBG(("handleInclude(%s)\n",qPrint(cmdName)));
+ QCString saveCmdName = cmdName;
int tok=doctokenizerYYlex();
bool isBlock = false;
if (tok==TK_WORD && g_token->name=="{")
@@ -5229,8 +5210,8 @@ void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
}
else if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return;
}
doctokenizerYYsetStateFile();
@@ -5239,13 +5220,13 @@ void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
- "argument of command %s",qPrint(cmdName));
+ "argument of command %s",qPrint(saveCmdName));
return;
}
else if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
return;
}
QCString fileName = g_token->name;
@@ -5259,7 +5240,7 @@ void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"expected block identifier, but found token %s instead while parsing the %s command",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
return;
}
blockId = "["+g_token->name+"]";
@@ -5293,25 +5274,26 @@ void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
void DocPara::handleSection(const QCString &cmdName)
{
+ QCString saveCmdName = cmdName;
// get the argument of the section command.
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
- qPrint(cmdName));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
+ qPrint(saveCmdName));
return;
}
tok=doctokenizerYYlex();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
- "argument of command %s\n", qPrint(cmdName));
+ "argument of command %s\n", qPrint(saveCmdName));
return;
}
else if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
- tokToString(tok),qPrint(cmdName));
+ tokToString(tok),qPrint(saveCmdName));
return;
}
g_token->sectionId = g_token->name;
@@ -5400,7 +5382,7 @@ int DocPara::handleCommand(const QCString &cmdName, const int tok)
{
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));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Found unknown command '\\%s'",qPrint(cmdName));
break;
case CMD_EMPHASIS:
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
@@ -5946,9 +5928,15 @@ int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &ta
case HTML_STRIKE:
handleStyleEnter(this,m_children,DocStyleChange::Strike,&g_token->attribs);
break;
+ case HTML_DEL:
+ handleStyleEnter(this,m_children,DocStyleChange::Del,&g_token->attribs);
+ break;
case HTML_UNDERLINE:
handleStyleEnter(this,m_children,DocStyleChange::Underline,&g_token->attribs);
break;
+ case HTML_INS:
+ handleStyleEnter(this,m_children,DocStyleChange::Ins,&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
@@ -6361,9 +6349,15 @@ int DocPara::handleHtmlEndTag(const QCString &tagName)
case HTML_STRIKE:
handleStyleLeave(this,m_children,DocStyleChange::Strike,"strike");
break;
+ case HTML_DEL:
+ handleStyleLeave(this,m_children,DocStyleChange::Del,"del");
+ break;
case HTML_UNDERLINE:
handleStyleLeave(this,m_children,DocStyleChange::Underline,"u");
break;
+ case HTML_INS:
+ handleStyleLeave(this,m_children,DocStyleChange::Ins,"ins");
+ break;
case HTML_CODE:
handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
break;
@@ -6886,55 +6880,56 @@ int DocSection::parse()
//printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel);
- if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1)
+ while (true)
{
- // then parse any number of nested sections
- while (retval==RetVal_Subsection) // more sections follow
+ if (retval==RetVal_Subsection && m_level<=Doxygen::subpageNestingLevel+1)
{
- //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
- DocSection *s=new DocSection(this,
- QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
- m_children.append(s);
- retval = s->parse();
+ // then parse any number of nested sections
+ while (retval==RetVal_Subsection) // more sections follow
+ {
+ //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
+ DocSection *s=new DocSection(this,
+ QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ break;
}
- }
- else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2)
- {
- // then parse any number of nested sections
- while (retval==RetVal_Subsubsection) // more sections follow
+ else if (retval==RetVal_Subsubsection && m_level<=Doxygen::subpageNestingLevel+2)
{
- //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
- DocSection *s=new DocSection(this,
- QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
- m_children.append(s);
- retval = s->parse();
+ if ((m_level<=1+Doxygen::subpageNestingLevel) && !QString(g_token->sectionId).startsWith("autotoc_md"))
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected subsubsection command found inside %s!",sectionLevelToName[m_level]);
+ // then parse any number of nested sections
+ while (retval==RetVal_Subsubsection) // more sections follow
+ {
+ //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
+ DocSection *s=new DocSection(this,
+ QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ if (!(m_level<Doxygen::subpageNestingLevel+2 && retval == RetVal_Subsection)) break;
}
- }
- else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3))
- {
- // then parse any number of nested sections
- while (retval==RetVal_Paragraph) // more sections follow
+ else if (retval==RetVal_Paragraph && m_level<=QMIN(5,Doxygen::subpageNestingLevel+3))
+ {
+ if ((m_level<=2+Doxygen::subpageNestingLevel) && !QString(g_token->sectionId).startsWith("autotoc_md"))
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected paragraph command found inside %s!",sectionLevelToName[m_level]);
+ // then parse any number of nested sections
+ while (retval==RetVal_Paragraph) // more sections follow
+ {
+ //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
+ DocSection *s=new DocSection(this,
+ QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ if (!(m_level<Doxygen::subpageNestingLevel+3 && (retval == RetVal_Subsection || retval == RetVal_Subsubsection))) break;
+ }
+ else
{
- //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
- DocSection *s=new DocSection(this,
- QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
- m_children.append(s);
- retval = s->parse();
+ break;
}
}
- else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) ||
- (m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph)
- )
- {
- int level = (retval==RetVal_Subsubsection) ? 3 : 4;
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected %s "
- "command found inside %s!",
- sectionLevelToName[level],sectionLevelToName[m_level]);
- retval=0; // stop parsing
- }
- else
- {
- }
INTERNAL_ASSERT(retval==0 ||
retval==RetVal_Section ||
@@ -7041,7 +7036,7 @@ void DocText::parse()
m_children.append(new DocSymbol(this,DocSymbol::Sym_Equal));
break;
default:
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command `%s' found",
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command '%s' found",
qPrint(g_token->name));
break;
}
@@ -7087,21 +7082,96 @@ void DocRoot::parse()
{
delete par;
}
- if (retval==TK_LISTITEM)
+ if (retval==RetVal_Paragraph)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
+ if (!QString(g_token->sectionId).startsWith("autotoc_md"))
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"found paragraph command outside of subsubsection context!");
+ while (retval==RetVal_Paragraph)
+ {
+ if (!g_token->sectionId.isEmpty())
+ {
+ SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
+ if (sec)
+ {
+ DocSection *s=new DocSection(this,
+ QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid paragraph id '%s'; ignoring paragraph",qPrint(g_token->sectionId));
+ retval = 0;
+ }
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing id for paragraph; ignoring paragraph");
+ retval = 0;
+ }
+ }
}
- else if (retval==RetVal_Subsection)
+ if (retval==RetVal_Subsubsection)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsection command outside of section context!");
+ if (!(QString(g_token->sectionId).startsWith("autotoc_md")))
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsubsection command outside of subsection context!");
+ while (retval==RetVal_Subsubsection)
+ {
+ if (!g_token->sectionId.isEmpty())
+ {
+ SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
+ if (sec)
+ {
+ DocSection *s=new DocSection(this,
+ QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid subsubsection id '%s'; ignoring subsubsection",qPrint(g_token->sectionId));
+ retval = 0;
+ }
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing id for subsubsection; ignoring subsubsection");
+ retval = 0;
+ }
+ }
}
- else if (retval==RetVal_Subsubsection)
+ if (retval==RetVal_Subsection)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsubsection command outside of subsection context!");
+ if (!(QString(g_token->sectionId).startsWith("autotoc_md")))
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsection command outside of section context!");
+ while (retval==RetVal_Subsection)
+ {
+ if (!g_token->sectionId.isEmpty())
+ {
+ SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
+ if (sec)
+ {
+ DocSection *s=new DocSection(this,
+ QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid subsection id '%s'; ignoring subsection",qPrint(g_token->sectionId));
+ retval = 0;
+ }
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing id for subsection; ignoring subsection");
+ retval = 0;
+ }
+ }
}
- else if (retval==RetVal_Paragraph)
+ if (retval==TK_LISTITEM)
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"found paragraph command outside of subsubsection context!");
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
}
if (retval==RetVal_Internal)
{
@@ -7116,17 +7186,25 @@ void DocRoot::parse()
// then parse any number of level1 sections
while (retval==RetVal_Section)
{
- SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
- if (sec)
+ if (!g_token->sectionId.isEmpty())
{
- DocSection *s=new DocSection(this,
- QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
- m_children.append(s);
- retval = s->parse();
+ SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
+ if (sec)
+ {
+ DocSection *s=new DocSection(this,
+ QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
+ m_children.append(s);
+ retval = s->parse();
+ }
+ else
+ {
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid section id '%s'; ignoring section",qPrint(g_token->sectionId));
+ retval = 0;
+ }
}
else
{
- warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid section id `%s'; ignoring section",qPrint(g_token->sectionId));
+ warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing id for section; ignoring section");
retval = 0;
}
}
@@ -7616,6 +7694,8 @@ DocRoot *validatingParseDoc(const char *fileName,int startLine,
g_exampleName = exampleName;
g_hasParamCommand = FALSE;
g_hasReturnCommand = FALSE;
+ g_retvalsFound.setAutoDelete(FALSE);
+ g_retvalsFound.clear();
g_paramsFound.setAutoDelete(FALSE);
g_paramsFound.clear();
g_sectionDict = 0; //sections;
@@ -7686,6 +7766,8 @@ DocText *validatingParseText(const char *input)
g_exampleName = "";
g_hasParamCommand = FALSE;
g_hasReturnCommand = FALSE;
+ g_retvalsFound.setAutoDelete(FALSE);
+ g_retvalsFound.clear();
g_paramsFound.setAutoDelete(FALSE);
g_paramsFound.clear();
g_searchUrl="";
diff --git a/src/docparser.h b/src/docparser.h
index ef01089..e608d8f 100644
--- a/src/docparser.h
+++ b/src/docparser.h
@@ -141,7 +141,8 @@ class DocNode
Kind_VhdlFlow = 50,
Kind_ParBlock = 51,
Kind_DiaFile = 52,
- Kind_Emoji = 53
+ Kind_Emoji = 53,
+ Kind_Sep = 54
};
/*! Creates a new node */
DocNode() : m_parent(0), m_insidePre(FALSE) {}
@@ -382,7 +383,9 @@ class DocStyleChange : public DocNode
Span = (1<<8),
Div = (1<<9),
Strike = (1<<10),
- Underline = (1<<11)
+ Underline = (1<<11),
+ Del = (1<<12),
+ Ins = (1<<13)
};
DocStyleChange(DocNode *parent,uint position,Style s,bool enable,
@@ -516,6 +519,19 @@ class DocWhiteSpace : public DocNode
QCString m_chars;
};
+/** Node representing a separator */
+class DocSeparator : public DocNode
+{
+ public:
+ DocSeparator(DocNode *parent,const QCString &chars) :
+ m_chars(chars) { m_parent = parent; }
+ Kind kind() const { return Kind_Sep; }
+ QCString chars() const { return m_chars; }
+ void accept(DocVisitor *v) { }
+ private:
+ QCString m_chars;
+};
+
/** Node representing a verbatim, unparsed text fragment */
class DocVerbatim : public DocNode
{
@@ -694,24 +710,6 @@ class DocIndexEntry : public DocNode
//-----------------------------------------------------------------------
-/** Node representing a copy of documentation block. */
-class DocCopy : public DocNode
-{
- public:
- DocCopy(DocNode *parent,const QCString &link,bool copyBrief,bool copyDetails)
- : m_link(link),
- m_copyBrief(copyBrief), m_copyDetails(copyDetails) { m_parent = parent; }
- Kind kind() const { return Kind_Copy; }
- QCString link() const { return m_link; }
- void accept(DocVisitor * /*v*/) { /*CompAccept<DocCopy>::accept(this,v);*/ }
- void parse(QList<DocNode> &children);
-
- private:
- QCString m_link;
- bool m_copyBrief;
- bool m_copyDetails;
-};
-
/** Node representing an auto List */
class DocAutoList : public CompAccept<DocAutoList>
{
@@ -816,7 +814,7 @@ class DocDotFile : public CompAccept<DocDotFile>
{
public:
DocDotFile(DocNode *parent,const QCString &name,const QCString &context);
- void parse();
+ bool parse();
Kind kind() const { return Kind_DotFile; }
QCString name() const { return m_name; }
QCString file() const { return m_file; }
@@ -839,7 +837,7 @@ class DocMscFile : public CompAccept<DocMscFile>
{
public:
DocMscFile(DocNode *parent,const QCString &name,const QCString &context);
- void parse();
+ bool parse();
Kind kind() const { return Kind_MscFile; }
QCString name() const { return m_name; }
QCString file() const { return m_file; }
@@ -862,7 +860,7 @@ class DocDiaFile : public CompAccept<DocDiaFile>
{
public:
DocDiaFile(DocNode *parent,const QCString &name,const QCString &context);
- void parse();
+ bool parse();
Kind kind() const { return Kind_DiaFile; }
QCString name() const { return m_name; }
QCString file() const { return m_file; }
diff --git a/src/doctokenizer.l b/src/doctokenizer.l
index 5346c0a..194327c 100644
--- a/src/doctokenizer.l
+++ b/src/doctokenizer.l
@@ -157,7 +157,7 @@ static int computeIndent(const char *str,int length)
static void processSection()
{
- //printf("%s: found section/anchor with name `%s'\n",g_fileName.data(),g_secLabel.data());
+ //printf("%s: found section/anchor with name '%s'\n",g_fileName.data(),g_secLabel.data());
QCString file;
if (g_memberGroup)
{
@@ -405,8 +405,8 @@ 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"|"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"
+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"|"del"|"ins"
+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"|"DEL"|"INS"
HTMLKEYW {HTMLKEYL}|{HTMLKEYU}
REFWORD2_PRE ("#"|"::")?((({ID}{TEMPLPART}?)|{ANONNS})("."|"#"|"::"|"-"|"/"))*({ID}{TEMPLPART}?(":")?)
REFWORD2 {REFWORD2_PRE}{FUNCARG2}?
@@ -1151,7 +1151,7 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
g_token->name = g_token->name.left((int)yyleng-2);
return TK_WORD;
}
-<St_Param>({PHPTYPE}{BLANK}*"|"{BLANK}*)*{PHPTYPE}{WS}+("&")?"$"{LABELID} {
+<St_Param>({PHPTYPE}{BLANK}*("["{BLANK}*"]")*{BLANK}*"|"{BLANK}*)*{PHPTYPE}{BLANK}*("["{BLANK}*"]")*{WS}+("&")?"$"{LABELID} {
QCString params = yytext;
int j = params.find('&');
int i = params.find('$');
@@ -1343,7 +1343,7 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
BEGIN(St_Sections);
}
<St_SecTitle,St_SecLabel1,St_SecLabel2>. {
- warn(g_fileName,yylineno,"Unexpected character `%s' while looking for section label or title",yytext);
+ warn(g_fileName,yylineno,"Unexpected character '%s' while looking for section label or title",yytext);
}
<St_Snippet>[^\n]+ |
@@ -1358,12 +1358,12 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV}
warn(g_fileName,yylineno,"Unexpected new line character");
}
<*>[\\@<>&$#%~"=] { /* unescaped special character */
- //warn(g_fileName,yylineno,"Unexpected character `%s', assuming command \\%s was meant.",yytext,yytext);
+ //warn(g_fileName,yylineno,"Unexpected character '%s', assuming command \\%s was meant.",yytext,yytext);
g_token->name = yytext;
return TK_COMMAND_SEL();
}
<*>. {
- warn(g_fileName,yylineno,"Unexpected character `%s'",yytext);
+ warn(g_fileName,yylineno,"Unexpected character '%s'",yytext);
}
%%
@@ -1375,7 +1375,7 @@ void doctokenizerYYFindSections(const char *input,Definition *d,
if (input==0) return;
printlex(yy_flex_debug, TRUE, __FILE__, fileName);
g_inputString = input;
- //printf("parsing --->`%s'<---\n",input);
+ //printf("parsing --->'%s'<---\n",input);
g_inputPos = 0;
g_definition = d;
g_memberGroup = mg;
diff --git a/src/docvisitor.h b/src/docvisitor.h
index d2318c9..0a53595 100644
--- a/src/docvisitor.h
+++ b/src/docvisitor.h
@@ -79,7 +79,6 @@ class DocLinkedWord;
class DocParamSect;
class DocParamList;
class DocInternalRef;
-class DocCopy; // TODO: no longer generated => remove
class DocText;
class DocSimpleSectSep;
class DocHtmlBlockQuote;
@@ -187,8 +186,6 @@ class DocVisitor
virtual void visitPost(DocXRefItem *) = 0;
virtual void visitPre(DocInternalRef *) = 0;
virtual void visitPost(DocInternalRef *) = 0;
- virtual void visitPre(DocCopy *) = 0;
- virtual void visitPost(DocCopy *) = 0;
virtual void visitPre(DocText *) = 0;
virtual void visitPost(DocText *) = 0;
virtual void visitPre(DocHtmlBlockQuote *) = 0;
diff --git a/src/dot.cpp b/src/dot.cpp
index 5aca277..5cdf92c 100644
--- a/src/dot.cpp
+++ b/src/dot.cpp
@@ -1,13 +1,10 @@
/*****************************************************************************
*
- *
- *
- *
- * Copyright (C) 1997-2015 by Dimitri van Heesch.
+ * Copyright (C) 1997-2019 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby
- * granted. No representations are made about the suitability of this software
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
@@ -26,392 +23,47 @@
#include <qwaitcondition.h>
#include <qregexp.h>
+#include "config.h"
#include "dot.h"
-#include "doxygen.h"
-#include "message.h"
+#include "dotrunner.h"
+#include "dotfilepatcher.h"
#include "util.h"
-#include "config.h"
-#include "language.h"
-#include "defargs.h"
-#include "docparser.h"
-#include "debug.h"
-#include "pagedef.h"
#include "portable.h"
-#include "dirdef.h"
-#include "vhdldocgen.h"
+#include "message.h"
#include "ftextstream.h"
-#include "md5.h"
-#include "memberlist.h"
-#include "groupdef.h"
-#include "classlist.h"
-#include "filename.h"
-#include "namespacedef.h"
-#include "memberdef.h"
-#include "membergroup.h"
+#include "doxygen.h"
+#include "language.h"
+#include "index.h"
#define MAP_CMD "cmapx"
-//#define FONTNAME "Helvetica"
-#define FONTNAME getDotFontName()
-#define FONTSIZE getDotFontSize()
-
-//--------------------------------------------------------------------
-
-static const char svgZoomHeader[] =
-"<svg id=\"main\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" onload=\"init(evt)\">\n"
-"<style type=\"text/css\"><![CDATA[\n"
-".edge:hover path { stroke: red; }\n"
-".edge:hover polygon { stroke: red; fill: red; }\n"
-"]]></style>\n"
-"<script type=\"text/javascript\"><![CDATA[\n"
-"var edges = document.getElementsByTagName('g');\n"
-"if (edges && edges.length) {\n"
-" for (var i=0;i<edges.length;i++) {\n"
-" if (edges[i].id.substr(0,4)=='edge') {\n"
-" edges[i].setAttribute('class','edge');\n"
-" }\n"
-" }\n"
-"}\n"
-"]]></script>\n"
-" <defs>\n"
-" <circle id=\"rim\" cx=\"0\" cy=\"0\" r=\"7\"/>\n"
-" <circle id=\"rim2\" cx=\"0\" cy=\"0\" r=\"3.5\"/>\n"
-" <g id=\"zoomPlus\">\n"
-" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"zoomplus.mouseover\" end=\"zoomplus.mouseout\"/>\n"
-" </use>\n"
-" <path d=\"M-4,0h8M0,-4v8\" fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" pointer-events=\"none\"/>\n"
-" </g>\n"
-" <g id=\"zoomMin\">\n"
-" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"zoomminus.mouseover\" end=\"zoomminus.mouseout\"/>\n"
-" </use>\n"
-" <path d=\"M-4,0h8\" fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" pointer-events=\"none\"/>\n"
-" </g>\n"
-" <g id=\"dirArrow\">\n"
-" <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 id=\"resetDef\">\n"
-" <use xlink:href=\"#rim2\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"reset.mouseover\" end=\"reset.mouseout\"/>\n"
-" </use>\n"
-" </g>\n"
-" </defs>\n"
-"\n"
-"<script type=\"text/javascript\">\n"
-;
-
-static const char svgZoomFooter[] =
-// navigation panel
-" <g id=\"navigator\" transform=\"translate(0 0)\" fill=\"#404254\">\n"
-" <rect fill=\"#f2f5e9\" fill-opacity=\"0.5\" stroke=\"#606060\" stroke-width=\".5\" x=\"0\" y=\"0\" width=\"60\" height=\"60\"/>\n"
-// zoom in
-" <use id=\"zoomplus\" xlink:href=\"#zoomPlus\" x=\"17\" y=\"9\" onmousedown=\"handleZoom(evt,'in')\"/>\n"
-// zoom out
-" <use id=\"zoomminus\" xlink:href=\"#zoomMin\" x=\"42\" y=\"9\" onmousedown=\"handleZoom(evt,'out')\"/>\n"
-// reset zoom
-" <use id=\"reset\" xlink:href=\"#resetDef\" x=\"30\" y=\"36\" onmousedown=\"handleReset()\"/>\n"
-// arrow up
-" <g id=\"arrowUp\" xlink:href=\"#dirArrow\" transform=\"translate(30 24)\" onmousedown=\"handlePan(0,-1)\">\n"
-" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowUp.mouseover\" end=\"arrowUp.mouseout\"/>\n"
-" </use>\n"
-" <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"
-// arrow right
-" <g id=\"arrowRight\" xlink:href=\"#dirArrow\" transform=\"rotate(90) translate(36 -43)\" onmousedown=\"handlePan(1,0)\">\n"
-" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowRight.mouseover\" end=\"arrowRight.mouseout\"/>\n"
-" </use>\n"
-" <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"
-// arrow down
-" <g id=\"arrowDown\" xlink:href=\"#dirArrow\" transform=\"rotate(180) translate(-30 -48)\" onmousedown=\"handlePan(0,1)\">\n"
-" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowDown.mouseover\" end=\"arrowDown.mouseout\"/>\n"
-" </use>\n"
-" <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"
-// arrow left
-" <g id=\"arrowLeft\" xlink:href=\"#dirArrow\" transform=\"rotate(270) translate(-36 17)\" onmousedown=\"handlePan(-1,0)\">\n"
-" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
-" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowLeft.mouseover\" end=\"arrowLeft.mouseout\"/>\n"
-" </use>\n"
-" <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 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"
-" <rect id=\"button\" ry=\"5\" rx=\"5\" y=\"6\" x=\"6\" height=\"38\" width=\"38\"\n"
-" fill=\"#f2f5e9\" fill-opacity=\"0.5\" stroke=\"#606060\" stroke-width=\"1.0\"/>\n"
-" <path id=\"arrow\"\n"
-" d=\"M 11.500037,31.436501 C 11.940474,20.09759 22.043105,11.32322 32.158766,21.979434 L 37.068811,17.246167 C 37.068811,17.246167 37.088388,32 37.088388,32 L 22.160133,31.978069 C 22.160133,31.978069 26.997745,27.140456 26.997745,27.140456 C 18.528582,18.264221 13.291696,25.230495 11.500037,31.436501 z\"\n"
-" style=\"fill:#404040;\"/>\n"
-" </a>\n"
-" </g>\n"
-" </svg>\n"
-"</svg>\n"
-;
+static int DOT_NUM_THREADS; // will be initialized in initDot
//--------------------------------------------------------------------
-/*! mapping from protection levels to color names */
-static const char *normalEdgeColorMap[] =
-{
- "midnightblue", // Public
- "darkgreen", // Protected
- "firebrick4", // Private
- "darkorchid3", // "use" relation
- "grey75", // Undocumented
- "orange", // template relation
- "orange" // type constraint
-};
-
-static const char *normalArrowStyleMap[] =
-{
- "empty", // Public
- "empty", // Protected
- "empty", // Private
- "open", // "use" relation
- 0, // Undocumented
- 0 // template relation
-};
-
-static const char *normalEdgeStyleMap[] =
-{
- "solid", // inheritance
- "dashed" // usage
-};
-
-static const char *umlEdgeColorMap[] =
-{
- "midnightblue", // Public
- "darkgreen", // Protected
- "firebrick4", // Private
- "grey25", // "use" relation
- "grey75", // Undocumented
- "orange", // template relation
- "orange" // type constraint
-};
-
-static const char *umlArrowStyleMap[] =
-{
- "onormal", // Public
- "onormal", // Protected
- "onormal", // Private
- "odiamond", // "use" relation
- 0, // Undocumented
- 0 // template relation
-};
-
-static const char *umlEdgeStyleMap[] =
-{
- "solid", // inheritance
- "solid" // usage
-};
-
-/** Helper struct holding the properties of a edge in a dot graph. */
-struct EdgeProperties
-{
- const char * const *edgeColorMap;
- const char * const *arrowStyleMap;
- const char * const *edgeStyleMap;
-};
-
-static EdgeProperties normalEdgeProps =
-{
- normalEdgeColorMap, normalArrowStyleMap, normalEdgeStyleMap
-};
-
-static EdgeProperties umlEdgeProps =
+void initDot()
{
- umlEdgeColorMap, umlArrowStyleMap, umlEdgeStyleMap
-};
-
-
-static QCString convertLabel(const QCString &l);
-
-static QCString getDotFontName()
-{
- static QCString dotFontName = Config_getString(DOT_FONTNAME);
- if (dotFontName.isEmpty())
+ DotGraph::DOT_FONTNAME = Config_getString(DOT_FONTNAME);
+ if (DotGraph::DOT_FONTNAME.isEmpty())
{
- //dotFontName="FreeSans.ttf";
- dotFontName="Helvetica";
+ DotGraph::DOT_FONTNAME="Helvetica";
}
- return dotFontName;
-}
-static int getDotFontSize()
-{
- static int dotFontSize = Config_getInt(DOT_FONTSIZE);
- if (dotFontSize<4) dotFontSize=4;
- return dotFontSize;
-}
+ DotGraph::DOT_FONTSIZE = Config_getInt(DOT_FONTSIZE);
+ if (DotGraph::DOT_FONTSIZE<4) DotGraph::DOT_FONTSIZE=4;
-static void writeGraphHeader(FTextStream &t,const QCString &title=QCString())
-{
- static bool interactiveSVG = Config_getBool(INTERACTIVE_SVG);
- t << "digraph ";
- if (title.isEmpty())
- {
- t << "\"Dot Graph\"";
- }
- else
- {
- t << "\"" << convertLabel(title) << "\"";
- }
- t << endl << "{" << endl;
- if (interactiveSVG) // insert a comment to force regeneration when this
- // option is toggled
- {
- t << " // INTERACTIVE_SVG=YES\n";
- }
- t << " // LATEX_PDF_SIZE\n"; // write placeholder for LaTeX PDF bounding box size repacement
- if (Config_getBool(DOT_TRANSPARENT))
- {
- t << " bgcolor=\"transparent\";" << endl;
- }
- t << " edge [fontname=\"" << FONTNAME << "\","
- "fontsize=\"" << FONTSIZE << "\","
- "labelfontname=\"" << FONTNAME << "\","
- "labelfontsize=\"" << FONTSIZE << "\"];\n";
- t << " node [fontname=\"" << FONTNAME << "\","
- "fontsize=\"" << FONTSIZE << "\",shape=record];\n";
-}
+ DOT_NUM_THREADS = Config_getInt(DOT_NUM_THREADS);
+ if (DOT_NUM_THREADS > 32) DOT_NUM_THREADS = 32;
+ if (DOT_NUM_THREADS <= 0) DOT_NUM_THREADS = QMAX(2,QThread::idealThreadCount()+1);
-static void writeGraphFooter(FTextStream &t)
-{
- t << "}" << endl;
-}
+ // these are copied to be sure to be thread save
+ DotRunner::DOT_CLEANUP = Config_getBool(DOT_CLEANUP);
+ DotRunner::DOT_MULTI_TARGETS = Config_getBool(DOT_MULTI_TARGETS);
+ DotRunner::DOT_EXE.init(Config_getString(DOT_PATH) + "dot");
-static QCString replaceRef(const QCString &buf,const QCString relPath,
- bool urlOnly,const QCString &context,const QCString &target=QCString())
-{
- // search for href="...", store ... part in link
- QCString href = "href";
- //bool isXLink=FALSE;
- int len = 6;
- int indexS = buf.find("href=\""), indexE;
- bool setTarget = FALSE;
- if (indexS>5 && buf.find("xlink:href=\"")!=-1) // XLink href (for SVG)
- {
- indexS-=6;
- len+=6;
- href.prepend("xlink:");
- //isXLink=TRUE;
- }
- if (indexS>=0 && (indexE=buf.find('"',indexS+len))!=-1)
- {
- QCString link = buf.mid(indexS+len,indexE-indexS-len);
- QCString result;
- if (urlOnly) // for user defined dot graphs
- {
- if (link.left(5)=="\\ref " || link.left(5)=="@ref ") // \ref url
- {
- result=href+"=\"";
- // fake ref node to resolve the url
- DocRef *df = new DocRef( (DocNode*) 0, link.mid(5), context );
- result+=externalRef(relPath,df->ref(),TRUE);
- if (!df->file().isEmpty())
- result += df->file().data() + Doxygen::htmlFileExtension;
- if (!df->anchor().isEmpty())
- result += "#" + df->anchor();
- delete df;
- result += "\"";
- }
- else
- {
- result = href+"=\"" + link + "\"";
- }
- }
- else // ref$url (external ref via tag file), or $url (local ref)
- {
- int marker = link.find('$');
- if (marker!=-1)
- {
- QCString ref = link.left(marker);
- QCString url = link.mid(marker+1);
- if (!ref.isEmpty())
- {
- result = externalLinkTarget();
- if (result != "") setTarget = TRUE;
- }
- result+= href+"=\"";
- result+=externalRef(relPath,ref,TRUE);
- result+= url + "\"";
- }
- else // should not happen, but handle properly anyway
- {
- result = href+"=\"" + link + "\"";
- }
- }
- if (!target.isEmpty() && !setTarget)
- {
- result+=" target=\""+target+"\"";
- }
- QCString leftPart = buf.left(indexS);
- QCString rightPart = buf.mid(indexE+1);
- return leftPart + result + rightPart;
- }
- else
- {
- return buf;
- }
+ DotGraph::IMG_EXT = getDotImageExtension();
}
-/*! converts the rectangles in a client site image map into a stream
- * \param t the stream to which the result is written.
- * \param mapName the name of the map file.
- * \param relPath the relative path to the root of the output directory
- * (used in case CREATE_SUBDIRS is enabled).
- * \param urlOnly if FALSE the url field in the map contains an external
- * references followed by a $ and then the URL.
- * \param context the context (file, class, or namespace) in which the
- * map file was found
- * \returns TRUE if successful.
- */
-static bool convertMapFile(FTextStream &t,const char *mapName,
- const QCString relPath, bool urlOnly=FALSE,
- const QCString &context=QCString())
-{
- QFile f(mapName);
- if (!f.open(IO_ReadOnly))
- {
- err("problems opening map file %s for inclusion in the docs!\n"
- "If you installed Graphviz/dot after a previous failing run, \n"
- "try deleting the output directory and rerun doxygen.\n",mapName);
- return FALSE;
- }
- const int maxLineLen=10240;
- while (!f.atEnd()) // foreach line
- {
- QCString buf(maxLineLen);
- int numBytes = f.readLine(buf.rawData(),maxLineLen);
- if (numBytes>0)
- {
- buf.resize(numBytes+1);
-
- if (buf.left(5)=="<area")
- {
- QCString replBuf = replaceRef(buf,relPath,urlOnly,context);
- // strip id="..." from replBuf since the id's are not needed and not unique.
- int indexS = replBuf.find("id=\""), indexE;
- if (indexS>0 && (indexE=replBuf.find('"',indexS+4))!=-1)
- {
- t << replBuf.left(indexS-1) << replBuf.right(replBuf.length() - indexE - 1);
- }
- else
- {
- t << replBuf;
- }
- }
- }
- }
- return TRUE;
-}
static QCString g_dotFontPath;
@@ -450,147 +102,6 @@ static void unsetDotFontPath()
g_dotFontPath="";
}
-static bool resetPDFSize(const int width,const int height, const char *base)
-{
- QString tmpName = QString::fromUtf8(QCString(base)+".tmp");
- QString patchFile = QString::fromUtf8(QCString(base)+".dot");
- if (!QDir::current().rename(patchFile,tmpName))
- {
- err("Failed to rename file %s to %s!\n",patchFile.data(),tmpName.data());
- return FALSE;
- }
- QFile fi(tmpName);
- QFile fo(patchFile);
- if (!fi.open(IO_ReadOnly))
- {
- err("problem opening file %s for patching!\n",tmpName.data());
- QDir::current().rename(tmpName,patchFile);
- return FALSE;
- }
- if (!fo.open(IO_WriteOnly))
- {
- err("problem opening file %s for patching!\n",patchFile.data());
- QDir::current().rename(tmpName,patchFile);
- fi.close();
- return FALSE;
- }
- FTextStream t(&fo);
- const int maxLineLen=100*1024;
- while (!fi.atEnd()) // foreach line
- {
- QCString line(maxLineLen);
- int numBytes = fi.readLine(line.rawData(),maxLineLen);
- if (numBytes<=0)
- {
- break;
- }
- line.resize(numBytes+1);
- if (line.find("LATEX_PDF_SIZE") != -1)
- {
- double scale = (width > height ? width : height)/double(MAX_LATEX_GRAPH_INCH);
- t << " size=\""<<width/scale << "," <<height/scale <<"\";\n";
- }
- else
- t << line;
- }
- fi.close();
- fo.close();
- // remove temporary file
- QDir::current().remove(tmpName);
- return TRUE;
-}
-static bool readBoundingBox(const char *fileName,int *width,int *height,bool isEps)
-{
- QCString bb = isEps ? QCString("%%PageBoundingBox:") : QCString("/MediaBox [");
- QFile f(fileName);
- if (!f.open(IO_ReadOnly|IO_Raw))
- {
- //printf("readBoundingBox: could not open %s\n",fileName);
- return FALSE;
- }
- const int maxLineLen=1024;
- char buf[maxLineLen];
- while (!f.atEnd())
- {
- int numBytes = f.readLine(buf,maxLineLen-1); // read line
- if (numBytes>0)
- {
- buf[numBytes]='\0';
- const char *p = strstr(buf,bb);
- if (p) // found PageBoundingBox or /MediaBox string
- {
- int x,y;
- if (sscanf(p+bb.length(),"%d %d %d %d",&x,&y,width,height)!=4)
- {
- //printf("readBoundingBox sscanf fail\n");
- return FALSE;
- }
- return TRUE;
- }
- }
- else // read error!
- {
- //printf("Read error %d!\n",numBytes);
- return FALSE;
- }
- }
- err("Failed to extract bounding box from generated diagram file %s\n",fileName);
- return FALSE;
-}
-
-static bool writeVecGfxFigure(FTextStream &out,const QCString &baseName,
- const QCString &figureName)
-{
- int width=400,height=550;
- static bool usePdfLatex = Config_getBool(USE_PDFLATEX);
- if (usePdfLatex)
- {
- if (!readBoundingBox(figureName+".pdf",&width,&height,FALSE))
- {
- //printf("writeVecGfxFigure()=0\n");
- return FALSE;
- }
- }
- else
- {
- if (!readBoundingBox(figureName+".eps",&width,&height,TRUE))
- {
- //printf("writeVecGfxFigure()=0\n");
- return FALSE;
- }
- }
- //printf("Got PDF/EPS size %d,%d\n",width,height);
- int maxWidth = 350; /* approx. page width in points, excl. margins */
- int maxHeight = 550; /* approx. page height in points, excl. margins */
- out << "\\nopagebreak\n"
- "\\begin{figure}[H]\n"
- "\\begin{center}\n"
- "\\leavevmode\n";
- if (width>maxWidth || height>maxHeight) // figure too big for page
- {
- // c*width/maxWidth > c*height/maxHeight, where c=maxWidth*maxHeight>0
- if (width*maxHeight>height*maxWidth)
- {
- out << "\\includegraphics[width=" << maxWidth << "pt]";
- }
- else
- {
- out << "\\includegraphics[height=" << maxHeight << "pt]";
- }
- }
- else
- {
- out << "\\includegraphics[width=" << width << "pt]";
- }
-
- out << "{" << baseName << "}\n"
- "\\end{center}\n"
- "\\end{figure}\n";
-
- //printf("writeVecGfxFigure()=1\n");
- return TRUE;
-}
-
// extract size from a dot generated SVG file
static bool readSVGSize(const QCString &fileName,int *width,int *height)
{
@@ -638,8 +149,8 @@ static void writeSVGNotSupported(FTextStream &out)
// check if a reference to a SVG figure can be written and does so if possible.
// return FALSE if not possible (for instance because the SVG file is not yet generated).
-static bool writeSVGFigureLink(FTextStream &out,const QCString &relPath,
- const QCString &baseName,const QCString &absImgName)
+bool writeSVGFigureLink(FTextStream &out,const QCString &relPath,
+ const QCString &baseName,const QCString &absImgName)
{
int width=600,height=600;
if (!readSVGSize(absImgName,&width,&height))
@@ -680,593 +191,6 @@ static bool writeSVGFigureLink(FTextStream &out,const QCString &relPath,
return TRUE;
}
-// since dot silently reproduces the input file when it does not
-// support the PNG format, we need to check the result.
-static void checkDotResult(const char *imgExt, const char *imgName)
-{
- if (qstrcmp(imgExt,"png")==0)
- {
- FILE *f = portable_fopen(imgName,"rb");
- if (f)
- {
- char data[4];
- if (fread(data,1,4,f)==4)
- {
- if (!(data[1]=='P' && data[2]=='N' && data[3]=='G'))
- {
- err("Image `%s' produced by dot is not a valid PNG!\n"
- "You should either select a different format "
- "(DOT_IMAGE_FORMAT in the config file) or install a more "
- "recent version of graphviz (1.7+)\n",imgName
- );
- }
- }
- else
- {
- err("Could not read image `%s' generated by dot!\n",imgName);
- }
- fclose(f);
- }
- else
- {
- err("Could not open image `%s' generated by dot!\n",imgName);
- }
- }
-}
-
-static bool insertMapFile(FTextStream &out,const QCString &mapFile,
- const QCString &relPath,const QCString &mapLabel)
-{
- QFileInfo fi(mapFile);
- if (fi.exists() && fi.size()>0) // reuse existing map file
- {
- QGString tmpstr;
- FTextStream tmpout(&tmpstr);
- convertMapFile(tmpout,mapFile,relPath,FALSE);
- if (!tmpstr.isEmpty())
- {
- out << "<map name=\"" << mapLabel << "\" id=\"" << mapLabel << "\">" << endl;
- out << tmpstr;
- out << "</map>" << endl;
- }
- return TRUE;
- }
- return FALSE; // no map file yet, need to generate it
-}
-
-static void removeDotGraph(const QCString &dotName)
-{
- static bool dotCleanUp = Config_getBool(DOT_CLEANUP);
- if (dotCleanUp)
- {
- QDir d;
- d.remove(dotName);
- }
-}
-
-
-
-/*! Checks if a file "baseName".md5 exists. If so the contents
- * are compared with \a md5. If equal FALSE is returned. If the .md5
- * file does not exist or its contents are not equal to \a md5,
- * a new .md5 is generated with the \a md5 string as contents.
- */
-static bool checkAndUpdateMd5Signature(const QCString &baseName,
- const QCString &md5)
-{
- QFile f(baseName+".md5");
- if (f.open(IO_ReadOnly))
- {
- // read checksum
- QCString md5stored(33);
- int bytesRead=f.readBlock(md5stored.rawData(),32);
- md5stored[32]='\0';
- // compare checksum
- if (bytesRead==32 && md5==md5stored)
- {
- // bail out if equal
- return FALSE;
- }
- }
- f.close();
- // create checksum file
- if (f.open(IO_WriteOnly))
- {
- f.writeBlock(md5.data(),32);
- f.close();
- }
- return TRUE;
-}
-
-static bool checkDeliverables(const QCString &file1,
- const QCString &file2=QCString())
-{
- bool file1Ok = TRUE;
- bool file2Ok = TRUE;
- if (!file1.isEmpty())
- {
- QFileInfo fi(file1);
- file1Ok = (fi.exists() && fi.size()>0);
- }
- if (!file2.isEmpty())
- {
- QFileInfo fi(file2);
- file2Ok = (fi.exists() && fi.size()>0);
- }
- return file1Ok && file2Ok;
-}
-
-//--------------------------------------------------------------------
-
-inline int DotNode::findParent( DotNode *n )
-{
- if ( !m_parents ) return -1;
- return m_parents->find(n);
-}
-
-//--------------------------------------------------------------------
-
-int DotNodeList::compareValues(const DotNode *n1,const DotNode *n2) const
-{
- return qstricmp(n1->m_label,n2->m_label);
-}
-
-//--------------------------------------------------------------------
-
-DotRunner::DotRunner(const QCString &file,const QCString &path,
- bool checkResult,const QCString &imageName)
- : m_dotExe(Config_getString(DOT_PATH)+"dot"),
- m_file(file), m_path(path),
- m_checkResult(checkResult), m_imageName(imageName),
- m_imgExt(getDotImageExtension())
-{
- static bool dotCleanUp = Config_getBool(DOT_CLEANUP);
- static bool dotMultiTargets = Config_getBool(DOT_MULTI_TARGETS);
- m_cleanUp = dotCleanUp;
- m_multiTargets = dotMultiTargets;
- m_jobs.setAutoDelete(TRUE);
-}
-
-void DotRunner::addJob(const char *format,const char *output, const char *base)
-{
- QCString args = QCString("-T")+format+" -o \""+output+"\"";
- m_jobs.append(new DotConstString(args, base));
-}
-
-void DotRunner::addPostProcessing(const char *cmd,const char *args)
-{
- m_postCmd.set(cmd);
- m_postArgs.set(args);
-}
-
-bool DotRunner::run()
-{
- int exitCode=0;
- int width=0,height=0;
-
- QCString dotArgs;
- QListIterator<DotConstString> li(m_jobs);
- DotConstString *s;
- if (m_multiTargets)
- {
- dotArgs=QCString("\"")+m_file.data()+"\"";
- for (li.toFirst();(s=li.current());++li)
- {
- dotArgs+=' ';
- dotArgs+=s->data();
- }
- if ((exitCode=portable_system(m_dotExe.data(),dotArgs,FALSE))!=0) goto error;
- dotArgs=QCString("\"")+m_file.data()+"\"";
- bool redo = FALSE;
- for (li.toFirst();(s=li.current());++li)
- {
- if (s->pdfData())
- {
- if (!readBoundingBox(QCString(s->pdfData())+".pdf",&width,&height,FALSE)) goto error;
- if ((width > MAX_LATEX_GRAPH_SIZE) || (height > MAX_LATEX_GRAPH_SIZE))
- {
- if (!resetPDFSize(width,height,s->pdfData())) goto error;
- dotArgs+=' ';
- dotArgs+=s->data();
- redo = TRUE;
- }
- }
- }
- if (redo)
- {
- if ((exitCode=portable_system(m_dotExe.data(),dotArgs,FALSE))!=0) goto error;
- }
- }
- else
- {
- for (li.toFirst();(s=li.current());++li)
- {
- dotArgs=QCString("\"")+m_file.data()+"\" "+s->data();
- if ((exitCode=portable_system(m_dotExe.data(),dotArgs,FALSE))!=0) goto error;
- if (s->pdfData())
- {
- if (!readBoundingBox(QCString(s->pdfData())+".pdf",&width,&height,FALSE)) goto error;
- if ((width > MAX_LATEX_GRAPH_SIZE) || (height > MAX_LATEX_GRAPH_SIZE))
- {
- if (!resetPDFSize(width,height,s->pdfData())) goto error;
- if ((exitCode=portable_system(m_dotExe.data(),dotArgs,FALSE))!=0) goto error;
- }
- }
- }
- }
- if (!m_postCmd.isEmpty() && portable_system(m_postCmd.data(),m_postArgs.data())!=0)
- {
- err("Problems running '%s' as a post-processing step for dot output\n",m_postCmd.data());
- return FALSE;
- }
- if (m_checkResult)
- {
- checkDotResult(m_imgExt.data(),m_imageName.data());
- }
- if (m_cleanUp)
- {
- //printf("removing dot file %s\n",m_file.data());
- //QDir(path).remove(file);
- m_cleanupItem.file.set(m_file.data());
- m_cleanupItem.path.set(m_path.data());
- }
- return TRUE;
-error:
- err("Problems running dot: exit code=%d, command='%s', arguments='%s'\n",
- exitCode,m_dotExe.data(),dotArgs.data());
- return FALSE;
-}
-
-//--------------------------------------------------------------------
-
-DotFilePatcher::DotFilePatcher(const char *patchFile)
- : m_patchFile(patchFile)
-{
- m_maps.setAutoDelete(TRUE);
-}
-
-QCString DotFilePatcher::file() const
-{
- return m_patchFile;
-}
-
-int DotFilePatcher::addMap(const QCString &mapFile,const QCString &relPath,
- bool urlOnly,const QCString &context,const QCString &label)
-{
- int id = m_maps.count();
- Map *map = new Map;
- map->mapFile = mapFile;
- map->relPath = relPath;
- map->urlOnly = urlOnly;
- map->context = context;
- map->label = label;
- map->zoomable = FALSE;
- map->graphId = -1;
- m_maps.append(map);
- return id;
-}
-
-int DotFilePatcher::addFigure(const QCString &baseName,
- const QCString &figureName,bool heightCheck)
-{
- int id = m_maps.count();
- Map *map = new Map;
- map->mapFile = figureName;
- map->urlOnly = heightCheck;
- map->label = baseName;
- map->zoomable = FALSE;
- map->graphId = -1;
- m_maps.append(map);
- return id;
-}
-
-int DotFilePatcher::addSVGConversion(const QCString &relPath,bool urlOnly,
- const QCString &context,bool zoomable,
- int graphId)
-{
- int id = m_maps.count();
- Map *map = new Map;
- map->relPath = relPath;
- map->urlOnly = urlOnly;
- map->context = context;
- map->zoomable = zoomable;
- map->graphId = graphId;
- m_maps.append(map);
- return id;
-}
-
-int DotFilePatcher::addSVGObject(const QCString &baseName,
- const QCString &absImgName,
- const QCString &relPath)
-{
- int id = m_maps.count();
- Map *map = new Map;
- map->mapFile = absImgName;
- map->relPath = relPath;
- map->label = baseName;
- map->zoomable = FALSE;
- map->graphId = -1;
- m_maps.append(map);
- return id;
-}
-
-bool DotFilePatcher::run()
-{
- //printf("DotFilePatcher::run(): %s\n",m_patchFile.data());
- static bool interactiveSVG = Config_getBool(INTERACTIVE_SVG);
- bool isSVGFile = m_patchFile.right(4)==".svg";
- int graphId = -1;
- QCString relPath;
- if (isSVGFile)
- {
- Map *map = m_maps.at(0); // there is only one 'map' for a SVG file
- interactiveSVG = interactiveSVG && map->zoomable;
- graphId = map->graphId;
- relPath = map->relPath;
- //printf("DotFilePatcher::addSVGConversion: file=%s zoomable=%d\n",
- // m_patchFile.data(),map->zoomable);
- }
- QString tmpName = QString::fromUtf8(m_patchFile+".tmp");
- QString patchFile = QString::fromUtf8(m_patchFile);
- if (!QDir::current().rename(patchFile,tmpName))
- {
- err("Failed to rename file %s to %s!\n",m_patchFile.data(),tmpName.data());
- return FALSE;
- }
- QFile fi(tmpName);
- QFile fo(patchFile);
- if (!fi.open(IO_ReadOnly))
- {
- err("problem opening file %s for patching!\n",tmpName.data());
- QDir::current().rename(tmpName,patchFile);
- return FALSE;
- }
- if (!fo.open(IO_WriteOnly))
- {
- err("problem opening file %s for patching!\n",m_patchFile.data());
- QDir::current().rename(tmpName,patchFile);
- return FALSE;
- }
- FTextStream t(&fo);
- const int maxLineLen=100*1024;
- int lineNr=1;
- int width,height;
- bool insideHeader=FALSE;
- bool replacedHeader=FALSE;
- bool foundSize=FALSE;
- while (!fi.atEnd()) // foreach line
- {
- QCString line(maxLineLen);
- int numBytes = fi.readLine(line.rawData(),maxLineLen);
- if (numBytes<=0)
- {
- break;
- }
- line.resize(numBytes+1);
-
- //printf("line=[%s]\n",line.stripWhiteSpace().data());
- int i;
- ASSERT(numBytes<maxLineLen);
- if (isSVGFile)
- {
- if (interactiveSVG)
- {
- if (line.find("<svg")!=-1 && !replacedHeader)
- {
- int count;
- count = sscanf(line.data(),"<svg width=\"%dpt\" height=\"%dpt\"",&width,&height);
- //printf("width=%d height=%d\n",width,height);
- foundSize = count==2 && (width>500 || height>450);
- if (foundSize) insideHeader=TRUE;
- }
- else if (insideHeader && !replacedHeader && line.find("<title>")!=-1)
- {
- if (foundSize)
- {
- // insert special replacement header for interactive SVGs
- t << "<!--zoomable " << height << " -->\n";
- t << svgZoomHeader;
- t << "var viewWidth = " << width << ";\n";
- t << "var viewHeight = " << height << ";\n";
- if (graphId>=0)
- {
- t << "var sectionId = 'dynsection-" << graphId << "';\n";
- }
- t << "</script>\n";
- t << "<script xlink:href=\"" << relPath << "svgpan.js\"/>\n";
- t << "<svg id=\"graph\" class=\"graph\">\n";
- t << "<g id=\"viewport\">\n";
- }
- insideHeader=FALSE;
- replacedHeader=TRUE;
- }
- }
- if (!insideHeader || !foundSize) // copy SVG and replace refs,
- // unless we are inside the header of the SVG.
- // Then we replace it with another header.
- {
- Map *map = m_maps.at(0); // there is only one 'map' for a SVG file
- t << replaceRef(line,map->relPath,map->urlOnly,map->context,"_top");
- }
- }
- else if ((i=line.find("<!-- SVG"))!=-1 || (i=line.find("[!-- SVG"))!=-1)
- {
- //printf("Found marker at %d\n",i);
- int mapId=-1;
- t << line.left(i);
- int n = sscanf(line.data()+i+1,"!-- SVG %d",&mapId);
- if (n==1 && mapId>=0 && mapId<(int)m_maps.count())
- {
- int e = QMAX(line.find("--]"),line.find("-->"));
- Map *map = m_maps.at(mapId);
- //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n",
- // m_patchFile.data(),map->zoomable);
- if (!writeSVGFigureLink(t,map->relPath,map->label,map->mapFile))
- {
- err("Problem extracting size from SVG file %s\n",map->mapFile.data());
- }
- if (e!=-1) t << line.mid(e+3);
- }
- else // error invalid map id!
- {
- err("Found invalid SVG id in file %s!\n",m_patchFile.data());
- t << line.mid(i);
- }
- }
- else if ((i=line.find("<!-- MAP"))!=-1)
- {
- int mapId=-1;
- t << line.left(i);
- int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId);
- if (n==1 && mapId>=0 && mapId<(int)m_maps.count())
- {
- QGString result;
- FTextStream tt(&result);
- Map *map = m_maps.at(mapId);
- //printf("patching MAP %d in file %s with contents of %s\n",
- // mapId,m_patchFile.data(),map->mapFile.data());
- convertMapFile(tt,map->mapFile,map->relPath,map->urlOnly,map->context);
- if (!result.isEmpty())
- {
- t << "<map name=\"" << map->label << "\" id=\"" << map->label << "\">" << endl;
- t << result;
- t << "</map>" << endl;
- }
- }
- else // error invalid map id!
- {
- err("Found invalid MAP id in file %s!\n",m_patchFile.data());
- t << line.mid(i);
- }
- }
- else if ((i=line.find("% FIG"))!=-1)
- {
- int mapId=-1;
- int n = sscanf(line.data()+i+2,"FIG %d",&mapId);
- //printf("line='%s' n=%d\n",line.data()+i,n);
- if (n==1 && mapId>=0 && mapId<(int)m_maps.count())
- {
- Map *map = m_maps.at(mapId);
- //printf("patching FIG %d in file %s with contents of %s\n",
- // mapId,m_patchFile.data(),map->mapFile.data());
- if (!writeVecGfxFigure(t,map->label,map->mapFile))
- {
- err("problem writing FIG %d figure!\n",mapId);
- return FALSE;
- }
- }
- else // error invalid map id!
- {
- err("Found invalid bounding FIG %d in file %s!\n",mapId,m_patchFile.data());
- t << line;
- }
- }
- else
- {
- t << line;
- }
- lineNr++;
- }
- fi.close();
- if (isSVGFile && interactiveSVG && replacedHeader)
- {
- QCString orgName=m_patchFile.left(m_patchFile.length()-4)+"_org.svg";
- t << substitute(svgZoomFooter,"$orgname",stripPath(orgName));
- fo.close();
- // keep original SVG file so we can refer to it, we do need to replace
- // dummy link by real ones
- QFile fi(tmpName);
- QFile fo(orgName);
- if (!fi.open(IO_ReadOnly))
- {
- err("problem opening file %s for reading!\n",tmpName.data());
- return FALSE;
- }
- if (!fo.open(IO_WriteOnly))
- {
- err("problem opening file %s for writing!\n",orgName.data());
- return FALSE;
- }
- FTextStream t(&fo);
- while (!fi.atEnd()) // foreach line
- {
- QCString line(maxLineLen);
- int numBytes = fi.readLine(line.rawData(),maxLineLen);
- if (numBytes<=0)
- {
- break;
- }
- line.resize(numBytes+1);
- Map *map = m_maps.at(0); // there is only one 'map' for a SVG file
- t << replaceRef(line,map->relPath,map->urlOnly,map->context,"_top");
- }
- fi.close();
- fo.close();
- }
- // remove temporary file
- QDir::current().remove(tmpName);
- return TRUE;
-}
-
-//--------------------------------------------------------------------
-
-void DotRunnerQueue::enqueue(DotRunner *runner)
-{
- QMutexLocker locker(&m_mutex);
- m_queue.enqueue(runner);
- m_bufferNotEmpty.wakeAll();
-}
-
-DotRunner *DotRunnerQueue::dequeue()
-{
- QMutexLocker locker(&m_mutex);
- while (m_queue.isEmpty())
- {
- // wait until something is added to the queue
- m_bufferNotEmpty.wait(&m_mutex);
- }
- DotRunner *result = m_queue.dequeue();
- return result;
-}
-
-uint DotRunnerQueue::count() const
-{
- QMutexLocker locker(&m_mutex);
- return m_queue.count();
-}
-
-//--------------------------------------------------------------------
-
-DotWorkerThread::DotWorkerThread(DotRunnerQueue *queue)
- : m_queue(queue)
-{
- m_cleanupItems.setAutoDelete(TRUE);
-}
-
-void DotWorkerThread::run()
-{
- DotRunner *runner;
- while ((runner=m_queue->dequeue()))
- {
- runner->run();
- const DotRunner::CleanupItem &cleanup = runner->cleanup();
- if (!cleanup.file.isEmpty())
- {
- m_cleanupItems.append(new DotRunner::CleanupItem(cleanup));
- }
- }
-}
-
-void DotWorkerThread::cleanup()
-{
- QListIterator<DotRunner::CleanupItem> it(m_cleanupItems);
- DotRunner::CleanupItem *ci;
- for (;(ci=it.current());++it)
- {
- QDir(ci->path.data()).remove(ci->file.data());
- }
-}
-
//--------------------------------------------------------------------
DotManager *DotManager::m_theInstance = 0;
@@ -1282,15 +206,13 @@ DotManager *DotManager::instance()
DotManager::DotManager() : m_dotMaps(1009)
{
- m_dotRuns.setAutoDelete(TRUE);
+ m_runners.setAutoDelete(TRUE);
m_dotMaps.setAutoDelete(TRUE);
m_queue = new DotRunnerQueue;
int i;
- int numThreads = QMIN(32,Config_getInt(DOT_NUM_THREADS));
- if (numThreads!=1)
+ if (DOT_NUM_THREADS!=1)
{
- if (numThreads==0) numThreads = QMAX(2,QThread::idealThreadCount()+1);
- for (i=0;i<numThreads;i++)
+ for (i=0;i<DOT_NUM_THREADS;i++)
{
DotWorkerThread *thread = new DotWorkerThread(m_queue);
thread->start();
@@ -1312,11 +234,26 @@ DotManager::~DotManager()
delete m_queue;
}
-void DotManager::addRun(DotRunner *run)
+DotRunner* DotManager::createRunner(const QCString& absDotName, const QCString& md5Hash)
{
- m_dotRuns.append(run);
+ DotRunner * run = m_runners.find(absDotName);
+ if (run == 0)
+ {
+ run = new DotRunner(absDotName, md5Hash);
+ m_runners.insert(absDotName, run);
+ }
+ else
+ {
+ // we have a match
+ if (md5Hash != QCString(run->getMd5Hash().data()))
+ {
+ err("md5 hash does not match for two different runs of %s !\n", absDotName.data());
+ }
+ }
+ return run;
}
+
int DotManager::addMap(const QCString &file,const QCString &mapFile,
const QCString &relPath,bool urlOnly,const QCString &context,
const QCString &label)
@@ -1369,7 +306,7 @@ int DotManager::addSVGObject(const QCString &file,const QCString &baseName,
bool DotManager::run()
{
- uint numDotRuns = m_dotRuns.count();
+ uint numDotRuns = m_runners.count();
uint numDotMaps = m_dotMaps.count();
if (numDotRuns+numDotMaps>1)
{
@@ -1383,7 +320,7 @@ bool DotManager::run()
}
}
int i=1;
- QListIterator<DotRunner> li(m_dotRuns);
+ QDictIterator<DotRunner> li(m_runners);
bool setPath=FALSE;
if (Config_getBool(GENERATE_HTML))
@@ -1451,11 +388,6 @@ bool DotManager::run()
{
m_workers.at(i)->wait();
}
- // clean up dot files from main thread
- for (i=0;i<(int)m_workers.count();i++)
- {
- m_workers.at(i)->cleanup();
- }
}
portable_sysTimerStop();
if (setPath)
@@ -1494,2736 +426,59 @@ bool DotManager::run()
//--------------------------------------------------------------------
-
-/*! helper function that deletes all nodes in a connected graph, given
- * one of the graph's nodes
- */
-static void deleteNodes(DotNode *node,SDict<DotNode> *skipNodes=0)
-{
- //printf("deleteNodes skipNodes=%p\n",skipNodes);
- static DotNodeList deletedNodes;
- deletedNodes.setAutoDelete(TRUE);
- node->deleteNode(deletedNodes,skipNodes); // collect nodes to be deleted.
- deletedNodes.clear(); // actually remove the nodes.
-}
-
-DotNode::DotNode(int n,const char *lab,const char *tip, const char *url,
- bool isRoot,const ClassDef *cd)
- : m_subgraphId(-1)
- , m_number(n)
- , m_label(lab)
- , m_tooltip(tip)
- , m_url(url)
- , m_parents(0)
- , m_children(0)
- , m_edgeInfo(0)
- , m_deleted(FALSE)
- , m_written(FALSE)
- , m_hasDoc(FALSE)
- , m_isRoot(isRoot)
- , m_classDef(cd)
- , m_visible(FALSE)
- , m_truncated(Unknown)
- , m_distance(1000)
- , m_renumbered(false)
-{
-}
-
-DotNode::~DotNode()
-{
- delete m_children;
- delete m_parents;
- delete m_edgeInfo;
-}
-
-void DotNode::addChild(DotNode *n,
- int edgeColor,
- int edgeStyle,
- const char *edgeLab,
- const char *edgeURL,
- int edgeLabCol
- )
-{
- if (m_children==0)
- {
- m_children = new QList<DotNode>;
- m_edgeInfo = new QList<EdgeInfo>;
- m_edgeInfo->setAutoDelete(TRUE);
- }
- m_children->append(n);
- EdgeInfo *ei = new EdgeInfo;
- ei->m_color = edgeColor;
- ei->m_style = edgeStyle;
- ei->m_label = edgeLab;
- ei->m_url = edgeURL;
- if (edgeLabCol==-1)
- ei->m_labColor=edgeColor;
- else
- ei->m_labColor=edgeLabCol;
- m_edgeInfo->append(ei);
-}
-
-void DotNode::addParent(DotNode *n)
-{
- if (m_parents==0)
- {
- m_parents = new QList<DotNode>;
- }
- m_parents->append(n);
-}
-
-void DotNode::removeChild(DotNode *n)
-{
- if (m_children) m_children->remove(n);
-}
-
-void DotNode::removeParent(DotNode *n)
-{
- if (m_parents) m_parents->remove(n);
-}
-
-void DotNode::deleteNode(DotNodeList &deletedList,SDict<DotNode> *skipNodes)
-{
- if (m_deleted) return; // avoid recursive loops in case the graph has cycles
- m_deleted=TRUE;
- if (m_parents!=0) // delete all parent nodes of this node
- {
- QListIterator<DotNode> dnlip(*m_parents);
- DotNode *pn;
- for (dnlip.toFirst();(pn=dnlip.current());++dnlip)
- {
- //pn->removeChild(this);
- pn->deleteNode(deletedList,skipNodes);
- }
- }
- if (m_children!=0) // delete all child nodes of this node
- {
- QListIterator<DotNode> dnlic(*m_children);
- DotNode *cn;
- for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
- {
- //cn->removeParent(this);
- cn->deleteNode(deletedList,skipNodes);
- }
- }
- // add this node to the list of deleted nodes.
- //printf("skipNodes=%p find(%p)=%p\n",skipNodes,this,skipNodes ? skipNodes->find((int)this) : 0);
- if (skipNodes==0 || skipNodes->find((char*)this)==0)
- {
- //printf("deleting\n");
- deletedList.append(this);
- }
-}
-
-void DotNode::setDistance(int distance)
-{
- if (distance<m_distance) m_distance = distance;
-}
-
-static QCString convertLabel(const QCString &l)
-{
- QString bBefore("\\_/<({[: =-+@%#~?$"); // break before character set
- QString bAfter(">]),:;|"); // break after character set
- QString p(l);
- if (p.isEmpty()) return QCString();
- QString result;
- QChar c,pc=0;
- uint idx = 0;
- int len=p.length();
- int charsLeft=len;
- int sinceLast=0;
- int foldLen=17; // ideal text length
- while (idx < p.length())
- {
- c = p[idx++];
- QString replacement;
- switch(c)
- {
- case '\\': replacement="\\\\"; break;
- case '\n': replacement="\\n"; break;
- case '<': replacement="\\<"; break;
- case '>': replacement="\\>"; break;
- case '|': replacement="\\|"; break;
- case '{': replacement="\\{"; break;
- case '}': replacement="\\}"; break;
- case '"': replacement="\\\""; break;
- default: replacement=c; break;
- }
- // Some heuristics to insert newlines to prevent too long
- // boxes and at the same time prevent ugly breaks
- if (c=='\n')
- {
- result+=replacement;
- foldLen = (3*foldLen+sinceLast+2)/4;
- sinceLast=1;
- }
- else if ((pc!=':' || c!=':') && charsLeft>foldLen/3 && sinceLast>foldLen && bBefore.contains(c))
- {
- result+="\\l";
- result+=replacement;
- foldLen = (foldLen+sinceLast+1)/2;
- sinceLast=1;
- }
- else if (charsLeft>1+foldLen/4 && sinceLast>foldLen+foldLen/3 &&
- !isupper(c) && p[idx].category()==QChar::Letter_Uppercase)
- {
- result+=replacement;
- result+="\\l";
- foldLen = (foldLen+sinceLast+1)/2;
- sinceLast=0;
- }
- else if (charsLeft>foldLen/3 && sinceLast>foldLen && bAfter.contains(c) && (c!=':' || p[idx]!=':'))
- {
- result+=replacement;
- result+="\\l";
- foldLen = (foldLen+sinceLast+1)/2;
- sinceLast=0;
- }
- else
- {
- result+=replacement;
- sinceLast++;
- }
- charsLeft--;
- pc=c;
- }
- return result.utf8();
-}
-
-static QCString escapeTooltip(const QCString &tooltip)
-{
- QCString result;
- const char *p=tooltip.data();
- if (p==0) return result;
- char c;
- while ((c=*p++))
- {
- switch(c)
- {
- case '"': result+="\\\""; break;
- case '\\': result+="\\\\"; break;
- default: result+=c; break;
- }
- }
- return result;
-}
-
-static void writeBoxMemberList(FTextStream &t,
- char prot,MemberList *ml,const ClassDef *scope,
- bool isStatic=FALSE,const QDict<void> *skipNames=0)
-{
- (void)isStatic;
- if (ml)
- {
- MemberListIterator mlia(*ml);
- MemberDef *mma;
- int totalCount=0;
- for (mlia.toFirst();(mma = mlia.current());++mlia)
- {
- if (mma->getClassDef()==scope &&
- (skipNames==0 || skipNames->find(mma->name())==0))
- {
- totalCount++;
- }
- }
-
- int count=0;
- for (mlia.toFirst();(mma = mlia.current());++mlia)
- {
- if (mma->getClassDef() == scope &&
- (skipNames==0 || skipNames->find(mma->name())==0))
- {
- static int limit = Config_getInt(UML_LIMIT_NUM_FIELDS);
- if (limit>0 && (totalCount>limit*3/2 && count>=limit))
- {
- t << theTranslator->trAndMore(QCString().sprintf("%d",totalCount-count)) << "\\l";
- break;
- }
- else
- {
- t << prot << " ";
- t << convertLabel(mma->name());
- if (!mma->isObjCMethod() &&
- (mma->isFunction() || mma->isSlot() || mma->isSignal())) t << "()";
- t << "\\l";
- count++;
- }
- }
- }
- // write member groups within the memberlist
- MemberGroupList *mgl = ml->getMemberGroupList();
- if (mgl)
- {
- MemberGroupListIterator mgli(*mgl);
- MemberGroup *mg;
- for (mgli.toFirst();(mg=mgli.current());++mgli)
- {
- if (mg->members())
- {
- writeBoxMemberList(t,prot,mg->members(),scope,isStatic,skipNames);
- }
- }
- }
- }
-}
-
-static QCString stripProtectionPrefix(const QCString &s)
-{
- if (!s.isEmpty() && (s[0]=='-' || s[0]=='+' || s[0]=='~' || s[0]=='#'))
- {
- return s.mid(1);
- }
- else
- {
- return s;
- }
-}
-
-void DotNode::writeBox(FTextStream &t,
- GraphType gt,
- GraphOutputFormat /*format*/,
- bool hasNonReachableChildren
- )
-{
- const char *labCol =
- m_url.isEmpty() ? "grey75" : // non link
- (
- (hasNonReachableChildren) ? "red" : "black"
- );
- t << " Node" << m_number << " [label=\"";
- static bool umlLook = Config_getBool(UML_LOOK);
-
- if (m_classDef && umlLook && (gt==Inheritance || gt==Collaboration))
- {
- // add names shown as relations to a dictionary, so we don't show
- // them as attributes as well
- QDict<void> arrowNames(17);
- if (m_edgeInfo)
- {
- // for each edge
- QListIterator<EdgeInfo> li(*m_edgeInfo);
- EdgeInfo *ei;
- for (li.toFirst();(ei=li.current());++li)
- {
- if (!ei->m_label.isEmpty()) // labels joined by \n
- {
- int li=ei->m_label.find('\n');
- int p=0;
- QCString lab;
- while ((li=ei->m_label.find('\n',p))!=-1)
- {
- lab = stripProtectionPrefix(ei->m_label.mid(p,li-p));
- arrowNames.insert(lab,(void*)0x8);
- p=li+1;
- }
- lab = stripProtectionPrefix(ei->m_label.right(ei->m_label.length()-p));
- arrowNames.insert(lab,(void*)0x8);
- }
- }
- }
-
- //printf("DotNode::writeBox for %s\n",m_classDef->name().data());
- static bool extractPrivate = Config_getBool(EXTRACT_PRIVATE);
- t << "{" << convertLabel(m_label);
- t << "\\n|";
- writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubAttribs),m_classDef,FALSE,&arrowNames);
- writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubStaticAttribs),m_classDef,TRUE,&arrowNames);
- writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_properties),m_classDef,FALSE,&arrowNames);
- writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacAttribs),m_classDef,FALSE,&arrowNames);
- writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacStaticAttribs),m_classDef,TRUE,&arrowNames);
- writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proAttribs),m_classDef,FALSE,&arrowNames);
- writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proStaticAttribs),m_classDef,TRUE,&arrowNames);
- if (extractPrivate)
- {
- writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priAttribs),m_classDef,FALSE,&arrowNames);
- writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priStaticAttribs),m_classDef,TRUE,&arrowNames);
- }
- t << "|";
- writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubMethods),m_classDef);
- writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubStaticMethods),m_classDef,TRUE);
- writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubSlots),m_classDef);
- writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacMethods),m_classDef);
- writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacStaticMethods),m_classDef,TRUE);
- writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proMethods),m_classDef);
- writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proStaticMethods),m_classDef,TRUE);
- writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proSlots),m_classDef);
- if (extractPrivate)
- {
- writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priMethods),m_classDef);
- writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priStaticMethods),m_classDef,TRUE);
- writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priSlots),m_classDef);
- }
- if (m_classDef->getLanguage()!=SrcLangExt_Fortran &&
- m_classDef->getMemberGroupSDict())
- {
- MemberGroupSDict::Iterator mgdi(*m_classDef->getMemberGroupSDict());
- MemberGroup *mg;
- for (mgdi.toFirst();(mg=mgdi.current());++mgdi)
- {
- if (mg->members())
- {
- writeBoxMemberList(t,'*',mg->members(),m_classDef,FALSE,&arrowNames);
- }
- }
- }
- t << "}";
- }
- else // standard look
- {
- t << convertLabel(m_label);
- }
- t << "\",height=0.2,width=0.4";
- if (m_isRoot)
- {
- t << ",color=\"black\", fillcolor=\"grey75\", style=\"filled\", fontcolor=\"black\"";
- }
- else
- {
- static bool dotTransparent = Config_getBool(DOT_TRANSPARENT);
- if (!dotTransparent)
- {
- t << ",color=\"" << labCol << "\", fillcolor=\"";
- t << "white";
- t << "\", style=\"filled\"";
- }
- else
- {
- t << ",color=\"" << labCol << "\"";
- }
- if (!m_url.isEmpty())
- {
- int anchorPos = m_url.findRev('#');
- if (anchorPos==-1)
- {
- t << ",URL=\"" << m_url << Doxygen::htmlFileExtension << "\"";
- }
- else
- {
- t << ",URL=\"" << m_url.left(anchorPos) << Doxygen::htmlFileExtension
- << m_url.right(m_url.length()-anchorPos) << "\"";
- }
- }
- }
- if (!m_tooltip.isEmpty())
- {
- t << ",tooltip=\"" << escapeTooltip(m_tooltip) << "\"";
- }
- else
- {
- t << ",tooltip=\" \""; // space in tooltip is required otherwise still something like 'Node0' is used
- }
- t << "];" << endl;
-}
-
-void DotNode::writeArrow(FTextStream &t,
- GraphType gt,
- GraphOutputFormat format,
- DotNode *cn,
- EdgeInfo *ei,
- bool topDown,
- bool pointBack
- )
-{
- t << " Node";
- if (topDown)
- t << cn->number();
- else
- t << m_number;
- t << " -> Node";
- if (topDown)
- t << m_number;
- else
- t << cn->number();
- t << " [";
-
- static bool umlLook = Config_getBool(UML_LOOK);
- const EdgeProperties *eProps = umlLook ? &umlEdgeProps : &normalEdgeProps;
- QCString aStyle = eProps->arrowStyleMap[ei->m_color];
- bool umlUseArrow = aStyle=="odiamond";
-
- if (pointBack && !umlUseArrow) t << "dir=\"back\",";
- t << "color=\"" << eProps->edgeColorMap[ei->m_color]
- << "\",fontsize=\"" << FONTSIZE << "\",";
- t << "style=\"" << eProps->edgeStyleMap[ei->m_style] << "\"";
- if (!ei->m_label.isEmpty())
- {
- t << ",label=\" " << convertLabel(ei->m_label) << "\" ";
- }
- if (umlLook &&
- eProps->arrowStyleMap[ei->m_color] &&
- (gt==Inheritance || gt==Collaboration)
- )
- {
- bool rev = pointBack;
- if (umlUseArrow) rev=!rev; // UML use relates has arrow on the start side
- if (rev)
- t << ",arrowtail=\"" << eProps->arrowStyleMap[ei->m_color] << "\"";
- else
- t << ",arrowhead=\"" << eProps->arrowStyleMap[ei->m_color] << "\"";
- }
-
- if (format==GOF_BITMAP) t << ",fontname=\"" << FONTNAME << "\"";
- t << "];" << endl;
-}
-
-void DotNode::write(FTextStream &t,
- GraphType gt,
- GraphOutputFormat format,
- bool topDown,
- bool toChildren,
- bool backArrows
- )
-{
- //printf("DotNode::write(%d) name=%s this=%p written=%d visible=%d\n",m_distance,m_label.data(),this,m_written,m_visible);
- if (m_written) return; // node already written to the output
- if (!m_visible) return; // node is not visible
- writeBox(t,gt,format,m_truncated==Truncated);
- m_written=TRUE;
- QList<DotNode> *nl = toChildren ? m_children : m_parents;
- if (nl)
- {
- if (toChildren)
- {
- QListIterator<DotNode> dnli1(*nl);
- QListIterator<EdgeInfo> dnli2(*m_edgeInfo);
- DotNode *cn;
- for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2)
- {
- if (cn->isVisible())
- {
- //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",cn->label().data());
- writeArrow(t,gt,format,cn,dnli2.current(),topDown,backArrows);
- }
- cn->write(t,gt,format,topDown,toChildren,backArrows);
- }
- }
- else // render parents
- {
- QListIterator<DotNode> dnli(*nl);
- DotNode *pn;
- for (dnli.toFirst();(pn=dnli.current());++dnli)
- {
- if (pn->isVisible())
- {
- //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",pn->label().data());
- writeArrow(t,
- gt,
- format,
- pn,
- pn->m_edgeInfo->at(pn->m_children->findRef(this)),
- FALSE,
- backArrows
- );
- }
- pn->write(t,gt,format,TRUE,FALSE,backArrows);
- }
- }
- }
- //printf("end DotNode::write(%d) name=%s\n",distance,m_label.data());
-}
-
-void DotNode::writeXML(FTextStream &t,bool isClassGraph)
-{
- t << " <node id=\"" << m_number << "\">" << endl;
- t << " <label>" << convertToXML(m_label) << "</label>" << endl;
- if (!m_url.isEmpty())
- {
- QCString url(m_url);
- const char *refPtr = url.data();
- char *urlPtr = strchr(url.rawData(),'$');
- if (urlPtr)
- {
- *urlPtr++='\0';
- t << " <link refid=\"" << convertToXML(urlPtr) << "\"";
- if (*refPtr!='\0')
- {
- t << " external=\"" << convertToXML(refPtr) << "\"";
- }
- t << "/>" << endl;
- }
- }
- if (m_children)
- {
- QListIterator<DotNode> nli(*m_children);
- QListIterator<EdgeInfo> eli(*m_edgeInfo);
- DotNode *childNode;
- EdgeInfo *edgeInfo;
- for (;(childNode=nli.current());++nli,++eli)
- {
- edgeInfo=eli.current();
- t << " <childnode refid=\"" << childNode->m_number << "\" relation=\"";
- if (isClassGraph)
- {
- switch(edgeInfo->m_color)
- {
- case EdgeInfo::Blue: t << "public-inheritance"; break;
- case EdgeInfo::Green: t << "protected-inheritance"; break;
- case EdgeInfo::Red: t << "private-inheritance"; break;
- case EdgeInfo::Purple: t << "usage"; break;
- case EdgeInfo::Orange: t << "template-instance"; break;
- case EdgeInfo::Orange2: t << "type-constraint"; break;
- case EdgeInfo::Grey: ASSERT(0); break;
- }
- }
- else // include graph
- {
- t << "include";
- }
- t << "\">" << endl;
- if (!edgeInfo->m_label.isEmpty())
- {
- int p=0;
- int ni;
- while ((ni=edgeInfo->m_label.find('\n',p))!=-1)
- {
- t << " <edgelabel>"
- << convertToXML(edgeInfo->m_label.mid(p,ni-p))
- << "</edgelabel>" << endl;
- p=ni+1;
- }
- t << " <edgelabel>"
- << convertToXML(edgeInfo->m_label.right(edgeInfo->m_label.length()-p))
- << "</edgelabel>" << endl;
- }
- t << " </childnode>" << endl;
- }
- }
- t << " </node>" << endl;
-}
-
-void DotNode::writeDocbook(FTextStream &t,bool isClassGraph)
-{
- t << " <node id=\"" << m_number << "\">" << endl;
- t << " <label>" << convertToXML(m_label) << "</label>" << endl;
- if (!m_url.isEmpty())
- {
- QCString url(m_url);
- const char *refPtr = url.data();
- char *urlPtr = strchr(url.rawData(),'$');
- if (urlPtr)
- {
- *urlPtr++='\0';
- t << " <link refid=\"" << convertToXML(urlPtr) << "\"";
- if (*refPtr!='\0')
- {
- t << " external=\"" << convertToXML(refPtr) << "\"";
- }
- t << "/>" << endl;
- }
- }
- if (m_children)
- {
- QListIterator<DotNode> nli(*m_children);
- QListIterator<EdgeInfo> eli(*m_edgeInfo);
- DotNode *childNode;
- EdgeInfo *edgeInfo;
- for (;(childNode=nli.current());++nli,++eli)
- {
- edgeInfo=eli.current();
- t << " <childnode refid=\"" << childNode->m_number << "\" relation=\"";
- if (isClassGraph)
- {
- switch(edgeInfo->m_color)
- {
- case EdgeInfo::Blue: t << "public-inheritance"; break;
- case EdgeInfo::Green: t << "protected-inheritance"; break;
- case EdgeInfo::Red: t << "private-inheritance"; break;
- case EdgeInfo::Purple: t << "usage"; break;
- case EdgeInfo::Orange: t << "template-instance"; break;
- case EdgeInfo::Orange2: t << "type-constraint"; break;
- case EdgeInfo::Grey: ASSERT(0); break;
- }
- }
- else // include graph
- {
- t << "include";
- }
- t << "\">" << endl;
- if (!edgeInfo->m_label.isEmpty())
- {
- int p=0;
- int ni;
- while ((ni=edgeInfo->m_label.find('\n',p))!=-1)
- {
- t << " <edgelabel>"
- << convertToXML(edgeInfo->m_label.mid(p,ni-p))
- << "</edgelabel>" << endl;
- p=ni+1;
- }
- t << " <edgelabel>"
- << convertToXML(edgeInfo->m_label.right(edgeInfo->m_label.length()-p))
- << "</edgelabel>" << endl;
- }
- t << " </childnode>" << endl;
- }
- }
- t << " </node>" << endl;
-}
-
-
-void DotNode::writeDEF(FTextStream &t)
-{
- const char* nodePrefix = " node-";
-
- t << " node = {" << endl;
- t << nodePrefix << "id = " << m_number << ';' << endl;
- t << nodePrefix << "label = '" << m_label << "';" << endl;
-
- if (!m_url.isEmpty())
- {
- QCString url(m_url);
- const char *refPtr = url.data();
- char *urlPtr = strchr(url.rawData(),'$');
- if (urlPtr)
- {
- *urlPtr++='\0';
- t << nodePrefix << "link = {" << endl << " "
- << nodePrefix << "link-id = '" << urlPtr << "';" << endl;
-
- if (*refPtr!='\0')
- {
- t << " " << nodePrefix << "link-external = '"
- << refPtr << "';" << endl;
- }
- t << " };" << endl;
- }
- }
- if (m_children)
- {
- QListIterator<DotNode> nli(*m_children);
- QListIterator<EdgeInfo> eli(*m_edgeInfo);
- DotNode *childNode;
- EdgeInfo *edgeInfo;
- for (;(childNode=nli.current());++nli,++eli)
- {
- edgeInfo=eli.current();
- t << " node-child = {" << endl;
- t << " child-id = '" << childNode->m_number << "';" << endl;
- t << " relation = ";
-
- switch(edgeInfo->m_color)
- {
- case EdgeInfo::Blue: t << "public-inheritance"; break;
- case EdgeInfo::Green: t << "protected-inheritance"; break;
- case EdgeInfo::Red: t << "private-inheritance"; break;
- case EdgeInfo::Purple: t << "usage"; break;
- case EdgeInfo::Orange: t << "template-instance"; break;
- case EdgeInfo::Orange2: t << "type-constraint"; break;
- case EdgeInfo::Grey: ASSERT(0); break;
- }
- t << ';' << endl;
-
- if (!edgeInfo->m_label.isEmpty())
- {
- t << " edgelabel = <<_EnD_oF_dEf_TeXt_" << endl
- << edgeInfo->m_label << endl
- << "_EnD_oF_dEf_TeXt_;" << endl;
- }
- t << " }; /* node-child */" << endl;
- } /* for (;childNode...) */
- }
- t << " }; /* node */" << endl;
-}
-
-
-void DotNode::clearWriteFlag()
-{
- m_written=FALSE;
- if (m_parents!=0)
- {
- QListIterator<DotNode> dnlip(*m_parents);
- DotNode *pn;
- for (dnlip.toFirst();(pn=dnlip.current());++dnlip)
- {
- if (pn->m_written)
- {
- pn->clearWriteFlag();
- }
- }
- }
- if (m_children!=0)
- {
- QListIterator<DotNode> dnlic(*m_children);
- DotNode *cn;
- for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
- {
- if (cn->m_written)
- {
- cn->clearWriteFlag();
- }
- }
- }
-}
-
-void DotNode::colorConnectedNodes(int curColor)
-{
- if (m_children)
- {
- QListIterator<DotNode> dnlic(*m_children);
- DotNode *cn;
- for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
- {
- if (cn->m_subgraphId==-1) // uncolored child node
- {
- cn->m_subgraphId=curColor;
- cn->markAsVisible();
- cn->colorConnectedNodes(curColor);
- //printf("coloring node %s (%p): %d\n",cn->m_label.data(),cn,cn->m_subgraphId);
- }
- }
- }
-
- if (m_parents)
- {
- QListIterator<DotNode> dnlip(*m_parents);
- DotNode *pn;
- for (dnlip.toFirst();(pn=dnlip.current());++dnlip)
- {
- if (pn->m_subgraphId==-1) // uncolored parent node
- {
- pn->m_subgraphId=curColor;
- pn->markAsVisible();
- pn->colorConnectedNodes(curColor);
- //printf("coloring node %s (%p): %d\n",pn->m_label.data(),pn,pn->m_subgraphId);
- }
- }
- }
-}
-
-void DotNode::renumberNodes(int &number)
-{
- m_number = number++;
- if (m_children)
- {
- QListIterator<DotNode> dnlic(*m_children);
- DotNode *cn;
- for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
- {
- if (!cn->m_renumbered)
- {
- cn->m_renumbered = true;
- cn->renumberNodes(number);
- }
- }
- }
-}
-
-const DotNode *DotNode::findDocNode() const
-{
- if (!m_url.isEmpty()) return this;
- //printf("findDocNode(): `%s'\n",m_label.data());
- if (m_parents)
- {
- QListIterator<DotNode> dnli(*m_parents);
- DotNode *pn;
- for (dnli.toFirst();(pn=dnli.current());++dnli)
- {
- if (!pn->m_hasDoc)
- {
- pn->m_hasDoc=TRUE;
- const DotNode *dn = pn->findDocNode();
- if (dn) return dn;
- }
- }
- }
- if (m_children)
- {
- QListIterator<DotNode> dnli(*m_children);
- DotNode *cn;
- for (dnli.toFirst();(cn=dnli.current());++dnli)
- {
- if (!cn->m_hasDoc)
- {
- cn->m_hasDoc=TRUE;
- const DotNode *dn = cn->findDocNode();
- if (dn) return dn;
- }
- }
- }
- return 0;
-}
-
-//--------------------------------------------------------------------
-
-void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out,
- const char *path,const char *fileName,int id) const
+class GraphLegendDotGraph : public DotGraph
{
- QDir d(path);
- QCString baseName;
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- if (m_prefix.isEmpty())
- baseName.sprintf("inherit_graph_%d",id);
- else
- baseName.sprintf("%sinherit_graph_%d",m_prefix.data(),id);
- QCString imgName = baseName+"."+ imgExt;
- QCString mapName = baseName+".map";
- QCString absImgName = QCString(d.absPath().data())+"/"+imgName;
- QCString absMapName = QCString(d.absPath().data())+"/"+mapName;
- QCString absBaseName = QCString(d.absPath().data())+"/"+baseName;
- QListIterator<DotNode> dnli2(*m_rootNodes);
- DotNode *node;
-
- // compute md5 checksum of the graph were are about to generate
- QGString theGraph;
- FTextStream md5stream(&theGraph);
- writeGraphHeader(md5stream,theTranslator->trGraphicalHierarchy());
- md5stream << " rankdir=\"LR\";" << endl;
- for (dnli2.toFirst();(node=dnli2.current());++dnli2)
- {
- if (node->m_subgraphId==n->m_subgraphId)
+ private:
+ virtual QCString getBaseName() const
{
- node->clearWriteFlag();
+ return "graph_legend";
}
- }
- for (dnli2.toFirst();(node=dnli2.current());++dnli2)
- {
- if (node->m_subgraphId==n->m_subgraphId)
- {
- node->write(md5stream,DotNode::Hierarchy,GOF_BITMAP,FALSE,TRUE,TRUE);
- }
- }
- writeGraphFooter(md5stream);
- uchar md5_sig[16];
- QCString sigStr(33);
- MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
- MD5SigToString(md5_sig,sigStr.rawData(),33);
- bool regenerate=FALSE;
- if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
- !checkDeliverables(absImgName,absMapName))
- {
- regenerate=TRUE;
- // image was new or has changed
- QCString dotName=absBaseName+".dot";
- QFile f(dotName);
- if (!f.open(IO_WriteOnly)) return;
- FTextStream t(&f);
- t << theGraph;
- f.close();
- DotRunner *dotRun = new DotRunner(dotName,d.absPath().data(),TRUE,absImgName);
- dotRun->addJob(imgFmt,absImgName);
- dotRun->addJob(MAP_CMD,absMapName);
- DotManager::instance()->addRun(dotRun);
- }
- else
- {
- removeDotGraph(absBaseName+".dot");
- }
- Doxygen::indexList->addImageFile(imgName);
- // write image and map in a table row
- QCString mapLabel = escapeCharsInString(n->m_label,FALSE);
- if (imgExt=="svg") // vector graphics
- {
- if (regenerate || !writeSVGFigureLink(out,QCString(),baseName,absImgName))
+ virtual void computeTheGraph()
{
- if (regenerate)
- {
- DotManager::instance()->addSVGConversion(absImgName,QCString(),
- FALSE,QCString(),FALSE,0);
- }
- int mapId = DotManager::instance()->addSVGObject(fileName,baseName,
- absImgName,QCString());
- out << "<!-- SVG " << mapId << " -->" << endl;
+ FTextStream md5stream(&m_theGraph);
+ writeGraphHeader(md5stream,theTranslator->trLegendTitle());
+ md5stream << " Node9 [shape=\"box\",label=\"Inherited\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",fillcolor=\"grey75\",style=\"filled\" fontcolor=\"black\"];\n";
+ md5stream << " Node10 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"solid\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node10 [shape=\"box\",label=\"PublicBase\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"black\",URL=\"$classPublicBase" << Doxygen::htmlFileExtension << "\"];\n";
+ md5stream << " Node11 -> Node10 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"solid\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node11 [shape=\"box\",label=\"Truncated\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"red\",URL=\"$classTruncated" << Doxygen::htmlFileExtension << "\"];\n";
+ md5stream << " Node13 -> Node9 [dir=\"back\",color=\"darkgreen\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"solid\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node13 [shape=\"box\",label=\"ProtectedBase\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"black\",URL=\"$classProtectedBase" << Doxygen::htmlFileExtension << "\"];\n";
+ md5stream << " Node14 -> Node9 [dir=\"back\",color=\"firebrick4\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"solid\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node14 [shape=\"box\",label=\"PrivateBase\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"black\",URL=\"$classPrivateBase" << Doxygen::htmlFileExtension << "\"];\n";
+ md5stream << " Node15 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"solid\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node15 [shape=\"box\",label=\"Undocumented\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"grey75\"];\n";
+ md5stream << " Node16 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"solid\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node16 [shape=\"box\",label=\"Templ< int >\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n";
+ md5stream << " Node17 -> Node16 [dir=\"back\",color=\"orange\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"dashed\",label=\"< int >\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node17 [shape=\"box\",label=\"Templ< T >\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n";
+ md5stream << " Node18 -> Node9 [dir=\"back\",color=\"darkorchid3\",fontsize=\"" << DOT_FONTSIZE << "\",style=\"dashed\",label=\"m_usedClass\",fontname=\"" << DOT_FONTNAME << "\"];\n";
+ md5stream << " Node18 [shape=\"box\",label=\"Used\",fontsize=\"" << DOT_FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << DOT_FONTNAME << "\",color=\"black\",URL=\"$classUsed" << Doxygen::htmlFileExtension << "\"];\n";
+ writeGraphFooter(md5stream);
}
- }
- else // normal bitmap
- {
- out << "<img src=\"" << imgName << "\" border=\"0\" alt=\"\" usemap=\"#"
- << mapLabel << "\"/>" << endl;
- if (regenerate || !insertMapFile(out,absMapName,QCString(),mapLabel))
+ virtual QCString getMapLabel() const
{
- int mapId = DotManager::instance()->addMap(fileName,absMapName,QCString(),
- FALSE,QCString(),mapLabel);
- out << "<!-- MAP " << mapId << " -->" << endl;
+ return "";
}
- }
-}
-
-void DotGfxHierarchyTable::writeGraph(FTextStream &out,
- const char *path,const char *fileName) const
-{
- //printf("DotGfxHierarchyTable::writeGraph(%s)\n",name);
- //printf("m_rootNodes=%p count=%d\n",m_rootNodes,m_rootNodes->count());
-
- if (m_rootSubgraphs->count()==0) return;
-
- QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
- // put each connected subgraph of the hierarchy in a row of the HTML output
- out << "<table border=\"0\" cellspacing=\"10\" cellpadding=\"0\">" << endl;
-
- QListIterator<DotNode> dnli(*m_rootSubgraphs);
- DotNode *n;
- int count=0;
- for (dnli.toFirst();(n=dnli.current());++dnli)
- {
- out << "<tr><td>";
- createGraph(n,out,path,fileName,count++);
- out << "</td></tr>" << endl;
- }
- out << "</table>" << endl;
-}
-
-void DotGfxHierarchyTable::addHierarchy(DotNode *n,const ClassDef *cd,bool hideSuper)
-{
- //printf("addHierarchy `%s' baseClasses=%d\n",cd->name().data(),cd->baseClasses()->count());
- if (cd->subClasses())
- {
- BaseClassListIterator bcli(*cd->subClasses());
- BaseClassDef *bcd;
- for ( ; (bcd=bcli.current()) ; ++bcli )
- {
- ClassDef *bClass=bcd->classDef;
- //printf(" Trying sub class=`%s' usedNodes=%d\n",bClass->name().data(),m_usedNodes->count());
- if (bClass->isVisibleInHierarchy() && hasVisibleRoot(bClass->baseClasses()))
- {
- DotNode *bn;
- //printf(" Node `%s' Found visible class=`%s'\n",n->m_label.data(),
- // bClass->name().data());
- if ((bn=m_usedNodes->find(bClass->name()))) // node already present
- {
- if (n->m_children==0 || n->m_children->findRef(bn)==-1) // no arrow yet
- {
- n->addChild(bn,bcd->prot);
- bn->addParent(n);
- //printf(" Adding node %s to existing base node %s (c=%d,p=%d)\n",
- // n->m_label.data(),
- // bn->m_label.data(),
- // bn->m_children ? bn->m_children->count() : 0,
- // bn->m_parents ? bn->m_parents->count() : 0
- // );
- }
- //else
- //{
- // printf(" Class already has an arrow!\n");
- //}
- }
- else
- {
- QCString tmp_url="";
- if (bClass->isLinkable() && !bClass->isHidden())
- {
- tmp_url=bClass->getReference()+"$"+bClass->getOutputFileBase();
- if (!bClass->anchor().isEmpty())
- {
- tmp_url+="#"+bClass->anchor();
- }
- }
- QCString tooltip = bClass->briefDescriptionAsTooltip();
- bn = new DotNode(getNextNodeNumber(),
- bClass->displayName(),
- tooltip,
- tmp_url.data()
- );
- n->addChild(bn,bcd->prot);
- bn->addParent(n);
- //printf(" Adding node %s to new base node %s (c=%d,p=%d)\n",
- // n->m_label.data(),
- // bn->m_label.data(),
- // bn->m_children ? bn->m_children->count() : 0,
- // bn->m_parents ? bn->m_parents->count() : 0
- // );
- //printf(" inserting %s (%p)\n",bClass->name().data(),bn);
- m_usedNodes->insert(bClass->name(),bn); // add node to the used list
- }
- if (!bClass->isVisited() && !hideSuper && bClass->subClasses())
- {
- bool wasVisited=bClass->isVisited();
- bClass->setVisited(TRUE);
- addHierarchy(bn,bClass,wasVisited);
- }
- }
- }
- }
- //printf("end addHierarchy\n");
-}
-
-void DotGfxHierarchyTable::addClassList(const ClassSDict *cl)
-{
- static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
- ClassSDict::Iterator cli(*cl);
- ClassDef *cd;
- for (cli.toLast();(cd=cli.current());--cli)
- {
- //printf("Trying %s subClasses=%d\n",cd->name().data(),cd->subClasses()->count());
- if (cd->getLanguage()==SrcLangExt_VHDL &&
- (VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS
- )
- {
- continue;
- }
- if (sliceOpt && cd->compoundType() != m_classType)
- {
- continue;
- }
- if (!hasVisibleRoot(cd->baseClasses()) &&
- cd->isVisibleInHierarchy()
- ) // root node in the forest
- {
- QCString tmp_url="";
- if (cd->isLinkable() && !cd->isHidden())
- {
- tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
- if (!cd->anchor().isEmpty())
- {
- tmp_url+="#"+cd->anchor();
- }
- }
- //printf("Inserting root class %s\n",cd->name().data());
- QCString tooltip = cd->briefDescriptionAsTooltip();
- DotNode *n = new DotNode(getNextNodeNumber(),
- cd->displayName(),
- tooltip,
- tmp_url.data());
-
- //m_usedNodes->clear();
- m_usedNodes->insert(cd->name(),n);
- m_rootNodes->insert(0,n);
- if (!cd->isVisited() && cd->subClasses())
- {
- addHierarchy(n,cd,cd->isVisited());
- cd->setVisited(TRUE);
- }
- }
- }
-}
-
-DotGfxHierarchyTable::DotGfxHierarchyTable(const char *prefix,ClassDef::CompoundType ct)
- : m_prefix(prefix)
- , m_classType(ct)
-{
- m_rootNodes = new QList<DotNode>;
- m_usedNodes = new QDict<DotNode>(1009);
- m_usedNodes->setAutoDelete(TRUE);
- m_rootSubgraphs = new DotNodeList;
-
- // build a graph with each class as a node and the inheritance relations
- // as edges
- initClassHierarchy(Doxygen::classSDict);
- initClassHierarchy(Doxygen::hiddenClasses);
- addClassList(Doxygen::classSDict);
- addClassList(Doxygen::hiddenClasses);
- // m_usedNodes now contains all nodes in the graph
-
- // color the graph into a set of independent subgraphs
- bool done=FALSE;
- int curColor=0;
- QListIterator<DotNode> dnli(*m_rootNodes);
- while (!done) // there are still nodes to color
- {
- DotNode *n;
- done=TRUE; // we are done unless there are still uncolored nodes
- for (dnli.toLast();(n=dnli.current());--dnli)
- {
- if (n->m_subgraphId==-1) // not yet colored
- {
- //printf("Starting at node %s (%p): %d\n",n->m_label.data(),n,curColor);
- done=FALSE; // still uncolored nodes
- n->m_subgraphId=curColor;
- n->markAsVisible();
- n->colorConnectedNodes(curColor);
- curColor++;
- const DotNode *dn=n->findDocNode();
- if (dn!=0)
- m_rootSubgraphs->inSort(dn);
- else
- m_rootSubgraphs->inSort(n);
- }
- }
- }
-
- //printf("Number of independent subgraphs: %d\n",curColor);
- QListIterator<DotNode> dnli2(*m_rootSubgraphs);
- DotNode *n;
- for (dnli2.toFirst();(n=dnli2.current());++dnli2)
- {
- //printf("Node %s color=%d (c=%d,p=%d)\n",
- // n->m_label.data(),n->m_subgraphId,
- // n->m_children?n->m_children->count():0,
- // n->m_parents?n->m_parents->count():0);
- int number=0;
- n->renumberNodes(number);
- }
-}
-
-DotGfxHierarchyTable::~DotGfxHierarchyTable()
-{
- //printf("DotGfxHierarchyTable::~DotGfxHierarchyTable\n");
-
- //QDictIterator<DotNode> di(*m_usedNodes);
- //DotNode *n;
- //for (;(n=di.current());++di)
- //{
- // printf("Node %p: %s\n",n,n->label().data());
- //}
-
- delete m_rootNodes;
- delete m_usedNodes;
- delete m_rootSubgraphs;
-}
-
-//--------------------------------------------------------------------
-
-void DotClassGraph::addClass(const ClassDef *cd,DotNode *n,int prot,
- const char *label,const char *usedName,const char *templSpec,bool base,int distance)
-{
- if (Config_getBool(HIDE_UNDOC_CLASSES) && !cd->isLinkable()) return;
-
- int edgeStyle = (label || prot==EdgeInfo::Orange || prot==EdgeInfo::Orange2) ? EdgeInfo::Dashed : EdgeInfo::Solid;
- QCString className;
- if (cd->isAnonymous())
- {
- className="anonymous:";
- className+=label;
- }
- else if (usedName) // name is a typedef
- {
- className=usedName;
- }
- else if (templSpec) // name has a template part
- {
- className=insertTemplateSpecifierInScope(cd->name(),templSpec);
- }
- else // just a normal name
- {
- className=cd->displayName();
- }
- //printf("DotClassGraph::addClass(class=`%s',parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n",
- // className.data(),n->m_label.data(),prot,label,distance,usedName,templSpec,base);
- DotNode *bn = m_usedNodes->find(className);
- if (bn) // class already inserted
- {
- if (base)
- {
- n->addChild(bn,prot,edgeStyle,label);
- bn->addParent(n);
- }
- else
- {
- bn->addChild(n,prot,edgeStyle,label);
- n->addParent(bn);
- }
- bn->setDistance(distance);
- //printf(" add exiting node %s of %s\n",bn->m_label.data(),n->m_label.data());
- }
- else // new class
- {
- QCString displayName=className;
- if (Config_getBool(HIDE_SCOPE_NAMES)) displayName=stripScope(displayName);
- QCString tmp_url;
- if (cd->isLinkable() && !cd->isHidden())
- {
- tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
- if (!cd->anchor().isEmpty())
- {
- tmp_url+="#"+cd->anchor();
- }
- }
- QCString tooltip = cd->briefDescriptionAsTooltip();
- bn = new DotNode(getNextNodeNumber(),
- displayName,
- tooltip,
- tmp_url.data(),
- FALSE, // rootNode
- cd
- );
- if (base)
- {
- n->addChild(bn,prot,edgeStyle,label);
- bn->addParent(n);
- }
- else
- {
- bn->addChild(n,prot,edgeStyle,label);
- n->addParent(bn);
- }
- bn->setDistance(distance);
- m_usedNodes->insert(className,bn);
- //printf(" add new child node `%s' to %s hidden=%d url=%s\n",
- // className.data(),n->m_label.data(),cd->isHidden(),tmp_url.data());
-
- buildGraph(cd,bn,base,distance+1);
- }
-}
-
-void DotClassGraph::determineTruncatedNodes(QList<DotNode> &queue,bool includeParents)
-{
- while (queue.count()>0)
- {
- DotNode *n = queue.take(0);
- if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
- {
- bool truncated = FALSE;
- if (n->m_children)
- {
- QListIterator<DotNode> li(*n->m_children);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- if (!dn->isVisible())
- truncated = TRUE;
- else
- queue.append(dn);
- }
- }
- if (n->m_parents && includeParents)
- {
- QListIterator<DotNode> li(*n->m_parents);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- if (!dn->isVisible())
- truncated = TRUE;
- else
- queue.append(dn);
- }
- }
- n->markAsTruncated(truncated);
- }
- }
-}
-
-bool DotClassGraph::determineVisibleNodes(DotNode *rootNode,
- int maxNodes,bool includeParents)
-{
- QList<DotNode> childQueue;
- QList<DotNode> parentQueue;
- QArray<int> childTreeWidth;
- QArray<int> parentTreeWidth;
- childQueue.append(rootNode);
- if (includeParents) parentQueue.append(rootNode);
- bool firstNode=TRUE; // flag to force reprocessing rootNode in the parent loop
- // despite being marked visible in the child loop
- while ((childQueue.count()>0 || parentQueue.count()>0) && maxNodes>0)
- {
- static int maxDistance = Config_getInt(MAX_DOT_GRAPH_DEPTH);
- if (childQueue.count()>0)
- {
- DotNode *n = childQueue.take(0);
- int distance = n->distance();
- if (!n->isVisible() && distance<=maxDistance) // not yet processed
- {
- if (distance>0)
- {
- int oldSize=(int)childTreeWidth.size();
- if (distance>oldSize)
- {
- childTreeWidth.resize(QMAX(childTreeWidth.size(),(uint)distance));
- int i; for (i=oldSize;i<distance;i++) childTreeWidth[i]=0;
- }
- childTreeWidth[distance-1]+=n->label().length();
- }
- n->markAsVisible();
- maxNodes--;
- // add direct children
- if (n->m_children)
- {
- QListIterator<DotNode> li(*n->m_children);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- childQueue.append(dn);
- }
- }
- }
- }
- if (includeParents && parentQueue.count()>0)
- {
- DotNode *n = parentQueue.take(0);
- if ((!n->isVisible() || firstNode) && n->distance()<=maxDistance) // not yet processed
- {
- firstNode=FALSE;
- int distance = n->distance();
- if (distance>0)
- {
- int oldSize = (int)parentTreeWidth.size();
- if (distance>oldSize)
- {
- parentTreeWidth.resize(QMAX(parentTreeWidth.size(),(uint)distance));
- int i; for (i=oldSize;i<distance;i++) parentTreeWidth[i]=0;
- }
- parentTreeWidth[distance-1]+=n->label().length();
- }
- n->markAsVisible();
- maxNodes--;
- // add direct parents
- if (n->m_parents)
- {
- QListIterator<DotNode> li(*n->m_parents);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- parentQueue.append(dn);
- }
- }
- }
- }
- }
- if (Config_getBool(UML_LOOK)) return FALSE; // UML graph are always top to bottom
- int maxWidth=0;
- int maxHeight=(int)QMAX(childTreeWidth.size(),parentTreeWidth.size());
- uint i;
- for (i=0;i<childTreeWidth.size();i++)
- {
- if (childTreeWidth.at(i)>maxWidth) maxWidth=childTreeWidth.at(i);
- }
- for (i=0;i<parentTreeWidth.size();i++)
- {
- if (parentTreeWidth.at(i)>maxWidth) maxWidth=parentTreeWidth.at(i);
- }
- //printf("max tree width=%d, max tree height=%d\n",maxWidth,maxHeight);
- return maxWidth>80 && maxHeight<12; // used metric to decide to render the tree
- // from left to right instead of top to bottom,
- // with the idea to render very wide trees in
- // left to right order.
-}
-
-void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance)
-{
- static bool templateRelations = Config_getBool(TEMPLATE_RELATIONS);
- //printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n",
- // cd->name().data(),distance,base);
- // ---- Add inheritance relations
-
- if (m_graphType == DotNode::Inheritance || m_graphType==DotNode::Collaboration)
- {
- BaseClassList *bcl = base ? cd->baseClasses() : cd->subClasses();
- if (bcl)
- {
- BaseClassListIterator bcli(*bcl);
- BaseClassDef *bcd;
- for ( ; (bcd=bcli.current()) ; ++bcli )
- {
- //printf("-------- inheritance relation %s->%s templ=`%s'\n",
- // cd->name().data(),bcd->classDef->name().data(),bcd->templSpecifiers.data());
- addClass(bcd->classDef,n,bcd->prot,0,bcd->usedName,
- bcd->templSpecifiers,base,distance);
- }
- }
- }
- if (m_graphType == DotNode::Collaboration)
- {
- // ---- Add usage relations
-
- UsesClassDict *dict =
- base ? cd->usedImplementationClasses() :
- cd->usedByImplementationClasses()
- ;
- if (dict)
- {
- UsesClassDictIterator ucdi(*dict);
- UsesClassDef *ucd;
- for (;(ucd=ucdi.current());++ucdi)
- {
- QCString label;
- QDictIterator<void> dvi(*ucd->accessors);
- const char *s;
- bool first=TRUE;
- int count=0;
- int maxLabels=10;
- for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
- {
- if (first)
- {
- label=s;
- first=FALSE;
- }
- else
- {
- label+=QCString("\n")+s;
- }
- }
- if (count==maxLabels) label+="\n...";
- //printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
- addClass(ucd->classDef,n,EdgeInfo::Purple,label,0,
- ucd->templSpecifiers,base,distance);
- }
- }
- }
- if (templateRelations && base)
- {
- ConstraintClassDict *dict = cd->templateTypeConstraints();
- if (dict)
- {
- ConstraintClassDictIterator ccdi(*dict);
- ConstraintClassDef *ccd;
- for (;(ccd=ccdi.current());++ccdi)
- {
- QCString label;
- QDictIterator<void> dvi(*ccd->accessors);
- const char *s;
- bool first=TRUE;
- int count=0;
- int maxLabels=10;
- for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
- {
- if (first)
- {
- label=s;
- first=FALSE;
- }
- else
- {
- label+=QCString("\n")+s;
- }
- }
- if (count==maxLabels) label+="\n...";
- //printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
- addClass(ccd->classDef,n,EdgeInfo::Orange2,label,0,
- 0,TRUE,distance);
- }
- }
- }
-
- // ---- Add template instantiation relations
-
- if (templateRelations)
- {
- if (base) // template relations for base classes
- {
- const ClassDef *templMaster=cd->templateMaster();
- if (templMaster)
- {
- QDictIterator<ClassDef> cli(*templMaster->getTemplateInstances());
- const ClassDef *templInstance;
- for (;(templInstance=cli.current());++cli)
- {
- if (templInstance==cd)
- {
- addClass(templMaster,n,EdgeInfo::Orange,cli.currentKey(),0,
- 0,TRUE,distance);
- }
- }
- }
- }
- else // template relations for super classes
- {
- const QDict<ClassDef> *templInstances = cd->getTemplateInstances();
- if (templInstances)
- {
- QDictIterator<ClassDef> cli(*templInstances);
- const ClassDef *templInstance;
- for (;(templInstance=cli.current());++cli)
- {
- addClass(templInstance,n,EdgeInfo::Orange,cli.currentKey(),0,
- 0,FALSE,distance);
- }
- }
- }
- }
-}
-
-DotClassGraph::DotClassGraph(const ClassDef *cd,DotNode::GraphType t)
-{
- //printf("--------------- DotClassGraph::DotClassGraph `%s'\n",cd->displayName().data());
- m_graphType = t;
- QCString tmp_url="";
- if (cd->isLinkable() && !cd->isHidden())
- {
- tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
- if (!cd->anchor().isEmpty())
- {
- tmp_url+="#"+cd->anchor();
- }
- }
- QCString className = cd->displayName();
- QCString tooltip = cd->briefDescriptionAsTooltip();
- m_startNode = new DotNode(getNextNodeNumber(),
- className,
- tooltip,
- tmp_url.data(),
- TRUE, // is a root node
- cd
- );
- m_startNode->setDistance(0);
- m_usedNodes = new QDict<DotNode>(1009);
- m_usedNodes->insert(className,m_startNode);
-
- //printf("Root node %s\n",cd->name().data());
- //if (m_recDepth>0)
- //{
- buildGraph(cd,m_startNode,TRUE,1);
- if (t==DotNode::Inheritance) buildGraph(cd,m_startNode,FALSE,1);
- //}
-
- static int maxNodes = Config_getInt(DOT_GRAPH_MAX_NODES);
- //int directChildNodes = 1;
- //if (m_startNode->m_children!=0)
- // directChildNodes+=m_startNode->m_children->count();
- //if (t==DotNode::Inheritance && m_startNode->m_parents!=0)
- // directChildNodes+=m_startNode->m_parents->count();
- //if (directChildNodes>maxNodes) maxNodes=directChildNodes;
- //openNodeQueue.append(m_startNode);
- m_lrRank = determineVisibleNodes(m_startNode,maxNodes,t==DotNode::Inheritance);
- QList<DotNode> openNodeQueue;
- openNodeQueue.append(m_startNode);
- determineTruncatedNodes(openNodeQueue,t==DotNode::Inheritance);
-
- m_collabFileName = cd->collaborationGraphFileName();
- m_inheritFileName = cd->inheritanceGraphFileName();
-}
-
-bool DotClassGraph::isTrivial() const
-{
- static bool umlLook = Config_getBool(UML_LOOK);
- if (m_graphType==DotNode::Inheritance)
- return m_startNode->m_children==0 && m_startNode->m_parents==0;
- else
- return !umlLook && m_startNode->m_children==0;
-}
-
-bool DotClassGraph::isTooBig() const
-{
- static int maxNodes = Config_getInt(DOT_GRAPH_MAX_NODES);
- int numNodes = 0;
- numNodes+= m_startNode->m_children ? m_startNode->m_children->count() : 0;
- if (m_graphType==DotNode::Inheritance)
- {
- numNodes+= m_startNode->m_parents ? m_startNode->m_parents->count() : 0;
- }
- return numNodes>=maxNodes;
-}
-
-DotClassGraph::~DotClassGraph()
-{
- deleteNodes(m_startNode);
- delete m_usedNodes;
-}
-
-/*! Computes a 16 byte md5 checksum for a given dot graph.
- * The md5 checksum is returned as a 32 character ASCII string.
- */
-QCString computeMd5Signature(DotNode *root,
- DotNode::GraphType gt,
- GraphOutputFormat format,
- const QCString &rank, // either "LR", "RL", or ""
- bool renderParents,
- bool backArrows,
- const QCString &title,
- QCString &graphStr
- )
-{
- //printf("computeMd5Signature\n");
- QGString buf;
- FTextStream md5stream(&buf);
- writeGraphHeader(md5stream,title);
- if (!rank.isEmpty())
- {
- md5stream << " rankdir=\"" << rank << "\";" << endl;
- }
- root->clearWriteFlag();
- root->write(md5stream,
- gt,
- format,
- gt!=DotNode::CallGraph && gt!=DotNode::Dependency,
- TRUE,
- backArrows);
- if (renderParents && root->m_parents)
- {
- QListIterator<DotNode> dnli(*root->m_parents);
- DotNode *pn;
- for (dnli.toFirst();(pn=dnli.current());++dnli)
- {
- if (pn->isVisible())
- {
- root->writeArrow(md5stream, // stream
- gt, // graph type
- format, // output format
- pn, // child node
- pn->m_edgeInfo->at(pn->m_children->findRef(root)), // edge info
- FALSE, // topDown?
- backArrows // point back?
- );
- }
- pn->write(md5stream, // stream
- gt, // graph type
- format, // output format
- TRUE, // topDown?
- FALSE, // toChildren?
- backArrows // backward pointing arrows?
- );
- }
- }
- writeGraphFooter(md5stream);
- uchar md5_sig[16];
- QCString sigStr(33);
- MD5Buffer((const unsigned char *)buf.data(),buf.length(),md5_sig);
- MD5SigToString(md5_sig,sigStr.rawData(),33);
- graphStr=buf.data();
- //printf("md5: %s | file: %s\n",sigStr,baseName.data());
- return sigStr;
-}
-
-static bool updateDotGraph(DotNode *root,
- DotNode::GraphType gt,
- const QCString &baseName,
- GraphOutputFormat format,
- const QCString &rank,
- bool renderParents,
- bool backArrows,
- const QCString &title=QCString()
- )
-{
- QCString theGraph;
- // TODO: write graph to theGraph, then compute md5 checksum
- QCString md5 = computeMd5Signature(
- root,gt,format,rank,renderParents,
- backArrows,title,theGraph);
- QFile f(baseName+".dot");
- if (f.open(IO_WriteOnly))
- {
- FTextStream t(&f);
- t << theGraph;
- }
- return checkAndUpdateMd5Signature(baseName,md5); // graph needs to be regenerated
-}
-
-QCString DotClassGraph::writeGraph(FTextStream &out,
- GraphOutputFormat graphFormat,
- EmbeddedOutputFormat textFormat,
- const char *path,
- const char *fileName,
- const char *relPath,
- bool /*isTBRank*/,
- bool generateImageMap,
- int graphId) const
-{
- QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
- static bool usePDFLatex = Config_getBool(USE_PDFLATEX);
-
- QCString baseName;
- QCString mapName;
- switch (m_graphType)
- {
- case DotNode::Collaboration:
- mapName="coll_map";
- baseName=m_collabFileName;
- break;
- case DotNode::Inheritance:
- mapName="inherit_map";
- baseName=m_inheritFileName;
- break;
- default:
- ASSERT(0);
- break;
- }
-
- // derive target file names from baseName
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- QCString absBaseName = d.absPath().utf8()+"/"+baseName;
- QCString absDotName = absBaseName+".dot";
- QCString absMapName = absBaseName+".map";
- QCString absPdfName = absBaseName+".pdf";
- QCString absEpsName = absBaseName+".eps";
- QCString absImgName = absBaseName+"."+imgExt;
-
- bool regenerate = FALSE;
- if (updateDotGraph(m_startNode,
- m_graphType,
- absBaseName,
- graphFormat,
- m_lrRank ? "LR" : "",
- m_graphType==DotNode::Inheritance,
- TRUE,
- m_startNode->label()
- ) ||
- !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName :
- usePDFLatex ? absPdfName : absEpsName,
- graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString())
- )
- {
- regenerate=TRUE;
- if (graphFormat==GOF_BITMAP) // run dot to create a bitmap image
- {
- DotRunner *dotRun = new DotRunner(absDotName,
- d.absPath().data(),TRUE,absImgName);
- dotRun->addJob(imgFmt,absImgName);
- if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName);
- DotManager::instance()->addRun(dotRun);
-
- }
- else if (graphFormat==GOF_EPS) // run dot to create a .eps image
- {
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE);
- if (usePDFLatex)
- {
- dotRun->addJob("pdf",absPdfName,absBaseName);
- }
- else
- {
- dotRun->addJob("ps",absEpsName);
- }
- DotManager::instance()->addRun(dotRun);
- }
- }
- Doxygen::indexList->addImageFile(baseName+"."+imgExt);
-
- if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
- {
- out << "<para>" << endl;
- out << " <informalfigure>" << endl;
- out << " <mediaobject>" << endl;
- out << " <imageobject>" << endl;
- out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
- out << "</imagedata>" << endl;
- out << " </imageobject>" << endl;
- out << " </mediaobject>" << endl;
- out << " </informalfigure>" << endl;
- out << "</para>" << endl;
- }
- else if (graphFormat==GOF_BITMAP && generateImageMap) // produce HTML to include the image
- {
- QCString mapLabel = escapeCharsInString(m_startNode->m_label,FALSE)+"_"+
- escapeCharsInString(mapName,FALSE);
- if (imgExt=="svg") // add link to SVG file without map file
- {
- out << "<div class=\"center\">";
- if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file
- {
- if (regenerate)
- {
- DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId);
- }
- int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath);
- out << "<!-- SVG " << mapId << " -->" << endl;
- }
- out << "</div>" << endl;
- }
- else // add link to bitmap file with image map
- {
- out << "<div class=\"center\">";
- out << "<img src=\"" << relPath << baseName << "."
- << imgExt << "\" border=\"0\" usemap=\"#"
- << mapLabel << "\" alt=\"";
- switch (m_graphType)
- {
- case DotNode::Collaboration:
- out << "Collaboration graph";
- break;
- case DotNode::Inheritance:
- out << "Inheritance graph";
- break;
- default:
- ASSERT(0);
- break;
- }
- out << "\"/>";
- out << "</div>" << endl;
- if (regenerate || !insertMapFile(out,absMapName,relPath,mapLabel))
- {
- int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath,
- FALSE,QCString(),mapLabel);
- out << "<!-- MAP " << mapId << " -->" << endl;
- }
- }
- }
- else if (graphFormat==GOF_EPS) // produce tex to include the .eps image
- {
- if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName))
- {
- int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE /*TRUE*/);
- out << endl << "% FIG " << figId << endl;
- }
- }
- if (!regenerate) removeDotGraph(absDotName);
-
- return baseName;
-}
-
-//--------------------------------------------------------------------
-
-void DotClassGraph::writeXML(FTextStream &t)
-{
- QDictIterator<DotNode> dni(*m_usedNodes);
- DotNode *node;
- for (;(node=dni.current());++dni)
- {
- node->writeXML(t,TRUE);
- }
-}
-
-void DotClassGraph::writeDocbook(FTextStream &t)
-{
- QDictIterator<DotNode> dni(*m_usedNodes);
- DotNode *node;
- for (;(node=dni.current());++dni)
- {
- node->writeDocbook(t,TRUE);
- }
-}
-
-void DotClassGraph::writeDEF(FTextStream &t)
-{
- QDictIterator<DotNode> dni(*m_usedNodes);
- DotNode *node;
- for (;(node=dni.current());++dni)
- {
- node->writeDEF(t);
- }
-}
-
-//--------------------------------------------------------------------
-
-void DotInclDepGraph::buildGraph(DotNode *n,const FileDef *fd,int distance)
-{
- QList<IncludeInfo> *includeFiles =
- m_inverse ? fd->includedByFileList() : fd->includeFileList();
- if (includeFiles)
- {
- QListIterator<IncludeInfo> ili(*includeFiles);
- IncludeInfo *ii;
- for (;(ii=ili.current());++ili)
- {
- const FileDef *bfd = ii->fileDef;
- QCString in = ii->includeName;
- //printf(">>>> in=`%s' bfd=%p\n",ii->includeName.data(),bfd);
- bool doc=TRUE,src=FALSE;
- if (bfd)
- {
- in = bfd->absFilePath();
- doc = bfd->isLinkable() && !bfd->isHidden();
- src = bfd->generateSourceFile();
- }
- if (doc || src || !Config_getBool(HIDE_UNDOC_RELATIONS))
- {
- QCString url="";
- if (bfd) url=bfd->getOutputFileBase().copy();
- if (!doc && src)
- {
- url=bfd->getSourceFileBase();
- }
- DotNode *bn = m_usedNodes->find(in);
- if (bn) // file is already a node in the graph
- {
- n->addChild(bn,0,0,0);
- bn->addParent(n);
- bn->setDistance(distance);
- }
- else
- {
- QCString tmp_url;
- QCString tooltip;
- if (bfd)
- {
- tmp_url=doc || src ? bfd->getReference()+"$"+url : QCString();
- tooltip = bfd->briefDescriptionAsTooltip();
- }
- bn = new DotNode(
- getNextNodeNumber(),// n
- ii->includeName, // label
- tooltip, // tip
- tmp_url, // url
- FALSE, // rootNode
- 0 // cd
- );
- n->addChild(bn,0,0,0);
- bn->addParent(n);
- m_usedNodes->insert(in,bn);
- bn->setDistance(distance);
-
- if (bfd) buildGraph(bn,bfd,distance+1);
- }
- }
- }
- }
-}
-
-void DotInclDepGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes)
-{
- while (queue.count()>0 && maxNodes>0)
- {
- static int maxDistance = Config_getInt(MAX_DOT_GRAPH_DEPTH);
- DotNode *n = queue.take(0);
- if (!n->isVisible() && n->distance()<=maxDistance) // not yet processed
- {
- n->markAsVisible();
- maxNodes--;
- // add direct children
- if (n->m_children)
- {
- QListIterator<DotNode> li(*n->m_children);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- queue.append(dn);
- }
- }
- }
- }
-}
-
-void DotInclDepGraph::determineTruncatedNodes(QList<DotNode> &queue)
-{
- while (queue.count()>0)
- {
- DotNode *n = queue.take(0);
- if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
- {
- bool truncated = FALSE;
- if (n->m_children)
- {
- QListIterator<DotNode> li(*n->m_children);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- if (!dn->isVisible())
- truncated = TRUE;
- else
- queue.append(dn);
- }
- }
- n->markAsTruncated(truncated);
- }
- }
-}
-
-DotInclDepGraph::DotInclDepGraph(const FileDef *fd,bool inverse)
-{
- m_inverse = inverse;
- ASSERT(fd!=0);
- m_inclDepFileName = fd->includeDependencyGraphFileName();
- m_inclByDepFileName = fd->includedByDependencyGraphFileName();
- QCString tmp_url=fd->getReference()+"$"+fd->getOutputFileBase();
- QCString tooltip = fd->briefDescriptionAsTooltip();
- m_startNode = new DotNode(getNextNodeNumber(),
- fd->docName(),
- tooltip,
- tmp_url.data(),
- TRUE // root node
- );
- m_startNode->setDistance(0);
- m_usedNodes = new QDict<DotNode>(1009);
- m_usedNodes->insert(fd->absFilePath(),m_startNode);
- buildGraph(m_startNode,fd,1);
-
- static int nodes = Config_getInt(DOT_GRAPH_MAX_NODES);
- int maxNodes = nodes;
- //int directChildNodes = 1;
- //if (m_startNode->m_children!=0)
- // directChildNodes+=m_startNode->m_children->count();
- //if (directChildNodes>maxNodes) maxNodes=directChildNodes;
- QList<DotNode> openNodeQueue;
- openNodeQueue.append(m_startNode);
- determineVisibleNodes(openNodeQueue,maxNodes);
- openNodeQueue.clear();
- openNodeQueue.append(m_startNode);
- determineTruncatedNodes(openNodeQueue);
-}
-
-DotInclDepGraph::~DotInclDepGraph()
-{
- deleteNodes(m_startNode);
- delete m_usedNodes;
-}
-
-QCString DotInclDepGraph::writeGraph(FTextStream &out,
- GraphOutputFormat graphFormat,
- EmbeddedOutputFormat textFormat,
- const char *path,
- const char *fileName,
- const char *relPath,
- bool generateImageMap,
- int graphId
- ) const
-{
- QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
- static bool usePDFLatex = Config_getBool(USE_PDFLATEX);
-
- QCString baseName;
- if (m_inverse)
- {
- baseName=m_inclByDepFileName;
- }
- else
- {
- baseName=m_inclDepFileName;
- }
- QCString mapName=escapeCharsInString(m_startNode->m_label,FALSE);
- if (m_inverse) mapName+="dep";
-
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- QCString absBaseName = d.absPath().utf8()+"/"+baseName;
- QCString absDotName = absBaseName+".dot";
- QCString absMapName = absBaseName+".map";
- QCString absPdfName = absBaseName+".pdf";
- QCString absEpsName = absBaseName+".eps";
- QCString absImgName = absBaseName+"."+imgExt;
-
- bool regenerate = FALSE;
- if (updateDotGraph(m_startNode,
- DotNode::Dependency,
- absBaseName,
- graphFormat,
- "", // lrRank
- FALSE, // renderParents
- m_inverse, // backArrows
- m_startNode->label()
- ) ||
- !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName :
- usePDFLatex ? absPdfName : absEpsName,
- graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString())
- )
- {
- regenerate=TRUE;
- if (graphFormat==GOF_BITMAP)
- {
- // run dot to create a bitmap image
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName);
- dotRun->addJob(imgFmt,absImgName);
- if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName);
- DotManager::instance()->addRun(dotRun);
- }
- else if (graphFormat==GOF_EPS)
- {
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE);
- if (usePDFLatex)
- {
- dotRun->addJob("pdf",absPdfName,absBaseName);
- }
- else
- {
- dotRun->addJob("ps",absEpsName);
- }
- DotManager::instance()->addRun(dotRun);
- }
- }
- Doxygen::indexList->addImageFile(baseName+"."+imgExt);
-
- if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
- {
- out << "<para>" << endl;
- out << " <informalfigure>" << endl;
- out << " <mediaobject>" << endl;
- out << " <imageobject>" << endl;
- out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
- out << "</imagedata>" << endl;
- out << " </imageobject>" << endl;
- out << " </mediaobject>" << endl;
- out << " </informalfigure>" << endl;
- out << "</para>" << endl;
- }
- else if (graphFormat==GOF_BITMAP && generateImageMap)
- {
- if (imgExt=="svg") // Scalable vector graphics
- {
- out << "<div class=\"center\">";
- if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file
- {
- if (regenerate)
- {
- DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId);
- }
- int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath);
- out << "<!-- SVG " << mapId << " -->" << endl;
- }
- out << "</div>" << endl;
- }
- else // bitmap graphics
- {
- out << "<div class=\"center\"><img src=\"" << relPath << baseName << "." << imgExt << "\" border=\"0\" usemap=\"#" << mapName << "\" alt=\"\"/>";
- out << "</div>" << endl;
-
- QCString absMapName = absBaseName+".map";
- if (regenerate || !insertMapFile(out,absMapName,relPath,mapName))
- {
- int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath,
- FALSE,QCString(),mapName);
- out << "<!-- MAP " << mapId << " -->" << endl;
- }
- }
- }
- else if (graphFormat==GOF_EPS) // encapsulated postscript
- {
- if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName))
- {
- int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE);
- out << endl << "% FIG " << figId << endl;
- }
- }
- if (!regenerate) removeDotGraph(absDotName);
-
- return baseName;
-}
-
-bool DotInclDepGraph::isTrivial() const
-{
- return m_startNode->m_children==0;
-}
-
-bool DotInclDepGraph::isTooBig() const
-{
- static int maxNodes = Config_getInt(DOT_GRAPH_MAX_NODES);
- int numNodes = m_startNode->m_children ? m_startNode->m_children->count() : 0;
- return numNodes>=maxNodes;
-}
-
-void DotInclDepGraph::writeXML(FTextStream &t)
-{
- QDictIterator<DotNode> dni(*m_usedNodes);
- DotNode *node;
- for (;(node=dni.current());++dni)
- {
- node->writeXML(t,FALSE);
- }
-}
-
-void DotInclDepGraph::writeDocbook(FTextStream &t)
-{
- QDictIterator<DotNode> dni(*m_usedNodes);
- DotNode *node;
- for (;(node=dni.current());++dni)
- {
- node->writeDocbook(t,FALSE);
- }
-}
-
-//-------------------------------------------------------------
-
-void DotCallGraph::buildGraph(DotNode *n,const MemberDef *md,int distance)
-{
- MemberSDict *refs = m_inverse ? md->getReferencedByMembers() : md->getReferencesMembers();
- if (refs)
- {
- refs->sort();
- MemberSDict::Iterator mri(*refs);
- MemberDef *rmd;
- for (;(rmd=mri.current());++mri)
- {
- if (rmd->showInCallGraph())
- {
- QCString uniqueId;
- uniqueId=rmd->getReference()+"$"+
- rmd->getOutputFileBase()+"#"+rmd->anchor();
- DotNode *bn = m_usedNodes->find(uniqueId);
- if (bn) // file is already a node in the graph
- {
- n->addChild(bn,0,0,0);
- bn->addParent(n);
- bn->setDistance(distance);
- }
- else
- {
- QCString name;
- if (Config_getBool(HIDE_SCOPE_NAMES))
- {
- name = rmd->getOuterScope()==m_scope ?
- rmd->name() : rmd->qualifiedName();
- }
- else
- {
- name = rmd->qualifiedName();
- }
- QCString tooltip = rmd->briefDescriptionAsTooltip();
- bn = new DotNode(
- getNextNodeNumber(),
- linkToText(rmd->getLanguage(),name,FALSE),
- tooltip,
- uniqueId,
- 0 //distance
- );
- n->addChild(bn,0,0,0);
- bn->addParent(n);
- bn->setDistance(distance);
- m_usedNodes->insert(uniqueId,bn);
-
- buildGraph(bn,rmd,distance+1);
- }
- }
- }
- }
-}
-
-void DotCallGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes)
-{
- while (queue.count()>0 && maxNodes>0)
- {
- static int maxDistance = Config_getInt(MAX_DOT_GRAPH_DEPTH);
- DotNode *n = queue.take(0);
- if (!n->isVisible() && n->distance()<=maxDistance) // not yet processed
- {
- n->markAsVisible();
- maxNodes--;
- // add direct children
- if (n->m_children)
- {
- QListIterator<DotNode> li(*n->m_children);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- queue.append(dn);
- }
- }
- }
- }
-}
-
-void DotCallGraph::determineTruncatedNodes(QList<DotNode> &queue)
-{
- while (queue.count()>0)
- {
- DotNode *n = queue.take(0);
- if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
- {
- bool truncated = FALSE;
- if (n->m_children)
- {
- QListIterator<DotNode> li(*n->m_children);
- DotNode *dn;
- for (li.toFirst();(dn=li.current());++li)
- {
- if (!dn->isVisible())
- truncated = TRUE;
- else
- queue.append(dn);
- }
- }
- n->markAsTruncated(truncated);
- }
- }
-}
-
-DotCallGraph::DotCallGraph(const MemberDef *md,bool inverse)
-{
- m_inverse = inverse;
- m_diskName = md->getOutputFileBase()+"_"+md->anchor();
- m_scope = md->getOuterScope();
- QCString uniqueId;
- uniqueId = md->getReference()+"$"+
- md->getOutputFileBase()+"#"+md->anchor();
- QCString name;
- if (Config_getBool(HIDE_SCOPE_NAMES))
- {
- name = md->name();
- }
- else
- {
- name = md->qualifiedName();
- }
- QCString tooltip = md->briefDescriptionAsTooltip();
- m_startNode = new DotNode(getNextNodeNumber(),
- linkToText(md->getLanguage(),name,FALSE),
- tooltip,
- uniqueId.data(),
- TRUE // root node
- );
- m_startNode->setDistance(0);
- m_usedNodes = new QDict<DotNode>(1009);
- m_usedNodes->insert(uniqueId,m_startNode);
- buildGraph(m_startNode,md,1);
-
- static int nodes = Config_getInt(DOT_GRAPH_MAX_NODES);
- int maxNodes = nodes;
- //int directChildNodes = 1;
- //if (m_startNode->m_children!=0)
- // directChildNodes+=m_startNode->m_children->count();
- //if (directChildNodes>maxNodes) maxNodes=directChildNodes;
- QList<DotNode> openNodeQueue;
- openNodeQueue.append(m_startNode);
- determineVisibleNodes(openNodeQueue,maxNodes);
- openNodeQueue.clear();
- openNodeQueue.append(m_startNode);
- determineTruncatedNodes(openNodeQueue);
-}
-
-DotCallGraph::~DotCallGraph()
-{
- deleteNodes(m_startNode);
- delete m_usedNodes;
-}
-
-QCString DotCallGraph::writeGraph(FTextStream &out, GraphOutputFormat graphFormat,
- EmbeddedOutputFormat textFormat,
- const char *path,const char *fileName,
- const char *relPath,bool generateImageMap,int
- graphId) const
-{
- QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
- static bool usePDFLatex = Config_getBool(USE_PDFLATEX);
-
- QCString baseName = m_diskName + (m_inverse ? "_icgraph" : "_cgraph");
- QCString mapName = baseName;
-
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- QCString absBaseName = d.absPath().utf8()+"/"+baseName;
- QCString absDotName = absBaseName+".dot";
- QCString absMapName = absBaseName+".map";
- QCString absPdfName = absBaseName+".pdf";
- QCString absEpsName = absBaseName+".eps";
- QCString absImgName = absBaseName+"."+imgExt;
-
- bool regenerate = FALSE;
-
- if (updateDotGraph(m_startNode,
- DotNode::CallGraph,
- absBaseName,
- graphFormat,
- m_inverse ? "RL" : "LR", // lrRank
- FALSE, // renderParents
- m_inverse, // backArrows
- m_startNode->label()
- ) ||
- !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName :
- usePDFLatex ? absPdfName : absEpsName,
- graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString())
- )
- {
- regenerate=TRUE;
- if (graphFormat==GOF_BITMAP)
- {
- // run dot to create a bitmap image
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName);
- dotRun->addJob(imgFmt,absImgName);
- if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName);
- DotManager::instance()->addRun(dotRun);
-
- }
- else if (graphFormat==GOF_EPS)
- {
- // run dot to create a .eps image
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE);
- if (usePDFLatex)
- {
- dotRun->addJob("pdf",absPdfName,absBaseName);
- }
- else
- {
- dotRun->addJob("ps",absEpsName);
- }
- DotManager::instance()->addRun(dotRun);
-
- }
- }
- Doxygen::indexList->addImageFile(baseName+"."+imgExt);
-
- if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
- {
- out << "<para>" << endl;
- out << " <informalfigure>" << endl;
- out << " <mediaobject>" << endl;
- out << " <imageobject>" << endl;
- out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
- out << "</imagedata>" << endl;
- out << " </imageobject>" << endl;
- out << " </mediaobject>" << endl;
- out << " </informalfigure>" << endl;
- out << "</para>" << endl;
- }
- else if (graphFormat==GOF_BITMAP && generateImageMap)
- {
- if (imgExt=="svg") // Scalable vector graphics
- {
- out << "<div class=\"center\">";
- if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file
- {
- if (regenerate)
- {
- DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId);
- }
- int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath);
- out << "<!-- SVG " << mapId << " -->" << endl;
- }
- out << "</div>" << endl;
- }
- else // bitmap graphics
- {
- out << "<div class=\"center\"><img src=\"" << relPath << baseName << "."
- << imgExt << "\" border=\"0\" usemap=\"#"
- << mapName << "\" alt=\"";
- out << "\"/>";
- out << "</div>" << endl;
-
- if (regenerate || !insertMapFile(out,absMapName,relPath,mapName))
- {
- int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath,
- FALSE,QCString(),mapName);
- out << "<!-- MAP " << mapId << " -->" << endl;
- }
- }
- }
- else if (graphFormat==GOF_EPS) // encapsulated postscript
- {
- if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName))
- {
- int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE);
- out << endl << "% FIG " << figId << endl;
- }
- }
- if (!regenerate) removeDotGraph(absDotName);
-
- return baseName;
-}
-
-bool DotCallGraph::isTrivial() const
-{
- return m_startNode->m_children==0;
-}
-
-bool DotCallGraph::isTooBig() const
-{
- static int maxNodes = Config_getInt(DOT_GRAPH_MAX_NODES);
- int numNodes = m_startNode->m_children ? m_startNode->m_children->count() : 0;
- return numNodes>=maxNodes;
-}
-
-//-------------------------------------------------------------
-static void writeDotDirDepGraph(FTextStream &t,const DirDef *dd,bool linkRelations);
-
-DotDirDeps::DotDirDeps(const DirDef *dir) : m_dir(dir)
-{
-}
-
-DotDirDeps::~DotDirDeps()
-{
-}
-
-QCString DotDirDeps::writeGraph(FTextStream &out,
- GraphOutputFormat graphFormat,
- EmbeddedOutputFormat textFormat,
- const char *path,
- const char *fileName,
- const char *relPath,
- bool generateImageMap,
- int graphId,
- bool linkRelations) const
-{
- QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
- static bool usePDFLatex = Config_getBool(USE_PDFLATEX);
-
- QCString baseName=m_dir->getOutputFileBase()+"_dep";
- QCString mapName=escapeCharsInString(baseName,FALSE);
-
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- QCString absBaseName = d.absPath().utf8()+"/"+baseName;
- QCString absDotName = absBaseName+".dot";
- QCString absMapName = absBaseName+".map";
- QCString absPdfName = absBaseName+".pdf";
- QCString absEpsName = absBaseName+".eps";
- QCString absImgName = absBaseName+"."+imgExt;
-
- // compute md5 checksum of the graph were are about to generate
- QGString theGraph;
- FTextStream md5stream(&theGraph);
- //m_dir->writeDepGraph(md5stream);
- writeDotDirDepGraph(md5stream,m_dir,linkRelations);
- uchar md5_sig[16];
- QCString sigStr(33);
- MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
- MD5SigToString(md5_sig,sigStr.rawData(),33);
- bool regenerate=FALSE;
- if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
- !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName :
- usePDFLatex ? absPdfName : absEpsName,
- graphFormat==GOF_BITMAP && generateImageMap ? absMapName : QCString())
- )
- {
- regenerate=TRUE;
-
- QFile f(absDotName);
- if (!f.open(IO_WriteOnly))
- {
- err("Cannot create file %s.dot for writing!\n",baseName.data());
- }
- FTextStream t(&f);
- t << theGraph.data();
- f.close();
-
- if (graphFormat==GOF_BITMAP)
- {
- // run dot to create a bitmap image
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName);
- dotRun->addJob(imgFmt,absImgName);
- if (generateImageMap) dotRun->addJob(MAP_CMD,absMapName);
- DotManager::instance()->addRun(dotRun);
- }
- else if (graphFormat==GOF_EPS)
- {
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE);
- if (usePDFLatex)
- {
- dotRun->addJob("pdf",absPdfName,absBaseName);
- }
- else
- {
- dotRun->addJob("ps",absEpsName);
- }
- DotManager::instance()->addRun(dotRun);
- }
- }
- Doxygen::indexList->addImageFile(baseName+"."+imgExt);
-
- if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
- {
- out << "<para>" << endl;
- out << " <informalfigure>" << endl;
- out << " <mediaobject>" << endl;
- out << " <imageobject>" << endl;
- out << " <imagedata";
- out << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
- out << "</imagedata>" << endl;
- out << " </imageobject>" << endl;
- out << " </mediaobject>" << endl;
- out << " </informalfigure>" << endl;
- out << "</para>" << endl;
- }
- else if (graphFormat==GOF_BITMAP && generateImageMap)
- {
- if (imgExt=="svg") // Scalable vector graphics
- {
- out << "<div class=\"center\">";
- if (regenerate || !writeSVGFigureLink(out,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file
- {
- if (regenerate)
- {
- DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId);
- }
- int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath);
- out << "<!-- SVG " << mapId << " -->" << endl;
- }
- out << "</div>" << endl;
- }
- else // bitmap graphics
- {
- out << "<div class=\"center\"><img src=\"" << relPath << baseName << "."
- << imgExt << "\" border=\"0\" usemap=\"#"
- << mapName << "\" alt=\"";
- out << convertToXML(m_dir->displayName());
- out << "\"/>";
- out << "</div>" << endl;
-
- if (regenerate || !insertMapFile(out,absMapName,relPath,mapName))
- {
- int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath,
- TRUE,QCString(),mapName);
- out << "<!-- MAP " << mapId << " -->" << endl;
- }
- }
- }
- else if (graphFormat==GOF_EPS)
- {
- if (regenerate || !writeVecGfxFigure(out,baseName,absBaseName))
- {
- int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE);
- out << endl << "% FIG " << figId << endl;
- }
- }
- if (!regenerate) removeDotGraph(absDotName);
-
- return baseName;
-}
-
-bool DotDirDeps::isTrivial() const
-{
- return m_dir->depGraphIsTrivial();
-}
-
-//-------------------------------------------------------------
+ friend void generateGraphLegend(const char* path);
+};
void generateGraphLegend(const char *path)
{
QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
+ GraphLegendDotGraph dg;
+ FTextStream ts;
+ dg.writeGraph(ts, GOF_BITMAP, EOF_Html, path, "", "", FALSE, 0);
- QGString theGraph;
- FTextStream md5stream(&theGraph);
- writeGraphHeader(md5stream,theTranslator->trLegendTitle());
- md5stream << " Node9 [shape=\"box\",label=\"Inherited\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",fillcolor=\"grey75\",style=\"filled\" fontcolor=\"black\"];\n";
- md5stream << " Node10 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node10 [shape=\"box\",label=\"PublicBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classPublicBase" << Doxygen::htmlFileExtension << "\"];\n";
- md5stream << " Node11 -> Node10 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node11 [shape=\"box\",label=\"Truncated\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"red\",URL=\"$classTruncated" << Doxygen::htmlFileExtension << "\"];\n";
- md5stream << " Node13 -> Node9 [dir=\"back\",color=\"darkgreen\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node13 [shape=\"box\",label=\"ProtectedBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classProtectedBase" << Doxygen::htmlFileExtension << "\"];\n";
- md5stream << " Node14 -> Node9 [dir=\"back\",color=\"firebrick4\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node14 [shape=\"box\",label=\"PrivateBase\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classPrivateBase" << Doxygen::htmlFileExtension << "\"];\n";
- md5stream << " Node15 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node15 [shape=\"box\",label=\"Undocumented\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"grey75\"];\n";
- md5stream << " Node16 -> Node9 [dir=\"back\",color=\"midnightblue\",fontsize=\"" << FONTSIZE << "\",style=\"solid\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node16 [shape=\"box\",label=\"Templ< int >\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n";
- md5stream << " Node17 -> Node16 [dir=\"back\",color=\"orange\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"< int >\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node17 [shape=\"box\",label=\"Templ< T >\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classTempl" << Doxygen::htmlFileExtension << "\"];\n";
- md5stream << " Node18 -> Node9 [dir=\"back\",color=\"darkorchid3\",fontsize=\"" << FONTSIZE << "\",style=\"dashed\",label=\"m_usedClass\",fontname=\"" << FONTNAME << "\"];\n";
- md5stream << " Node18 [shape=\"box\",label=\"Used\",fontsize=\"" << FONTSIZE << "\",height=0.2,width=0.4,fontname=\"" << FONTNAME << "\",color=\"black\",URL=\"$classUsed" << Doxygen::htmlFileExtension << "\"];\n";
- writeGraphFooter(md5stream);
- uchar md5_sig[16];
- QCString sigStr(33);
- MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
- MD5SigToString(md5_sig,sigStr.rawData(),33);
- QCString absBaseName = (QCString)path+"/graph_legend";
- QCString absDotName = absBaseName+".dot";
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- QCString imgName = "graph_legend."+imgExt;
- QCString absImgName = absBaseName+"."+imgExt;
- if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
- !checkDeliverables(absImgName))
- {
- QFile dotFile(absDotName);
- if (!dotFile.open(IO_WriteOnly))
- {
- err("Could not open file %s for writing\n",dotFile.name().data());
- return;
- }
-
- FTextStream dotText(&dotFile);
- dotText << theGraph;
- dotFile.close();
-
- // run dot to generate the a bitmap image from the graph
-
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),TRUE,absImgName);
- dotRun->addJob(imgFmt,absImgName);
- DotManager::instance()->addRun(dotRun);
- }
- else
- {
- removeDotGraph(absDotName);
- }
- Doxygen::indexList->addImageFile(imgName);
-
- if (imgExt=="svg")
+ if (getDotImageExtension()=="svg")
{
DotManager::instance()->addSVGObject(
- absBaseName+Config_getString(HTML_FILE_EXTENSION),
+ dg.absBaseName()+Config_getString(HTML_FILE_EXTENSION),
"graph_legend",
- absImgName,QCString());
+ dg.absImgName(),QCString());
}
}
@@ -4238,19 +493,20 @@ void writeDotGraphFromFile(const char *inFile,const char *outDir,
}
QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
QCString imgName = (QCString)outFile+"."+imgExt;
QCString absImgName = d.absPath().utf8()+"/"+imgName;
QCString absOutFile = d.absPath().utf8()+"/"+outFile;
- DotRunner dotRun(inFile,d.absPath().data(),FALSE,absImgName);
+ DotRunner dotRun(inFile, QCString());
if (format==GOF_BITMAP)
- dotRun.addJob(imgFmt,absImgName);
+ {
+ dotRun.addJob(Config_getEnum(DOT_IMAGE_FORMAT),absImgName);
+ }
else // format==GOF_EPS
{
if (Config_getBool(USE_PDFLATEX))
{
- dotRun.addJob("pdf",absOutFile+".pdf",absOutFile);
+ dotRun.addJob("pdf",absOutFile+".pdf");
}
else
{
@@ -4264,13 +520,10 @@ void writeDotGraphFromFile(const char *inFile,const char *outDir,
return;
}
- if (format==GOF_BITMAP) checkDotResult(getDotImageExtension(),absImgName);
-
Doxygen::indexList->addImageFile(imgName);
}
-
/*! Writes user defined image map to the output.
* \param t text stream to write to
* \param inFile just the basename part of the filename
@@ -4294,11 +547,10 @@ void writeDotImageMapFromFile(FTextStream &t,
QCString mapName = baseName+".map";
QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
QCString imgName = baseName+"."+imgExt;
QCString absOutFile = d.absPath().utf8()+"/"+mapName;
- DotRunner dotRun(inFile,d.absPath().data(),FALSE);
+ DotRunner dotRun(inFile, QCString());
dotRun.addJob(MAP_CMD,absOutFile);
dotRun.preventCleanUp();
if (!dotRun.run())
@@ -4333,612 +585,3 @@ void writeDotImageMapFromFile(FTextStream &t,
}
d.remove(absOutFile);
}
-
-//-------------------------------------------------------------
-
-DotGroupCollaboration::DotGroupCollaboration(const GroupDef* gd)
-{
- QCString tmp_url = gd->getReference()+"$"+gd->getOutputFileBase();
- m_usedNodes = new QDict<DotNode>(1009);
- QCString tooltip = gd->briefDescriptionAsTooltip();
- m_rootNode = new DotNode(getNextNodeNumber(), gd->groupTitle(), tooltip, tmp_url, TRUE );
- m_rootNode->markAsVisible();
- m_usedNodes->insert(gd->name(), m_rootNode );
- m_edges.setAutoDelete(TRUE);
-
- m_diskName = gd->getOutputFileBase();
-
- buildGraph( gd );
-}
-
-DotGroupCollaboration::~DotGroupCollaboration()
-{
- delete m_usedNodes;
-}
-
-void DotGroupCollaboration::buildGraph(const GroupDef* gd)
-{
- QCString tmp_url;
- //===========================
- // hierarchy.
-
- // Write parents
- const GroupList *groups = gd->partOfGroups();
- if ( groups )
- {
- GroupListIterator gli(*groups);
- const GroupDef *d;
- for (gli.toFirst();(d=gli.current());++gli)
- {
- DotNode* nnode = m_usedNodes->find(d->name());
- if ( !nnode )
- { // add node
- tmp_url = d->getReference()+"$"+d->getOutputFileBase();
- QCString tooltip = d->briefDescriptionAsTooltip();
- nnode = new DotNode(getNextNodeNumber(), d->groupTitle(), tooltip, tmp_url );
- nnode->markAsVisible();
- m_usedNodes->insert(d->name(), nnode );
- }
- tmp_url = "";
- addEdge( nnode, m_rootNode, DotGroupCollaboration::thierarchy, tmp_url, tmp_url );
- }
- }
-
- // Add subgroups
- if ( gd->getSubGroups() && gd->getSubGroups()->count() )
- {
- QListIterator<GroupDef> defli(*gd->getSubGroups());
- const GroupDef *def;
- for (;(def=defli.current());++defli)
- {
- DotNode* nnode = m_usedNodes->find(def->name());
- if ( !nnode )
- { // add node
- tmp_url = def->getReference()+"$"+def->getOutputFileBase();
- QCString tooltip = def->briefDescriptionAsTooltip();
- nnode = new DotNode(getNextNodeNumber(), def->groupTitle(), tooltip, tmp_url );
- nnode->markAsVisible();
- m_usedNodes->insert(def->name(), nnode );
- }
- tmp_url = "";
- addEdge( m_rootNode, nnode, DotGroupCollaboration::thierarchy, tmp_url, tmp_url );
- }
- }
-
- //=======================
- // Write collaboration
-
- // Add members
- addMemberList( gd->getMemberList(MemberListType_allMembersList) );
-
- // Add classes
- if ( gd->getClasses() && gd->getClasses()->count() )
- {
- ClassSDict::Iterator defli(*gd->getClasses());
- ClassDef *def;
- for (;(def=defli.current());++defli)
- {
- tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
- if (!def->anchor().isEmpty())
- {
- tmp_url+="#"+def->anchor();
- }
- addCollaborationMember( def, tmp_url, DotGroupCollaboration::tclass );
- }
- }
-
- // Add namespaces
- if ( gd->getNamespaces() && gd->getNamespaces()->count() )
- {
- NamespaceSDict::Iterator defli(*gd->getNamespaces());
- NamespaceDef *def;
- for (;(def=defli.current());++defli)
- {
- tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
- addCollaborationMember( def, tmp_url, DotGroupCollaboration::tnamespace );
- }
- }
-
- // Add files
- if ( gd->getFiles() && gd->getFiles()->count() )
- {
- QListIterator<FileDef> defli(*gd->getFiles());
- const FileDef *def;
- for (;(def=defli.current());++defli)
- {
- tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
- addCollaborationMember( def, tmp_url, DotGroupCollaboration::tfile );
- }
- }
-
- // Add pages
- if ( gd->getPages() && gd->getPages()->count() )
- {
- PageSDict::Iterator defli(*gd->getPages());
- PageDef *def;
- for (;(def=defli.current());++defli)
- {
- tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
- addCollaborationMember( def, tmp_url, DotGroupCollaboration::tpages );
- }
- }
-
- // Add directories
- if ( gd->getDirs() && gd->getDirs()->count() )
- {
- QListIterator<DirDef> defli(*gd->getDirs());
- const DirDef *def;
- for (;(def=defli.current());++defli)
- {
- tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
- addCollaborationMember( def, tmp_url, DotGroupCollaboration::tdir );
- }
- }
-}
-
-void DotGroupCollaboration::addMemberList( MemberList* ml )
-{
- if ( !( ml && ml->count()) ) return;
- MemberListIterator defli(*ml);
- MemberDef *def;
- for (;(def=defli.current());++defli)
- {
- QCString tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension
- +"#"+def->anchor();
- addCollaborationMember( def, tmp_url, DotGroupCollaboration::tmember );
- }
-}
-
-DotGroupCollaboration::Edge* DotGroupCollaboration::addEdge(
- DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType,
- const QCString& _label, const QCString& _url )
-{
- // search a existing link.
- QListIterator<Edge> lli(m_edges);
- Edge* newEdge = 0;
- for ( lli.toFirst(); (newEdge=lli.current()); ++lli)
- {
- if ( newEdge->pNStart==_pNStart &&
- newEdge->pNEnd==_pNEnd &&
- newEdge->eType==_eType
- )
- { // edge already found
- break;
- }
- }
- if ( newEdge==0 ) // new link
- {
- newEdge = new Edge(_pNStart,_pNEnd,_eType);
- m_edges.append( newEdge );
- }
-
- if (!_label.isEmpty())
- {
- newEdge->links.append(new Link(_label,_url));
- }
-
- return newEdge;
-}
-
-void DotGroupCollaboration::addCollaborationMember(
- const Definition* def, QCString& url, EdgeType eType )
-{
- // Create group nodes
- if ( !def->partOfGroups() )
- return;
- GroupListIterator gli(*def->partOfGroups());
- GroupDef *d;
- QCString tmp_str;
- for (;(d=gli.current());++gli)
- {
- DotNode* nnode = m_usedNodes->find(d->name());
- if ( nnode != m_rootNode )
- {
- if ( nnode==0 )
- { // add node
- tmp_str = d->getReference()+"$"+d->getOutputFileBase();
- QCString tooltip = d->briefDescriptionAsTooltip();
- nnode = new DotNode(getNextNodeNumber(), d->groupTitle(), tooltip, tmp_str );
- nnode->markAsVisible();
- m_usedNodes->insert(d->name(), nnode );
- }
- tmp_str = def->qualifiedName();
- addEdge( m_rootNode, nnode, eType, tmp_str, url );
- }
- }
-}
-
-
-QCString DotGroupCollaboration::writeGraph( FTextStream &t,
- GraphOutputFormat graphFormat, EmbeddedOutputFormat textFormat,
- const char *path, const char *fileName, const char *relPath,
- bool writeImageMap,int graphId) const
-{
- QDir d(path);
- // store the original directory
- if (!d.exists())
- {
- err("Output dir %s does not exist!\n",path); exit(1);
- }
- static bool usePDFLatex = Config_getBool(USE_PDFLATEX);
-
- QGString theGraph;
- FTextStream md5stream(&theGraph);
- writeGraphHeader(md5stream,m_rootNode->label());
-
- // clean write flags
- QDictIterator<DotNode> dni(*m_usedNodes);
- DotNode *pn;
- for (dni.toFirst();(pn=dni.current());++dni)
- {
- pn->clearWriteFlag();
- }
-
- // write other nodes.
- for (dni.toFirst();(pn=dni.current());++dni)
- {
- pn->write(md5stream,DotNode::Inheritance,graphFormat,TRUE,FALSE,FALSE);
- }
-
- // write edges
- QListIterator<Edge> eli(m_edges);
- Edge* edge;
- for (eli.toFirst();(edge=eli.current());++eli)
- {
- edge->write( md5stream );
- }
-
- writeGraphFooter(md5stream);
- uchar md5_sig[16];
- QCString sigStr(33);
- MD5Buffer((const unsigned char *)theGraph.data(),theGraph.length(),md5_sig);
- MD5SigToString(md5_sig,sigStr.rawData(),33);
- QCString imgExt = getDotImageExtension();
- QCString imgFmt = Config_getEnum(DOT_IMAGE_FORMAT);
- QCString baseName = m_diskName;
- QCString imgName = baseName+"."+imgExt;
- QCString absPath = d.absPath().data();
- QCString absBaseName = absPath+"/"+baseName;
- QCString absDotName = absBaseName+".dot";
- QCString absImgName = absBaseName+"."+imgExt;
- QCString absMapName = absBaseName+".map";
- QCString absPdfName = absBaseName+".pdf";
- QCString absEpsName = absBaseName+".eps";
- bool regenerate=FALSE;
- if (checkAndUpdateMd5Signature(absBaseName,sigStr) ||
- !checkDeliverables(graphFormat==GOF_BITMAP ? absImgName :
- usePDFLatex ? absPdfName : absEpsName,
- graphFormat==GOF_BITMAP /*&& generateImageMap*/ ? absMapName : QCString())
- )
- {
- regenerate=TRUE;
-
- QFile dotfile(absDotName);
- if (dotfile.open(IO_WriteOnly))
- {
- FTextStream tdot(&dotfile);
- tdot << theGraph;
- dotfile.close();
- }
-
- if (graphFormat==GOF_BITMAP) // run dot to create a bitmap image
- {
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE);
- dotRun->addJob(imgFmt,absImgName);
- if (writeImageMap) dotRun->addJob(MAP_CMD,absMapName);
- DotManager::instance()->addRun(dotRun);
-
- }
- else if (graphFormat==GOF_EPS)
- {
- DotRunner *dotRun = new DotRunner(absDotName,d.absPath().data(),FALSE);
- if (usePDFLatex)
- {
- dotRun->addJob("pdf",absPdfName,absBaseName);
- }
- else
- {
- dotRun->addJob("ps",absEpsName);
- }
- DotManager::instance()->addRun(dotRun);
- }
-
- }
- if (graphFormat==GOF_BITMAP && textFormat==EOF_DocBook)
- {
- t << "<para>" << endl;
- t << " <informalfigure>" << endl;
- t << " <mediaobject>" << endl;
- t << " <imageobject>" << endl;
- t << " <imagedata";
- t << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << relPath << baseName << "." << imgExt << "\">";
- t << "</imagedata>" << endl;
- t << " </imageobject>" << endl;
- t << " </mediaobject>" << endl;
- t << " </informalfigure>" << endl;
- t << "</para>" << endl;
- }
- else if (graphFormat==GOF_BITMAP && writeImageMap)
- {
- QCString mapLabel = escapeCharsInString(baseName,FALSE);
- t << "<center><table><tr><td>";
-
- if (imgExt=="svg")
- {
- t << "<div class=\"center\">";
- if (regenerate || !writeSVGFigureLink(t,relPath,baseName,absImgName)) // need to patch the links in the generated SVG file
- {
- if (regenerate)
- {
- DotManager::instance()->addSVGConversion(absImgName,relPath,FALSE,QCString(),TRUE,graphId);
- }
- int mapId = DotManager::instance()->addSVGObject(fileName,baseName,absImgName,relPath);
- t << "<!-- SVG " << mapId << " -->" << endl;
- }
- t << "</div>" << endl;
- }
- else
- {
- t << "<img src=\"" << relPath << imgName
- << "\" border=\"0\" alt=\"\" usemap=\"#"
- << mapLabel << "\"/>" << endl;
- if (regenerate || !insertMapFile(t,absMapName,relPath,mapLabel))
- {
- int mapId = DotManager::instance()->addMap(fileName,absMapName,relPath,
- FALSE,QCString(),mapLabel);
- t << "<!-- MAP " << mapId << " -->" << endl;
- }
- }
- t << "</td></tr></table></center>" << endl;
- }
- else if (graphFormat==GOF_EPS)
- {
- if (regenerate || !writeVecGfxFigure(t,baseName,absBaseName))
- {
- int figId = DotManager::instance()->addFigure(fileName,baseName,absBaseName,FALSE);
- t << endl << "% FIG " << figId << endl;
- }
- }
- if (!regenerate) removeDotGraph(absDotName);
-
- return baseName;
-}
-
-void DotGroupCollaboration::Edge::write( FTextStream &t ) const
-{
- const char* linkTypeColor[] = {
- "darkorchid3"
- ,"orange"
- ,"blueviolet"
- ,"darkgreen"
- ,"firebrick4"
- ,"grey75"
- ,"midnightblue"
- };
- QCString arrowStyle = "dir=\"none\", style=\"dashed\"";
- t << " Node" << pNStart->number();
- t << "->";
- t << "Node" << pNEnd->number();
-
- t << " [shape=plaintext";
- if (links.count()>0) // there are links
- {
- t << ", ";
- // HTML-like edge labels crash on my Mac with Graphviz 2.0! and
- // are not supported by older version of dot.
- //
- //t << label=<<TABLE BORDER=\"0\" CELLBORDER=\"0\">";
- //QListIterator<Link> lli(links);
- //Link *link;
- //for( lli.toFirst(); (link=lli.current()); ++lli)
- //{
- // t << "<TR><TD";
- // if ( !link->url.isEmpty() )
- // t << " HREF=\"" << link->url << "\"";
- // t << ">" << link->label << "</TD></TR>";
- //}
- //t << "</TABLE>>";
-
- t << "label=\"";
- QListIterator<Link> lli(links);
- Link *link;
- bool first=TRUE;
- int count=0;
- const int maxLabels = 10;
- for( lli.toFirst(); (link=lli.current()) && count<maxLabels; ++lli,++count)
- {
- if (first) first=FALSE; else t << "\\n";
- t << convertLabel(link->label);
- }
- if (count==maxLabels) t << "\\n...";
- t << "\"";
-
- }
- switch( eType )
- {
- case thierarchy:
- arrowStyle = "dir=\"back\", style=\"solid\"";
- break;
- default:
- t << ", color=\"" << linkTypeColor[(int)eType] << "\"";
- break;
- }
- t << ", " << arrowStyle;
- t << "];" << endl;
-}
-
-bool DotGroupCollaboration::isTrivial() const
-{
- return m_usedNodes->count() <= 1;
-}
-
-void DotGroupCollaboration::writeGraphHeader(FTextStream &t,
- const QCString &title) const
-{
- t << "digraph ";
- if (title.isEmpty())
- {
- t << "\"Dot Graph\"";
- }
- else
- {
- t << "\"" << convertLabel(title) << "\"";
- }
- t << endl;
- t << "{" << endl;
- if (Config_getBool(DOT_TRANSPARENT))
- {
- t << " bgcolor=\"transparent\";" << endl;
- }
- t << " edge [fontname=\"" << FONTNAME << "\",fontsize=\"" << FONTSIZE << "\","
- "labelfontname=\"" << FONTNAME << "\",labelfontsize=\"" << FONTSIZE << "\"];\n";
- t << " node [fontname=\"" << FONTNAME << "\",fontsize=\"" << FONTSIZE << "\",shape=box];\n";
- t << " rankdir=LR;\n";
-}
-
-void writeDotDirDepGraph(FTextStream &t,const DirDef *dd,bool linkRelations)
-{
- t << "digraph \"" << dd->displayName() << "\" {\n";
- if (Config_getBool(DOT_TRANSPARENT))
- {
- t << " bgcolor=transparent;\n";
- }
- t << " compound=true\n";
- t << " node [ fontsize=\"" << FONTSIZE << "\", fontname=\"" << FONTNAME << "\"];\n";
- t << " edge [ labelfontsize=\"" << FONTSIZE << "\", labelfontname=\"" << FONTNAME << "\"];\n";
-
- QDict<DirDef> dirsInGraph(257);
-
- dirsInGraph.insert(dd->getOutputFileBase(),dd);
- if (dd->parent())
- {
- t << " subgraph cluster" << dd->parent()->getOutputFileBase() << " {\n";
- t << " graph [ bgcolor=\"#ddddee\", pencolor=\"black\", label=\""
- << dd->parent()->shortName()
- << "\" fontname=\"" << FONTNAME << "\", fontsize=\"" << FONTSIZE << "\", URL=\"";
- t << dd->parent()->getOutputFileBase() << Doxygen::htmlFileExtension;
- t << "\"]\n";
- }
- if (dd->isCluster())
- {
- t << " subgraph cluster" << dd->getOutputFileBase() << " {\n";
- t << " graph [ bgcolor=\"#eeeeff\", pencolor=\"black\", label=\"\""
- << " URL=\"" << dd->getOutputFileBase() << Doxygen::htmlFileExtension
- << "\"];\n";
- t << " " << dd->getOutputFileBase() << " [shape=plaintext label=\""
- << dd->shortName() << "\"];\n";
-
- // add nodes for sub directories
- QListIterator<DirDef> sdi(dd->subDirs());
- const DirDef *sdir;
- for (sdi.toFirst();(sdir=sdi.current());++sdi)
- {
- t << " " << sdir->getOutputFileBase() << " [shape=box label=\""
- << sdir->shortName() << "\"";
- if (sdir->isCluster())
- {
- t << " color=\"red\"";
- }
- else
- {
- t << " color=\"black\"";
- }
- t << " fillcolor=\"white\" style=\"filled\"";
- t << " URL=\"" << sdir->getOutputFileBase()
- << Doxygen::htmlFileExtension << "\"";
- t << "];\n";
- dirsInGraph.insert(sdir->getOutputFileBase(),sdir);
- }
- t << " }\n";
- }
- else
- {
- t << " " << dd->getOutputFileBase() << " [shape=box, label=\""
- << dd->shortName() << "\", style=\"filled\", fillcolor=\"#eeeeff\","
- << " pencolor=\"black\", URL=\"" << dd->getOutputFileBase()
- << Doxygen::htmlFileExtension << "\"];\n";
- }
- if (dd->parent())
- {
- t << " }\n";
- }
-
- // add nodes for other used directories
- QDictIterator<UsedDir> udi(*dd->usedDirs());
- UsedDir *udir;
- //printf("*** For dir %s\n",shortName().data());
- for (udi.toFirst();(udir=udi.current());++udi)
- // for each used dir (=directly used or a parent of a directly used dir)
- {
- const DirDef *usedDir=udir->dir();
- const DirDef *dir=dd;
- while (dir)
- {
- //printf("*** check relation %s->%s same_parent=%d !%s->isParentOf(%s)=%d\n",
- // dir->shortName().data(),usedDir->shortName().data(),
- // dir->parent()==usedDir->parent(),
- // usedDir->shortName().data(),
- // shortName().data(),
- // !usedDir->isParentOf(this)
- // );
- if (dir!=usedDir && dir->parent()==usedDir->parent() &&
- !usedDir->isParentOf(dd))
- // include if both have the same parent (or no parent)
- {
- t << " " << usedDir->getOutputFileBase() << " [shape=box label=\""
- << usedDir->shortName() << "\"";
- if (usedDir->isCluster())
- {
- if (!Config_getBool(DOT_TRANSPARENT))
- {
- t << " fillcolor=\"white\" style=\"filled\"";
- }
- t << " color=\"red\"";
- }
- t << " URL=\"" << usedDir->getOutputFileBase()
- << Doxygen::htmlFileExtension << "\"];\n";
- dirsInGraph.insert(usedDir->getOutputFileBase(),usedDir);
- break;
- }
- dir=dir->parent();
- }
- }
-
- // add relations between all selected directories
- const DirDef *dir;
- QDictIterator<DirDef> di(dirsInGraph);
- for (di.toFirst();(dir=di.current());++di) // foreach dir in the graph
- {
- QDictIterator<UsedDir> udi(*dir->usedDirs());
- UsedDir *udir;
- for (udi.toFirst();(udir=udi.current());++udi) // foreach used dir
- {
- const DirDef *usedDir=udir->dir();
- if ((dir!=dd || !udir->inherited()) && // only show direct dependendies for this dir
- (usedDir!=dd || !udir->inherited()) && // only show direct dependendies for this dir
- !usedDir->isParentOf(dir) && // don't point to own parent
- dirsInGraph.find(usedDir->getOutputFileBase())) // only point to nodes that are in the graph
- {
- QCString relationName;
- relationName.sprintf("dir_%06d_%06d",dir->dirCount(),usedDir->dirCount());
- if (Doxygen::dirRelations.find(relationName)==0)
- {
- // new relation
- Doxygen::dirRelations.append(relationName,
- new DirRelation(relationName,dir,udir));
- }
- int nrefs = udir->filePairs().count();
- t << " " << dir->getOutputFileBase() << "->"
- << usedDir->getOutputFileBase();
- t << " [headlabel=\"" << nrefs << "\", labeldistance=1.5";
- if (linkRelations)
- {
- t << " headhref=\"" << relationName << Doxygen::htmlFileExtension << "\"";
- }
- t << "];\n";
- }
- }
- }
-
- t << "}\n";
-}
diff --git a/src/dot.h b/src/dot.h
index d63dd05..124a32b 100644
--- a/src/dot.h
+++ b/src/dot.h
@@ -1,13 +1,10 @@
/******************************************************************************
*
- *
- *
- *
- * Copyright (C) 1997-2015 by Dimitri van Heesch.
+ * Copyright (C) 1997-2019 by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby
- * granted. No representations are made about the suitability of this software
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
* for any purpose. It is provided "as is" without express or implied warranty.
* See the GNU General Public License for more details.
*
@@ -16,8 +13,8 @@
*
*/
-#ifndef _DOT_H
-#define _DOT_H
+#ifndef DOT_H
+#define DOT_H
#include <qlist.h>
#include <qdict.h>
@@ -26,473 +23,24 @@
#include <qqueue.h>
#include <qthread.h>
#include "sortdict.h"
-#include "classdef.h"
+#include "qgstring.h"
+#include "qdir.h"
+#include "qcstring.h"
+#include "dotgraph.h"
+#include "dotfilepatcher.h"
+#include "dotrunner.h"
-class FileDef;
class FTextStream;
-class DotNodeList;
-class ClassSDict;
-class MemberDef;
-class Definition;
-class DirDef;
-class GroupDef;
-class DotGroupCollaboration;
+class DotRunner;
class DotRunnerQueue;
-
-enum GraphOutputFormat { GOF_BITMAP, GOF_EPS };
-enum EmbeddedOutputFormat { EOF_Html, EOF_LaTeX, EOF_Rtf, EOF_DocBook };
-
-// the graphicx LaTeX has a limitation of maximum size of 16384
-// To be on the save side we take it a little bit smaller i.e. 150 inch * 72 dpi
-// It is anyway hard to view these size of images
-#define MAX_LATEX_GRAPH_INCH 150
-#define MAX_LATEX_GRAPH_SIZE (MAX_LATEX_GRAPH_INCH * 72)
-
-/** Attributes of an edge of a dot graph */
-struct EdgeInfo
-{
- enum Colors { Blue=0, Green=1, Red=2, Purple=3, Grey=4, Orange=5, Orange2=6 };
- enum Styles { Solid=0, Dashed=1 };
- EdgeInfo() : m_color(0), m_style(0), m_labColor(0) {}
- ~EdgeInfo() {}
- int m_color;
- int m_style;
- QCString m_label;
- QCString m_url;
- int m_labColor;
-};
-
-/** A node in a dot graph */
-class DotNode
-{
- public:
- enum GraphType { Dependency, Inheritance, Collaboration, Hierarchy, CallGraph };
- enum TruncState { Unknown, Truncated, Untruncated };
- DotNode(int n,const char *lab,const char *tip,const char *url,
- bool rootNode=FALSE,const ClassDef *cd=0);
- ~DotNode();
- void addChild(DotNode *n,
- int edgeColor=EdgeInfo::Purple,
- int edgeStyle=EdgeInfo::Solid,
- const char *edgeLab=0,
- const char *edgeURL=0,
- int edgeLabCol=-1
- );
- void addParent(DotNode *n);
- void deleteNode(DotNodeList &deletedList,SDict<DotNode> *skipNodes=0);
- void removeChild(DotNode *n);
- void removeParent(DotNode *n);
- int findParent( DotNode *n );
- void write(FTextStream &t,GraphType gt,GraphOutputFormat f,
- bool topDown,bool toChildren,bool backArrows);
- int m_subgraphId;
- void clearWriteFlag();
- void writeXML(FTextStream &t,bool isClassGraph);
- void writeDocbook(FTextStream &t,bool isClassGraph);
- void writeDEF(FTextStream &t);
- QCString label() const { return m_label; }
- int number() const { return m_number; }
- bool isVisible() const { return m_visible; }
- TruncState isTruncated() const { return m_truncated; }
- int distance() const { return m_distance; }
- void renumberNodes(int &number);
-
- private:
- void colorConnectedNodes(int curColor);
- void writeBox(FTextStream &t,GraphType gt,GraphOutputFormat f,
- bool hasNonReachableChildren);
- void writeArrow(FTextStream &t,GraphType gt,GraphOutputFormat f,DotNode *cn,
- EdgeInfo *ei,bool topDown, bool pointBack=TRUE);
- void setDistance(int distance);
- const DotNode *findDocNode() const; // only works for acyclic graphs!
- void markAsVisible(bool b=TRUE) { m_visible=b; }
- void markAsTruncated(bool b=TRUE) { m_truncated=b ? Truncated : Untruncated; }
- int m_number;
- QCString m_label; //!< label text
- QCString m_tooltip; //!< node's tooltip
- QCString m_url; //!< url of the node (format: remote$local)
- QList<DotNode> *m_parents; //!< list of parent nodes (incoming arrows)
- QList<DotNode> *m_children; //!< list of child nodes (outgoing arrows)
- QList<EdgeInfo> *m_edgeInfo; //!< edge info for each child
- bool m_deleted; //!< used to mark a node as deleted
- bool m_written; //!< used to mark a node as written
- bool m_hasDoc; //!< used to mark a node as documented
- bool m_isRoot; //!< indicates if this is a root node
- const ClassDef * m_classDef; //!< class representing this node (can be 0)
- bool m_visible; //!< is the node visible in the output
- TruncState m_truncated; //!< does the node have non-visible children/parents
- int m_distance; //!< shortest path to the root node
- bool m_renumbered;//!< indicates if the node has been renumbered (to prevent endless loops)
-
- friend class DotGfxHierarchyTable;
- friend class DotClassGraph;
- friend class DotInclDepGraph;
- friend class DotNodeList;
- friend class DotCallGraph;
- friend class DotGroupCollaboration;
- friend class DotInheritanceGraph;
-
- friend QCString computeMd5Signature(
- DotNode *root, GraphType gt,
- GraphOutputFormat f,
- const QCString &rank,
- bool renderParents,
- bool backArrows,
- const QCString &title,
- QCString &graphStr
- );
-};
-
-/** Class representing a list of DotNode objects. */
-class DotNodeList : public QList<DotNode>
-{
- public:
- DotNodeList() : QList<DotNode>() {}
- ~DotNodeList() {}
- private:
- int compareValues(const DotNode *n1,const DotNode *n2) const;
-};
-
-/** A dot graph */
-class DotGraph
-{
- public:
- DotGraph() : m_curNodeNumber(0) {}
- virtual ~DotGraph() {}
-
- protected:
- int getNextNodeNumber() { return ++m_curNodeNumber; }
-
- private:
- DotGraph(const DotGraph &);
- DotGraph &operator=(const DotGraph &);
- int m_curNodeNumber;
-};
-
-/** Represents a graphical class hierarchy */
-class DotGfxHierarchyTable : public DotGraph
-{
- public:
- DotGfxHierarchyTable(const char *prefix="",ClassDef::CompoundType ct=ClassDef::Class);
- ~DotGfxHierarchyTable();
- void writeGraph(FTextStream &t,const char *path, const char *fileName) const;
- void createGraph(DotNode *rootNode,FTextStream &t,const char *path,const char *fileName,int id) const;
- const DotNodeList *subGraphs() const { return m_rootSubgraphs; }
-
- private:
- void addHierarchy(DotNode *n,const ClassDef *cd,bool hide);
- void addClassList(const ClassSDict *cl);
-
- QCString m_prefix;
- ClassDef::CompoundType m_classType;
- QList<DotNode> *m_rootNodes;
- QDict<DotNode> *m_usedNodes;
- DotNodeList *m_rootSubgraphs;
-};
-
-/** Representation of a class inheritance or dependency graph */
-class DotClassGraph : public DotGraph
-{
- public:
- DotClassGraph(const ClassDef *cd,DotNode::GraphType t);
- ~DotClassGraph();
- bool isTrivial() const;
- bool isTooBig() const;
- QCString writeGraph(FTextStream &t,GraphOutputFormat gf,EmbeddedOutputFormat ef,
- const char *path, const char *fileName, const char *relPath,
- bool TBRank=TRUE,bool imageMap=TRUE,int graphId=-1) const;
-
- void writeXML(FTextStream &t);
- void writeDocbook(FTextStream &t);
- void writeDEF(FTextStream &t);
-
- private:
- void buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance);
- bool determineVisibleNodes(DotNode *rootNode,int maxNodes,bool includeParents);
- void determineTruncatedNodes(QList<DotNode> &queue,bool includeParents);
- void addClass(const ClassDef *cd,DotNode *n,int prot,const char *label,
- const char *usedName,const char *templSpec,
- bool base,int distance);
-
- DotNode * m_startNode;
- QDict<DotNode> * m_usedNodes;
- DotNode::GraphType m_graphType;
- QCString m_collabFileName;
- QCString m_inheritFileName;
- bool m_lrRank;
-};
-
-/** Representation of an include dependency graph */
-class DotInclDepGraph : public DotGraph
-{
- public:
- DotInclDepGraph(const FileDef *fd,bool inverse);
- ~DotInclDepGraph();
- QCString writeGraph(FTextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef,
- const char *path,const char *fileName,const char *relPath,
- bool writeImageMap=TRUE,int graphId=-1) const;
- bool isTrivial() const;
- bool isTooBig() const;
- QCString diskName() const;
- void writeXML(FTextStream &t);
- void writeDocbook(FTextStream &t);
-
- private:
- void buildGraph(DotNode *n,const FileDef *fd,int distance);
- void determineVisibleNodes(QList<DotNode> &queue,int &maxNodes);
- void determineTruncatedNodes(QList<DotNode> &queue);
-
- DotNode *m_startNode;
- QDict<DotNode> *m_usedNodes;
- QCString m_inclDepFileName;
- QCString m_inclByDepFileName;
- bool m_inverse;
-};
-
-/** Representation of an call graph */
-class DotCallGraph : public DotGraph
-{
- public:
- DotCallGraph(const MemberDef *md,bool inverse);
- ~DotCallGraph();
- QCString writeGraph(FTextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef,
- const char *path,const char *fileName,
- const char *relPath,bool writeImageMap=TRUE,
- int graphId=-1) const;
- void buildGraph(DotNode *n,const MemberDef *md,int distance);
- bool isTrivial() const;
- bool isTooBig() const;
- void determineVisibleNodes(QList<DotNode> &queue, int &maxNodes);
- void determineTruncatedNodes(QList<DotNode> &queue);
-
- private:
- DotNode *m_startNode;
- QDict<DotNode> *m_usedNodes;
- bool m_inverse;
- QCString m_diskName;
- const Definition * m_scope;
-};
-
-/** Representation of an directory dependency graph */
-class DotDirDeps : public DotGraph
-{
- public:
- DotDirDeps(const DirDef *dir);
- ~DotDirDeps();
- bool isTrivial() const;
- QCString writeGraph(FTextStream &out,
- GraphOutputFormat gf,
- EmbeddedOutputFormat ef,
- const char *path,
- const char *fileName,
- const char *relPath,
- bool writeImageMap=TRUE,
- int graphId=-1,
- bool linkRelations=TRUE) const;
- private:
- const DirDef *m_dir;
-};
-
-/** Representation of a group collaboration graph */
-class DotGroupCollaboration : public DotGraph
-{
- public :
- enum EdgeType
- { tmember = 0,
- tclass,
- tnamespace,
- tfile,
- tpages,
- tdir,
- thierarchy
- };
-
- class Link
- {
- public:
- Link(const QCString lab,const QCString &u) : label(lab), url(u) {}
- QCString label;
- QCString url;
- };
-
- class Edge
- {
- public :
- Edge(DotNode *start,DotNode *end,EdgeType type)
- : pNStart(start), pNEnd(end), eType(type)
- { links.setAutoDelete(TRUE); }
-
- DotNode* pNStart;
- DotNode* pNEnd;
- EdgeType eType;
-
- QList<Link> links;
- void write( FTextStream &t ) const;
- };
-
- DotGroupCollaboration(const GroupDef* gd);
- ~DotGroupCollaboration();
- QCString writeGraph(FTextStream &t, GraphOutputFormat gf,EmbeddedOutputFormat ef,
- const char *path,const char *fileName,const char *relPath,
- bool writeImageMap=TRUE,int graphId=-1) const;
- void buildGraph(const GroupDef* gd);
- bool isTrivial() const;
-
- private :
- void addCollaborationMember(const Definition* def, QCString& url, EdgeType eType );
- void addMemberList( class MemberList* ml );
- void writeGraphHeader(FTextStream &t,const QCString &title) const;
- Edge* addEdge( DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType,
- const QCString& _label, const QCString& _url );
-
- DotNode *m_rootNode;
- QDict<DotNode> *m_usedNodes;
- QCString m_diskName;
- QList<Edge> m_edges;
-};
-
-/** Minimal constant string class that is thread safe, once initialized. */
-class DotConstString
-{
- public:
- DotConstString() { m_str=0; m_pdfstr=0;}
- ~DotConstString() { delete[] m_str; delete[] m_pdfstr;}
- DotConstString(const QCString &s, const QCString &p = NULL) : m_str(0), m_pdfstr(0) { set(s); setpdf(p);}
- DotConstString(const DotConstString &s) : m_str(0), m_pdfstr(0) { set(s.data()); }
- const char *data() const { return m_str; }
- const char *pdfData() const { return m_pdfstr; }
- bool isEmpty() const { return m_str==0 || m_str[0]=='\0'; }
- void set(const QCString &s)
- {
- delete[] m_str;
- m_str=0;
- if (!s.isEmpty())
- {
- m_str=new char[s.length()+1];
- qstrcpy(m_str,s.data());
- }
- }
- void setpdf(const QCString &p)
- {
- delete[] m_pdfstr;
- m_pdfstr=0;
- if (!p.isEmpty())
- {
- m_pdfstr=new char[p.length()+1];
- qstrcpy(m_pdfstr,p.data());
- }
- }
- private:
- DotConstString &operator=(const DotConstString &);
- char *m_str;
- char *m_pdfstr;
-};
-
-/** Helper class to run dot from doxygen.
- */
-class DotRunner
-{
- public:
- struct CleanupItem
- {
- DotConstString path;
- DotConstString file;
- };
-
- /** Creates a runner for a dot \a file. */
- DotRunner(const QCString &file,const QCString &fontPath,bool checkResult,
- const QCString &imageName = QCString());
-
- /** Adds an additional job to the run.
- * Performing multiple jobs one file can be faster.
- */
- void addJob(const char *format,const char *output, const char *base = NULL);
-
- void addPostProcessing(const char *cmd,const char *args);
-
- void preventCleanUp() { m_cleanUp = FALSE; }
-
- /** Runs dot for all jobs added. */
- bool run();
- const CleanupItem &cleanup() const { return m_cleanupItem; }
-
- private:
- DotConstString m_dotExe;
- bool m_multiTargets;
- QList<DotConstString> m_jobs;
- DotConstString m_postArgs;
- DotConstString m_postCmd;
- DotConstString m_file;
- DotConstString m_path;
- bool m_checkResult;
- DotConstString m_imageName;
- DotConstString m_imgExt;
- bool m_cleanUp;
- CleanupItem m_cleanupItem;
-};
-
-/** Helper class to insert a set of map file into an output file */
-class DotFilePatcher
-{
- public:
- struct Map
- {
- QCString mapFile;
- QCString relPath;
- bool urlOnly;
- QCString context;
- QCString label;
- bool zoomable;
- int graphId;
- };
- DotFilePatcher(const char *patchFile);
- int addMap(const QCString &mapFile,const QCString &relPath,
- bool urlOnly,const QCString &context,const QCString &label);
- int addFigure(const QCString &baseName,
- const QCString &figureName,bool heightCheck);
- int addSVGConversion(const QCString &relPath,bool urlOnly,
- const QCString &context,bool zoomable,int graphId);
- int addSVGObject(const QCString &baseName, const QCString &figureName,
- const QCString &relPath);
- bool run();
- QCString file() const;
-
- private:
- QList<Map> m_maps;
- QCString m_patchFile;
-};
-
-/** Queue of dot jobs to run. */
-class DotRunnerQueue
-{
- public:
- void enqueue(DotRunner *runner);
- DotRunner *dequeue();
- uint count() const;
- private:
- QWaitCondition m_bufferNotEmpty;
- QQueue<DotRunner> m_queue;
- mutable QMutex m_mutex;
-};
-
-/** Worker thread to execute a dot run */
-class DotWorkerThread : public QThread
-{
- public:
- DotWorkerThread(DotRunnerQueue *queue);
- void run();
- void cleanup();
- private:
- DotRunnerQueue *m_queue;
- QList<DotRunner::CleanupItem> m_cleanupItems;
-};
+class DotWorkerThread;
/** Singleton that manages dot relation actions */
class DotManager
{
public:
static DotManager *instance();
- void addRun(DotRunner *run);
+ DotRunner* createRunner(const QCString& absDotName, const QCString& md5Hash);
int addMap(const QCString &file,const QCString &mapFile,
const QCString &relPath,bool urlOnly,
const QCString &context,const QCString &label);
@@ -507,13 +55,15 @@ class DotManager
private:
DotManager();
virtual ~DotManager();
- QList<DotRunner> m_dotRuns;
+
+ QDict<DotRunner> m_runners;
SDict<DotFilePatcher> m_dotMaps;
static DotManager *m_theInstance;
DotRunnerQueue *m_queue;
QList<DotWorkerThread> m_workers;
};
+void initDot();
/** Generated a graphs legend page */
void generateGraphLegend(const char *path);
@@ -524,5 +74,10 @@ void writeDotImageMapFromFile(FTextStream &t,
const QCString& inFile, const QCString& outDir,
const QCString& relPath,const QCString& baseName,
const QCString& context,int graphId=-1);
+bool writeSVGFigureLink(FTextStream &out,const QCString &relPath,
+ const QCString &baseName,const QCString &absImgName);
+bool convertMapFile(FTextStream &t,const char *mapName,
+ const QCString relPath, bool urlOnly=FALSE,
+ const QCString &context=QCString());
#endif
diff --git a/src/dotcallgraph.cpp b/src/dotcallgraph.cpp
new file mode 100644
index 0000000..15d408a
--- /dev/null
+++ b/src/dotcallgraph.cpp
@@ -0,0 +1,217 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotcallgraph.h"
+
+#include "dotnode.h"
+#include "memberlist.h"
+#include "config.h"
+#include "util.h"
+
+#define HIDE_SCOPE_NAMES Config_getBool(HIDE_SCOPE_NAMES)
+#define DOT_GRAPH_MAX_NODES Config_getInt(DOT_GRAPH_MAX_NODES)
+#define MAX_DOT_GRAPH_DEPTH Config_getInt(MAX_DOT_GRAPH_DEPTH)
+
+void DotCallGraph::buildGraph(DotNode *n,const MemberDef *md,int distance)
+{
+ MemberSDict *refs = m_inverse ? md->getReferencedByMembers() : md->getReferencesMembers();
+ if (refs)
+ {
+ refs->sort();
+ MemberSDict::Iterator mri(*refs);
+ MemberDef *rmd;
+ for (;(rmd=mri.current());++mri)
+ {
+ if (rmd->showInCallGraph())
+ {
+ QCString uniqueId;
+ uniqueId=rmd->getReference()+"$"+
+ rmd->getOutputFileBase()+"#"+rmd->anchor();
+ DotNode *bn = m_usedNodes->find(uniqueId);
+ if (bn) // file is already a node in the graph
+ {
+ n->addChild(bn,0,0,0);
+ bn->addParent(n);
+ bn->setDistance(distance);
+ }
+ else
+ {
+ QCString name;
+ if (HIDE_SCOPE_NAMES)
+ {
+ name = rmd->getOuterScope()==m_scope ?
+ rmd->name() : rmd->qualifiedName();
+ }
+ else
+ {
+ name = rmd->qualifiedName();
+ }
+ QCString tooltip = rmd->briefDescriptionAsTooltip();
+ bn = new DotNode(
+ getNextNodeNumber(),
+ linkToText(rmd->getLanguage(),name,FALSE),
+ tooltip,
+ uniqueId,
+ 0 //distance
+ );
+ n->addChild(bn,0,0,0);
+ bn->addParent(n);
+ bn->setDistance(distance);
+ m_usedNodes->insert(uniqueId,bn);
+
+ buildGraph(bn,rmd,distance+1);
+ }
+ }
+ }
+ }
+}
+
+void DotCallGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes)
+{
+ while (queue.count()>0 && maxNodes>0)
+ {
+ DotNode *n = queue.take(0);
+ if (!n->isVisible() && n->distance()<=MAX_DOT_GRAPH_DEPTH) // not yet processed
+ {
+ n->markAsVisible();
+ maxNodes--;
+ // add direct children
+ if (n->children())
+ {
+ QListIterator<DotNode> li(*n->children());
+ DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ queue.append(dn);
+ }
+ }
+ }
+ }
+}
+
+void DotCallGraph::determineTruncatedNodes(QList<DotNode> &queue)
+{
+ while (queue.count()>0)
+ {
+ DotNode *n = queue.take(0);
+ if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
+ {
+ bool truncated = FALSE;
+ if (n->children())
+ {
+ QListIterator<DotNode> li(*n->children());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ if (!dn->isVisible())
+ truncated = TRUE;
+ else
+ queue.append(dn);
+ }
+ }
+ n->markAsTruncated(truncated);
+ }
+ }
+}
+
+DotCallGraph::DotCallGraph(const MemberDef *md,bool inverse)
+{
+ m_inverse = inverse;
+ m_diskName = md->getOutputFileBase()+"_"+md->anchor();
+ m_scope = md->getOuterScope();
+ QCString uniqueId;
+ uniqueId = md->getReference()+"$"+
+ md->getOutputFileBase()+"#"+md->anchor();
+ QCString name;
+ if (HIDE_SCOPE_NAMES)
+ {
+ name = md->name();
+ }
+ else
+ {
+ name = md->qualifiedName();
+ }
+ QCString tooltip = md->briefDescriptionAsTooltip();
+ m_startNode = new DotNode(getNextNodeNumber(),
+ linkToText(md->getLanguage(),name,FALSE),
+ tooltip,
+ uniqueId.data(),
+ TRUE // root node
+ );
+ m_startNode->setDistance(0);
+ m_usedNodes = new QDict<DotNode>(1009);
+ m_usedNodes->insert(uniqueId,m_startNode);
+ buildGraph(m_startNode,md,1);
+
+ int maxNodes = DOT_GRAPH_MAX_NODES;
+ QList<DotNode> openNodeQueue;
+ openNodeQueue.append(m_startNode);
+ determineVisibleNodes(openNodeQueue,maxNodes);
+ openNodeQueue.clear();
+ openNodeQueue.append(m_startNode);
+ determineTruncatedNodes(openNodeQueue);
+}
+
+DotCallGraph::~DotCallGraph()
+{
+ DotNode::deleteNodes(m_startNode);
+ delete m_usedNodes;
+}
+
+QCString DotCallGraph::getBaseName() const
+{
+ return m_diskName + (m_inverse ? "_icgraph" : "_cgraph");
+}
+
+void DotCallGraph::computeTheGraph()
+{
+ computeGraph(
+ m_startNode,
+ CallGraph,
+ m_graphFormat,
+ m_inverse ? "RL" : "LR",
+ FALSE,
+ m_inverse,
+ m_startNode->label(),
+ m_theGraph);
+}
+
+QCString DotCallGraph::getMapLabel() const
+{
+ return m_baseName;
+}
+
+QCString DotCallGraph::writeGraph(
+ FTextStream &out,
+ GraphOutputFormat graphFormat,
+ EmbeddedOutputFormat textFormat,
+ const char *path,
+ const char *fileName,
+ const char *relPath,bool generateImageMap,
+ int graphId)
+{
+ return DotGraph::writeGraph(out, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
+}
+
+bool DotCallGraph::isTrivial() const
+{
+ return m_startNode->children()==0;
+}
+
+bool DotCallGraph::isTooBig() const
+{
+ int numNodes = m_startNode->children() ? m_startNode->children()->count() : 0;
+ return numNodes>=DOT_GRAPH_MAX_NODES;
+}
diff --git a/src/dotcallgraph.h b/src/dotcallgraph.h
new file mode 100644
index 0000000..c96b9cf
--- /dev/null
+++ b/src/dotcallgraph.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTCALLGRAPH_H
+#define DOTCALLGRAPH_H
+
+#include "dotgraph.h"
+#include "ftextstream.h"
+#include "memberdef.h"
+
+/** Representation of an call graph */
+class DotCallGraph : public DotGraph
+{
+ public:
+ DotCallGraph(const MemberDef *md,bool inverse);
+ ~DotCallGraph();
+ bool isTrivial() const;
+ bool isTooBig() const;
+ QCString writeGraph(FTextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef,
+ const char *path,const char *fileName,
+ const char *relPath,bool writeImageMap=TRUE,
+ int graphId=-1);
+
+ protected:
+ virtual QCString getBaseName() const;
+ virtual QCString getMapLabel() const;
+ virtual void computeTheGraph();
+
+ private:
+ void buildGraph(DotNode *n,const MemberDef *md,int distance);
+ void determineVisibleNodes(QList<DotNode> &queue, int &maxNodes);
+ void determineTruncatedNodes(QList<DotNode> &queue);
+ DotNode *m_startNode;
+ QDict<DotNode> *m_usedNodes;
+ bool m_inverse;
+ QCString m_diskName;
+ const Definition * m_scope;
+};
+
+#endif
diff --git a/src/dotclassgraph.cpp b/src/dotclassgraph.cpp
new file mode 100644
index 0000000..3f5d228
--- /dev/null
+++ b/src/dotclassgraph.cpp
@@ -0,0 +1,548 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotclassgraph.h"
+#include "dotnode.h"
+
+#include "config.h"
+#include "util.h"
+
+#define HIDE_SCOPE_NAMES Config_getBool(HIDE_SCOPE_NAMES)
+#define MAX_DOT_GRAPH_DEPTH Config_getInt(MAX_DOT_GRAPH_DEPTH)
+#define UML_LOOK Config_getBool(UML_LOOK)
+#define TEMPLATE_RELATIONS Config_getBool(TEMPLATE_RELATIONS)
+#define DOT_GRAPH_MAX_NODES Config_getInt(DOT_GRAPH_MAX_NODES)
+
+void DotClassGraph::addClass(const ClassDef *cd,DotNode *n,int prot,
+ const char *label,const char *usedName,const char *templSpec,bool base,int distance)
+{
+ if (Config_getBool(HIDE_UNDOC_CLASSES) && !cd->isLinkable()) return;
+
+ int edgeStyle = (label || prot==EdgeInfo::Orange || prot==EdgeInfo::Orange2) ? EdgeInfo::Dashed : EdgeInfo::Solid;
+ QCString className;
+ if (cd->isAnonymous())
+ {
+ className="anonymous:";
+ className+=label;
+ }
+ else if (usedName) // name is a typedef
+ {
+ className=usedName;
+ }
+ else if (templSpec) // name has a template part
+ {
+ className=insertTemplateSpecifierInScope(cd->name(),templSpec);
+ }
+ else // just a normal name
+ {
+ className=cd->displayName();
+ }
+ //printf("DotClassGraph::addClass(class='%s',parent=%s,prot=%d,label=%s,dist=%d,usedName=%s,templSpec=%s,base=%d)\n",
+ // className.data(),n->label().data(),prot,label,distance,usedName,templSpec,base);
+ DotNode *bn = m_usedNodes->find(className);
+ if (bn) // class already inserted
+ {
+ if (base)
+ {
+ n->addChild(bn,prot,edgeStyle,label);
+ bn->addParent(n);
+ }
+ else
+ {
+ bn->addChild(n,prot,edgeStyle,label);
+ n->addParent(bn);
+ }
+ bn->setDistance(distance);
+ //printf(" add exiting node %s of %s\n",bn->label().data(),n->label().data());
+ }
+ else // new class
+ {
+ QCString displayName=className;
+ if (HIDE_SCOPE_NAMES) displayName=stripScope(displayName);
+ QCString tmp_url;
+ if (cd->isLinkable() && !cd->isHidden())
+ {
+ tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
+ if (!cd->anchor().isEmpty())
+ {
+ tmp_url+="#"+cd->anchor();
+ }
+ }
+ QCString tooltip = cd->briefDescriptionAsTooltip();
+ bn = new DotNode(getNextNodeNumber(),
+ displayName,
+ tooltip,
+ tmp_url.data(),
+ FALSE, // rootNode
+ cd
+ );
+ if (base)
+ {
+ n->addChild(bn,prot,edgeStyle,label);
+ bn->addParent(n);
+ }
+ else
+ {
+ bn->addChild(n,prot,edgeStyle,label);
+ n->addParent(bn);
+ }
+ bn->setDistance(distance);
+ m_usedNodes->insert(className,bn);
+ //printf(" add new child node '%s' to %s hidden=%d url=%s\n",
+ // className.data(),n->label().data(),cd->isHidden(),tmp_url.data());
+
+ buildGraph(cd,bn,base,distance+1);
+ }
+}
+
+void DotClassGraph::determineTruncatedNodes(QList<DotNode> &queue,bool includeParents)
+{
+ while (queue.count()>0)
+ {
+ DotNode *n = queue.take(0);
+ if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
+ {
+ bool truncated = FALSE;
+ if (n->children())
+ {
+ QListIterator<DotNode> li(*n->children());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ if (!dn->isVisible())
+ truncated = TRUE;
+ else
+ queue.append(dn);
+ }
+ }
+ if (n->parents() && includeParents)
+ {
+ QListIterator<DotNode> li(*n->parents());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ if (!dn->isVisible())
+ truncated = TRUE;
+ else
+ queue.append(dn);
+ }
+ }
+ n->markAsTruncated(truncated);
+ }
+ }
+}
+
+bool DotClassGraph::determineVisibleNodes(DotNode *rootNode,
+ int maxNodes,bool includeParents)
+{
+ QList<DotNode> childQueue;
+ QList<DotNode> parentQueue;
+ QArray<int> childTreeWidth;
+ QArray<int> parentTreeWidth;
+ childQueue.append(rootNode);
+ if (includeParents) parentQueue.append(rootNode);
+ bool firstNode=TRUE; // flag to force reprocessing rootNode in the parent loop
+ // despite being marked visible in the child loop
+ while ((childQueue.count()>0 || parentQueue.count()>0) && maxNodes>0)
+ {
+ if (childQueue.count()>0)
+ {
+ DotNode *n = childQueue.take(0);
+ int distance = n->distance();
+ if (!n->isVisible() && distance<=MAX_DOT_GRAPH_DEPTH) // not yet processed
+ {
+ if (distance>0)
+ {
+ int oldSize=(int)childTreeWidth.size();
+ if (distance>oldSize)
+ {
+ childTreeWidth.resize(QMAX(childTreeWidth.size(),(uint)distance));
+ int i; for (i=oldSize;i<distance;i++) childTreeWidth[i]=0;
+ }
+ childTreeWidth[distance-1]+=n->label().length();
+ }
+ n->markAsVisible();
+ maxNodes--;
+ // add direct children
+ if (n->children())
+ {
+ QListIterator<DotNode> li(*n->children());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ childQueue.append(dn);
+ }
+ }
+ }
+ }
+ if (includeParents && parentQueue.count()>0)
+ {
+ DotNode *n = parentQueue.take(0);
+ if ((!n->isVisible() || firstNode) && n->distance()<=MAX_DOT_GRAPH_DEPTH) // not yet processed
+ {
+ firstNode=FALSE;
+ int distance = n->distance();
+ if (distance>0)
+ {
+ int oldSize = (int)parentTreeWidth.size();
+ if (distance>oldSize)
+ {
+ parentTreeWidth.resize(QMAX(parentTreeWidth.size(),(uint)distance));
+ int i; for (i=oldSize;i<distance;i++) parentTreeWidth[i]=0;
+ }
+ parentTreeWidth[distance-1]+=n->label().length();
+ }
+ n->markAsVisible();
+ maxNodes--;
+ // add direct parents
+ if (n->parents())
+ {
+ QListIterator<DotNode> li(*n->parents());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ parentQueue.append(dn);
+ }
+ }
+ }
+ }
+ }
+ if (UML_LOOK) return FALSE; // UML graph are always top to bottom
+ int maxWidth=0;
+ int maxHeight=(int)QMAX(childTreeWidth.size(),parentTreeWidth.size());
+ uint i;
+ for (i=0;i<childTreeWidth.size();i++)
+ {
+ if (childTreeWidth.at(i)>maxWidth) maxWidth=childTreeWidth.at(i);
+ }
+ for (i=0;i<parentTreeWidth.size();i++)
+ {
+ if (parentTreeWidth.at(i)>maxWidth) maxWidth=parentTreeWidth.at(i);
+ }
+ //printf("max tree width=%d, max tree height=%d\n",maxWidth,maxHeight);
+ return maxWidth>80 && maxHeight<12; // used metric to decide to render the tree
+ // from left to right instead of top to bottom,
+ // with the idea to render very wide trees in
+ // left to right order.
+}
+
+void DotClassGraph::buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance)
+{
+ //printf("DocClassGraph::buildGraph(%s,distance=%d,base=%d)\n",
+ // cd->name().data(),distance,base);
+ // ---- Add inheritance relations
+
+ if (m_graphType == Inheritance || m_graphType==Collaboration)
+ {
+ BaseClassList *bcl = base ? cd->baseClasses() : cd->subClasses();
+ if (bcl)
+ {
+ BaseClassListIterator bcli(*bcl);
+ BaseClassDef *bcd;
+ for ( ; (bcd=bcli.current()) ; ++bcli )
+ {
+ //printf("-------- inheritance relation %s->%s templ='%s'\n",
+ // cd->name().data(),bcd->classDef->name().data(),bcd->templSpecifiers.data());
+ addClass(bcd->classDef,n,bcd->prot,0,bcd->usedName,
+ bcd->templSpecifiers,base,distance);
+ }
+ }
+ }
+ if (m_graphType == Collaboration)
+ {
+ // ---- Add usage relations
+
+ UsesClassDict *dict =
+ base ? cd->usedImplementationClasses() :
+ cd->usedByImplementationClasses()
+ ;
+ if (dict)
+ {
+ UsesClassDictIterator ucdi(*dict);
+ UsesClassDef *ucd;
+ for (;(ucd=ucdi.current());++ucdi)
+ {
+ QCString label;
+ QDictIterator<void> dvi(*ucd->accessors);
+ const char *s;
+ bool first=TRUE;
+ int count=0;
+ int maxLabels=10;
+ for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
+ {
+ if (first)
+ {
+ label=s;
+ first=FALSE;
+ }
+ else
+ {
+ label+=QCString("\n")+s;
+ }
+ }
+ if (count==maxLabels) label+="\n...";
+ //printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
+ addClass(ucd->classDef,n,EdgeInfo::Purple,label,0,
+ ucd->templSpecifiers,base,distance);
+ }
+ }
+ }
+ if (TEMPLATE_RELATIONS && base)
+ {
+ ConstraintClassDict *dict = cd->templateTypeConstraints();
+ if (dict)
+ {
+ ConstraintClassDictIterator ccdi(*dict);
+ ConstraintClassDef *ccd;
+ for (;(ccd=ccdi.current());++ccdi)
+ {
+ QCString label;
+ QDictIterator<void> dvi(*ccd->accessors);
+ const char *s;
+ bool first=TRUE;
+ int count=0;
+ int maxLabels=10;
+ for (;(s=dvi.currentKey()) && count<maxLabels;++dvi,++count)
+ {
+ if (first)
+ {
+ label=s;
+ first=FALSE;
+ }
+ else
+ {
+ label+=QCString("\n")+s;
+ }
+ }
+ if (count==maxLabels) label+="\n...";
+ //printf("addClass: %s templSpec=%s\n",ucd->classDef->name().data(),ucd->templSpecifiers.data());
+ addClass(ccd->classDef,n,EdgeInfo::Orange2,label,0,
+ 0,TRUE,distance);
+ }
+ }
+ }
+
+ // ---- Add template instantiation relations
+
+ if (TEMPLATE_RELATIONS)
+ {
+ if (base) // template relations for base classes
+ {
+ const ClassDef *templMaster=cd->templateMaster();
+ if (templMaster)
+ {
+ QDictIterator<ClassDef> cli(*templMaster->getTemplateInstances());
+ const ClassDef *templInstance;
+ for (;(templInstance=cli.current());++cli)
+ {
+ if (templInstance==cd)
+ {
+ addClass(templMaster,n,EdgeInfo::Orange,cli.currentKey(),0,
+ 0,TRUE,distance);
+ }
+ }
+ }
+ }
+ else // template relations for super classes
+ {
+ const QDict<ClassDef> *templInstances = cd->getTemplateInstances();
+ if (templInstances)
+ {
+ QDictIterator<ClassDef> cli(*templInstances);
+ const ClassDef *templInstance;
+ for (;(templInstance=cli.current());++cli)
+ {
+ addClass(templInstance,n,EdgeInfo::Orange,cli.currentKey(),0,
+ 0,FALSE,distance);
+ }
+ }
+ }
+ }
+}
+
+DotClassGraph::DotClassGraph(const ClassDef *cd,GraphType t)
+{
+ //printf("--------------- DotClassGraph::DotClassGraph '%s'\n",cd->displayName().data());
+ m_graphType = t;
+ QCString tmp_url="";
+ if (cd->isLinkable() && !cd->isHidden())
+ {
+ tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
+ if (!cd->anchor().isEmpty())
+ {
+ tmp_url+="#"+cd->anchor();
+ }
+ }
+ QCString className = cd->displayName();
+ QCString tooltip = cd->briefDescriptionAsTooltip();
+ m_startNode = new DotNode(getNextNodeNumber(),
+ className,
+ tooltip,
+ tmp_url.data(),
+ TRUE, // is a root node
+ cd
+ );
+ m_startNode->setDistance(0);
+ m_usedNodes = new QDict<DotNode>(1009);
+ m_usedNodes->insert(className,m_startNode);
+
+ buildGraph(cd,m_startNode,TRUE,1);
+ if (t==Inheritance) buildGraph(cd,m_startNode,FALSE,1);
+
+ m_lrRank = determineVisibleNodes(m_startNode,DOT_GRAPH_MAX_NODES,t==Inheritance);
+ QList<DotNode> openNodeQueue;
+ openNodeQueue.append(m_startNode);
+ determineTruncatedNodes(openNodeQueue,t==Inheritance);
+
+ m_collabFileName = cd->collaborationGraphFileName();
+ m_inheritFileName = cd->inheritanceGraphFileName();
+}
+
+bool DotClassGraph::isTrivial() const
+{
+ if (m_graphType==Inheritance)
+ return m_startNode->children()==0 && m_startNode->parents()==0;
+ else
+ return !UML_LOOK && m_startNode->children()==0;
+}
+
+bool DotClassGraph::isTooBig() const
+{
+ int numNodes = 0;
+ numNodes+= m_startNode->children() ? m_startNode->children()->count() : 0;
+ if (m_graphType==Inheritance)
+ {
+ numNodes+= m_startNode->parents() ? m_startNode->parents()->count() : 0;
+ }
+ return numNodes>=DOT_GRAPH_MAX_NODES;
+}
+
+DotClassGraph::~DotClassGraph()
+{
+ DotNode::deleteNodes(m_startNode);
+ delete m_usedNodes;
+}
+
+QCString DotClassGraph::getBaseName() const
+{
+ switch (m_graphType)
+ {
+ case Collaboration:
+ return m_collabFileName;
+ break;
+ case Inheritance:
+ return m_inheritFileName;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ return "";
+}
+
+void DotClassGraph::computeTheGraph()
+{
+ computeGraph(
+ m_startNode,
+ m_graphType,
+ m_graphFormat,
+ m_lrRank ? "LR" : "",
+ m_graphType == Inheritance,
+ TRUE,
+ m_startNode->label(),
+ m_theGraph
+ );
+}
+
+QCString DotClassGraph::getMapLabel() const
+{
+ QCString mapName;
+ switch (m_graphType)
+ {
+ case Collaboration:
+ mapName="coll_map";
+ break;
+ case Inheritance:
+ mapName="inherit_map";
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ return escapeCharsInString(m_startNode->label(),FALSE)+"_"+escapeCharsInString(mapName,FALSE);
+}
+
+QCString DotClassGraph::getImgAltText() const
+{
+ switch (m_graphType)
+ {
+ case Collaboration:
+ return "Collaboration graph";
+ break;
+ case Inheritance:
+ return "Inheritance graph";
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ return "";
+}
+
+QCString DotClassGraph::writeGraph(FTextStream &out,
+ GraphOutputFormat graphFormat,
+ EmbeddedOutputFormat textFormat,
+ const char *path,
+ const char *fileName,
+ const char *relPath,
+ bool /*isTBRank*/,
+ bool generateImageMap,
+ int graphId)
+{
+ return DotGraph::writeGraph(out, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
+}
+
+//--------------------------------------------------------------------
+
+void DotClassGraph::writeXML(FTextStream &t)
+{
+ QDictIterator<DotNode> dni(*m_usedNodes);
+ DotNode *node;
+ for (;(node=dni.current());++dni)
+ {
+ node->writeXML(t,TRUE);
+ }
+}
+
+void DotClassGraph::writeDocbook(FTextStream &t)
+{
+ QDictIterator<DotNode> dni(*m_usedNodes);
+ DotNode *node;
+ for (;(node=dni.current());++dni)
+ {
+ node->writeDocbook(t,TRUE);
+ }
+}
+
+void DotClassGraph::writeDEF(FTextStream &t)
+{
+ QDictIterator<DotNode> dni(*m_usedNodes);
+ DotNode *node;
+ for (;(node=dni.current());++dni)
+ {
+ node->writeDEF(t);
+ }
+}
diff --git a/src/dotclassgraph.h b/src/dotclassgraph.h
new file mode 100644
index 0000000..b3b9291
--- /dev/null
+++ b/src/dotclassgraph.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTCLASSGRAPH_H
+#define DOTCLASSGRAPH_H
+
+#include "classdef.h"
+
+#include "dotgraph.h"
+
+/** Representation of a class inheritance or dependency graph */
+class DotClassGraph : public DotGraph
+{
+public:
+ DotClassGraph(const ClassDef *cd,GraphType t);
+ ~DotClassGraph();
+ bool isTrivial() const;
+ bool isTooBig() const;
+ QCString writeGraph(FTextStream &t,GraphOutputFormat gf,EmbeddedOutputFormat ef,
+ const char *path, const char *fileName, const char *relPath,
+ bool TBRank=TRUE,bool imageMap=TRUE,int graphId=-1);
+
+ void writeXML(FTextStream &t);
+ void writeDocbook(FTextStream &t);
+ void writeDEF(FTextStream &t);
+
+protected:
+ virtual QCString getBaseName() const;
+ virtual QCString getMapLabel() const;
+ virtual void computeTheGraph();
+ virtual QCString getImgAltText() const;
+
+private:
+ void buildGraph(const ClassDef *cd,DotNode *n,bool base,int distance);
+ bool determineVisibleNodes(DotNode *rootNode,int maxNodes,bool includeParents);
+ void determineTruncatedNodes(QList<DotNode> &queue,bool includeParents);
+ void addClass(const ClassDef *cd,DotNode *n,int prot,const char *label,
+ const char *usedName,const char *templSpec,
+ bool base,int distance);
+
+ DotNode * m_startNode;
+ QDict<DotNode> * m_usedNodes;
+ GraphType m_graphType;
+ QCString m_collabFileName;
+ QCString m_inheritFileName;
+ bool m_lrRank;
+};
+
+
+#endif
diff --git a/src/dotdirdeps.cpp b/src/dotdirdeps.cpp
new file mode 100644
index 0000000..85906d1
--- /dev/null
+++ b/src/dotdirdeps.cpp
@@ -0,0 +1,220 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotdirdeps.h"
+
+#include "ftextstream.h"
+#include "util.h"
+#include "doxygen.h"
+#include "config.h"
+
+void writeDotDirDepGraph(FTextStream &t,const DirDef *dd,bool linkRelations)
+{
+ t << "digraph \"" << dd->displayName() << "\" {\n";
+ if (Config_getBool(DOT_TRANSPARENT))
+ {
+ t << " bgcolor=transparent;\n";
+ }
+ t << " compound=true\n";
+ t << " node [ fontsize=\"" << DotGraph::DOT_FONTSIZE << "\", fontname=\"" << DotGraph::DOT_FONTNAME << "\"];\n";
+ t << " edge [ labelfontsize=\"" << DotGraph::DOT_FONTSIZE << "\", labelfontname=\"" << DotGraph::DOT_FONTNAME << "\"];\n";
+
+ QDict<DirDef> dirsInGraph(257);
+
+ dirsInGraph.insert(dd->getOutputFileBase(),dd);
+ if (dd->parent())
+ {
+ t << " subgraph cluster" << dd->parent()->getOutputFileBase() << " {\n";
+ t << " graph [ bgcolor=\"#ddddee\", pencolor=\"black\", label=\""
+ << dd->parent()->shortName()
+ << "\" fontname=\"" << DotGraph::DOT_FONTNAME << "\", fontsize=\"" << DotGraph::DOT_FONTSIZE << "\", URL=\"";
+ t << dd->parent()->getOutputFileBase() << Doxygen::htmlFileExtension;
+ t << "\"]\n";
+ }
+ if (dd->isCluster())
+ {
+ t << " subgraph cluster" << dd->getOutputFileBase() << " {\n";
+ t << " graph [ bgcolor=\"#eeeeff\", pencolor=\"black\", label=\"\""
+ << " URL=\"" << dd->getOutputFileBase() << Doxygen::htmlFileExtension
+ << "\"];\n";
+ t << " " << dd->getOutputFileBase() << " [shape=plaintext label=\""
+ << dd->shortName() << "\"];\n";
+
+ // add nodes for sub directories
+ QListIterator<DirDef> sdi(dd->subDirs());
+ const DirDef *sdir;
+ for (sdi.toFirst();(sdir=sdi.current());++sdi)
+ {
+ t << " " << sdir->getOutputFileBase() << " [shape=box label=\""
+ << sdir->shortName() << "\"";
+ if (sdir->isCluster())
+ {
+ t << " color=\"red\"";
+ }
+ else
+ {
+ t << " color=\"black\"";
+ }
+ t << " fillcolor=\"white\" style=\"filled\"";
+ t << " URL=\"" << sdir->getOutputFileBase()
+ << Doxygen::htmlFileExtension << "\"";
+ t << "];\n";
+ dirsInGraph.insert(sdir->getOutputFileBase(),sdir);
+ }
+ t << " }\n";
+ }
+ else
+ {
+ t << " " << dd->getOutputFileBase() << " [shape=box, label=\""
+ << dd->shortName() << "\", style=\"filled\", fillcolor=\"#eeeeff\","
+ << " pencolor=\"black\", URL=\"" << dd->getOutputFileBase()
+ << Doxygen::htmlFileExtension << "\"];\n";
+ }
+ if (dd->parent())
+ {
+ t << " }\n";
+ }
+
+ // add nodes for other used directories
+ QDictIterator<UsedDir> udi(*dd->usedDirs());
+ UsedDir *udir;
+ //printf("*** For dir %s\n",shortName().data());
+ for (udi.toFirst();(udir=udi.current());++udi)
+ // for each used dir (=directly used or a parent of a directly used dir)
+ {
+ const DirDef *usedDir=udir->dir();
+ const DirDef *dir=dd;
+ while (dir)
+ {
+ //printf("*** check relation %s->%s same_parent=%d !%s->isParentOf(%s)=%d\n",
+ // dir->shortName().data(),usedDir->shortName().data(),
+ // dir->parent()==usedDir->parent(),
+ // usedDir->shortName().data(),
+ // shortName().data(),
+ // !usedDir->isParentOf(this)
+ // );
+ if (dir!=usedDir && dir->parent()==usedDir->parent() &&
+ !usedDir->isParentOf(dd))
+ // include if both have the same parent (or no parent)
+ {
+ t << " " << usedDir->getOutputFileBase() << " [shape=box label=\""
+ << usedDir->shortName() << "\"";
+ if (usedDir->isCluster())
+ {
+ if (!Config_getBool(DOT_TRANSPARENT))
+ {
+ t << " fillcolor=\"white\" style=\"filled\"";
+ }
+ t << " color=\"red\"";
+ }
+ t << " URL=\"" << usedDir->getOutputFileBase()
+ << Doxygen::htmlFileExtension << "\"];\n";
+ dirsInGraph.insert(usedDir->getOutputFileBase(),usedDir);
+ break;
+ }
+ dir=dir->parent();
+ }
+ }
+
+ // add relations between all selected directories
+ const DirDef *dir;
+ QDictIterator<DirDef> di(dirsInGraph);
+ for (di.toFirst();(dir=di.current());++di) // foreach dir in the graph
+ {
+ QDictIterator<UsedDir> udi(*dir->usedDirs());
+ UsedDir *udir;
+ for (udi.toFirst();(udir=udi.current());++udi) // foreach used dir
+ {
+ const DirDef *usedDir=udir->dir();
+ if ((dir!=dd || !udir->inherited()) && // only show direct dependendies for this dir
+ (usedDir!=dd || !udir->inherited()) && // only show direct dependendies for this dir
+ !usedDir->isParentOf(dir) && // don't point to own parent
+ dirsInGraph.find(usedDir->getOutputFileBase())) // only point to nodes that are in the graph
+ {
+ QCString relationName;
+ relationName.sprintf("dir_%06d_%06d",dir->dirCount(),usedDir->dirCount());
+ if (Doxygen::dirRelations.find(relationName)==0)
+ {
+ // new relation
+ Doxygen::dirRelations.append(relationName,
+ new DirRelation(relationName,dir,udir));
+ }
+ int nrefs = udir->filePairs().count();
+ t << " " << dir->getOutputFileBase() << "->"
+ << usedDir->getOutputFileBase();
+ t << " [headlabel=\"" << nrefs << "\", labeldistance=1.5";
+ if (linkRelations)
+ {
+ t << " headhref=\"" << relationName << Doxygen::htmlFileExtension << "\"";
+ }
+ t << "];\n";
+ }
+ }
+ }
+
+ t << "}\n";
+}
+
+DotDirDeps::DotDirDeps(const DirDef *dir) : m_dir(dir)
+{
+}
+
+DotDirDeps::~DotDirDeps()
+{
+}
+
+QCString DotDirDeps::getBaseName() const
+{
+ return m_dir->getOutputFileBase()+"_dep";
+
+}
+
+void DotDirDeps::computeTheGraph()
+{
+ // compute md5 checksum of the graph were are about to generate
+ FTextStream md5stream(&m_theGraph);
+ //m_dir->writeDepGraph(md5stream);
+ writeDotDirDepGraph(md5stream,m_dir,m_linkRelations);
+}
+
+QCString DotDirDeps::getMapLabel() const
+{
+ return escapeCharsInString(m_baseName,FALSE);
+}
+
+QCString DotDirDeps::getImgAltText() const
+{
+ return convertToXML(m_dir->displayName());
+}
+
+QCString DotDirDeps::writeGraph(FTextStream &out,
+ GraphOutputFormat graphFormat,
+ EmbeddedOutputFormat textFormat,
+ const char *path,
+ const char *fileName,
+ const char *relPath,
+ bool generateImageMap,
+ int graphId,
+ bool linkRelations)
+{
+ m_linkRelations = linkRelations;
+ m_urlOnly = TRUE;
+ return DotGraph::writeGraph(out, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
+}
+
+bool DotDirDeps::isTrivial() const
+{
+ return m_dir->depGraphIsTrivial();
+}
diff --git a/src/dotdirdeps.h b/src/dotdirdeps.h
new file mode 100644
index 0000000..f5eef65
--- /dev/null
+++ b/src/dotdirdeps.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTDIRDEPS_H
+#define DOTDIRDEPS_H
+
+#include "dotgraph.h"
+#include "dirdef.h"
+
+/** Representation of an directory dependency graph */
+class DotDirDeps : public DotGraph
+{
+ public:
+ DotDirDeps(const DirDef *dir);
+ ~DotDirDeps();
+ bool isTrivial() const;
+ QCString writeGraph(FTextStream &out,
+ GraphOutputFormat gf,
+ EmbeddedOutputFormat ef,
+ const char *path,
+ const char *fileName,
+ const char *relPath,
+ bool writeImageMap=TRUE,
+ int graphId=-1,
+ bool linkRelations=TRUE);
+
+ protected:
+ virtual QCString getBaseName() const;
+ virtual QCString getMapLabel() const;
+ virtual void computeTheGraph();
+ virtual QCString getImgAltText() const;
+
+ private:
+ const DirDef *m_dir;
+
+ bool m_linkRelations;
+};
+
+#endif
diff --git a/src/dotfilepatcher.cpp b/src/dotfilepatcher.cpp
new file mode 100644
index 0000000..91b7c78
--- /dev/null
+++ b/src/dotfilepatcher.cpp
@@ -0,0 +1,539 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotfilepatcher.h"
+
+#include "qstring.h"
+#include "config.h"
+#include "qdir.h"
+#include "message.h"
+#include "ftextstream.h"
+#include "docparser.h"
+#include "doxygen.h"
+#include "util.h"
+#include "dot.h"
+
+static const char svgZoomHeader[] =
+"<svg id=\"main\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" onload=\"init(evt)\">\n"
+"<style type=\"text/css\"><![CDATA[\n"
+".edge:hover path { stroke: red; }\n"
+".edge:hover polygon { stroke: red; fill: red; }\n"
+"]]></style>\n"
+"<script type=\"text/javascript\"><![CDATA[\n"
+"var edges = document.getElementsByTagName('g');\n"
+"if (edges && edges.length) {\n"
+" for (var i=0;i<edges.length;i++) {\n"
+" if (edges[i].id.substr(0,4)=='edge') {\n"
+" edges[i].setAttribute('class','edge');\n"
+" }\n"
+" }\n"
+"}\n"
+"]]></script>\n"
+" <defs>\n"
+" <circle id=\"rim\" cx=\"0\" cy=\"0\" r=\"7\"/>\n"
+" <circle id=\"rim2\" cx=\"0\" cy=\"0\" r=\"3.5\"/>\n"
+" <g id=\"zoomPlus\">\n"
+" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"zoomplus.mouseover\" end=\"zoomplus.mouseout\"/>\n"
+" </use>\n"
+" <path d=\"M-4,0h8M0,-4v8\" fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" pointer-events=\"none\"/>\n"
+" </g>\n"
+" <g id=\"zoomMin\">\n"
+" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"zoomminus.mouseover\" end=\"zoomminus.mouseout\"/>\n"
+" </use>\n"
+" <path d=\"M-4,0h8\" fill=\"none\" stroke=\"white\" stroke-width=\"1.5\" pointer-events=\"none\"/>\n"
+" </g>\n"
+" <g id=\"dirArrow\">\n"
+" <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 id=\"resetDef\">\n"
+" <use xlink:href=\"#rim2\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"reset.mouseover\" end=\"reset.mouseout\"/>\n"
+" </use>\n"
+" </g>\n"
+" </defs>\n"
+"\n"
+"<script type=\"text/javascript\">\n"
+;
+
+static const char svgZoomFooter[] =
+// navigation panel
+" <g id=\"navigator\" transform=\"translate(0 0)\" fill=\"#404254\">\n"
+" <rect fill=\"#f2f5e9\" fill-opacity=\"0.5\" stroke=\"#606060\" stroke-width=\".5\" x=\"0\" y=\"0\" width=\"60\" height=\"60\"/>\n"
+// zoom in
+" <use id=\"zoomplus\" xlink:href=\"#zoomPlus\" x=\"17\" y=\"9\" onmousedown=\"handleZoom(evt,'in')\"/>\n"
+// zoom out
+" <use id=\"zoomminus\" xlink:href=\"#zoomMin\" x=\"42\" y=\"9\" onmousedown=\"handleZoom(evt,'out')\"/>\n"
+// reset zoom
+" <use id=\"reset\" xlink:href=\"#resetDef\" x=\"30\" y=\"36\" onmousedown=\"handleReset()\"/>\n"
+// arrow up
+" <g id=\"arrowUp\" xlink:href=\"#dirArrow\" transform=\"translate(30 24)\" onmousedown=\"handlePan(0,-1)\">\n"
+" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowUp.mouseover\" end=\"arrowUp.mouseout\"/>\n"
+" </use>\n"
+" <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"
+// arrow right
+" <g id=\"arrowRight\" xlink:href=\"#dirArrow\" transform=\"rotate(90) translate(36 -43)\" onmousedown=\"handlePan(1,0)\">\n"
+" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowRight.mouseover\" end=\"arrowRight.mouseout\"/>\n"
+" </use>\n"
+" <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"
+// arrow down
+" <g id=\"arrowDown\" xlink:href=\"#dirArrow\" transform=\"rotate(180) translate(-30 -48)\" onmousedown=\"handlePan(0,1)\">\n"
+" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowDown.mouseover\" end=\"arrowDown.mouseout\"/>\n"
+" </use>\n"
+" <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"
+// arrow left
+" <g id=\"arrowLeft\" xlink:href=\"#dirArrow\" transform=\"rotate(270) translate(-36 17)\" onmousedown=\"handlePan(-1,0)\">\n"
+" <use xlink:href=\"#rim\" fill=\"#404040\">\n"
+" <set attributeName=\"fill\" to=\"#808080\" begin=\"arrowLeft.mouseover\" end=\"arrowLeft.mouseout\"/>\n"
+" </use>\n"
+" <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 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"
+" <rect id=\"button\" ry=\"5\" rx=\"5\" y=\"6\" x=\"6\" height=\"38\" width=\"38\"\n"
+" fill=\"#f2f5e9\" fill-opacity=\"0.5\" stroke=\"#606060\" stroke-width=\"1.0\"/>\n"
+" <path id=\"arrow\"\n"
+" d=\"M 11.500037,31.436501 C 11.940474,20.09759 22.043105,11.32322 32.158766,21.979434 L 37.068811,17.246167 C 37.068811,17.246167 37.088388,32 37.088388,32 L 22.160133,31.978069 C 22.160133,31.978069 26.997745,27.140456 26.997745,27.140456 C 18.528582,18.264221 13.291696,25.230495 11.500037,31.436501 z\"\n"
+" style=\"fill:#404040;\"/>\n"
+" </a>\n"
+" </g>\n"
+" </svg>\n"
+"</svg>\n"
+;
+
+static QCString replaceRef(const QCString &buf,const QCString relPath,
+ bool urlOnly,const QCString &context,const QCString &target=QCString())
+{
+ // search for href="...", store ... part in link
+ QCString href = "href";
+ //bool isXLink=FALSE;
+ int len = 6;
+ int indexS = buf.find("href=\""), indexE;
+ bool setTarget = FALSE;
+ if (indexS>5 && buf.find("xlink:href=\"")!=-1) // XLink href (for SVG)
+ {
+ indexS-=6;
+ len+=6;
+ href.prepend("xlink:");
+ //isXLink=TRUE;
+ }
+ if (indexS>=0 && (indexE=buf.find('"',indexS+len))!=-1)
+ {
+ QCString link = buf.mid(indexS+len,indexE-indexS-len);
+ QCString result;
+ if (urlOnly) // for user defined dot graphs
+ {
+ if (link.left(5)=="\\ref " || link.left(5)=="@ref ") // \ref url
+ {
+ result=href+"=\"";
+ // fake ref node to resolve the url
+ DocRef *df = new DocRef( (DocNode*) 0, link.mid(5), context );
+ result+=externalRef(relPath,df->ref(),TRUE);
+ if (!df->file().isEmpty())
+ result += df->file().data() + Doxygen::htmlFileExtension;
+ if (!df->anchor().isEmpty())
+ result += "#" + df->anchor();
+ delete df;
+ result += "\"";
+ }
+ else
+ {
+ result = href+"=\"" + link + "\"";
+ }
+ }
+ else // ref$url (external ref via tag file), or $url (local ref)
+ {
+ int marker = link.find('$');
+ if (marker!=-1)
+ {
+ QCString ref = link.left(marker);
+ QCString url = link.mid(marker+1);
+ if (!ref.isEmpty())
+ {
+ result = externalLinkTarget();
+ if (result != "") setTarget = TRUE;
+ }
+ result+= href+"=\"";
+ result+=externalRef(relPath,ref,TRUE);
+ result+= url + "\"";
+ }
+ else // should not happen, but handle properly anyway
+ {
+ result = href+"=\"" + link + "\"";
+ }
+ }
+ if (!target.isEmpty() && !setTarget)
+ {
+ result+=" target=\""+target+"\"";
+ }
+ QCString leftPart = buf.left(indexS);
+ QCString rightPart = buf.mid(indexE+1);
+ return leftPart + result + rightPart;
+ }
+ else
+ {
+ return buf;
+ }
+}
+
+/*! converts the rectangles in a client site image map into a stream
+* \param t the stream to which the result is written.
+* \param mapName the name of the map file.
+* \param relPath the relative path to the root of the output directory
+* (used in case CREATE_SUBDIRS is enabled).
+* \param urlOnly if FALSE the url field in the map contains an external
+* references followed by a $ and then the URL.
+* \param context the context (file, class, or namespace) in which the
+* map file was found
+* \returns TRUE if successful.
+*/
+bool convertMapFile(FTextStream &t,const char *mapName,
+ const QCString relPath, bool urlOnly,
+ const QCString &context)
+{
+ QFile f(mapName);
+ if (!f.open(IO_ReadOnly))
+ {
+ err("problems opening map file %s for inclusion in the docs!\n"
+ "If you installed Graphviz/dot after a previous failing run, \n"
+ "try deleting the output directory and rerun doxygen.\n",mapName);
+ return FALSE;
+ }
+ const int maxLineLen=10240;
+ while (!f.atEnd()) // foreach line
+ {
+ QCString buf(maxLineLen);
+ int numBytes = f.readLine(buf.rawData(),maxLineLen);
+ if (numBytes>0)
+ {
+ buf.resize(numBytes+1);
+
+ if (buf.left(5)=="<area")
+ {
+ QCString replBuf = replaceRef(buf,relPath,urlOnly,context);
+ // strip id="..." from replBuf since the id's are not needed and not unique.
+ int indexS = replBuf.find("id=\""), indexE;
+ if (indexS>0 && (indexE=replBuf.find('"',indexS+4))!=-1)
+ {
+ t << replBuf.left(indexS-1) << replBuf.right(replBuf.length() - indexE - 1);
+ }
+ else
+ {
+ t << replBuf;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+DotFilePatcher::DotFilePatcher(const char *patchFile)
+ : m_patchFile(patchFile)
+{
+ m_maps.setAutoDelete(TRUE);
+}
+
+QCString DotFilePatcher::file() const
+{
+ return m_patchFile;
+}
+
+int DotFilePatcher::addMap(const QCString &mapFile,const QCString &relPath,
+ bool urlOnly,const QCString &context,const QCString &label)
+{
+ int id = m_maps.count();
+ Map *map = new Map;
+ map->mapFile = mapFile;
+ map->relPath = relPath;
+ map->urlOnly = urlOnly;
+ map->context = context;
+ map->label = label;
+ map->zoomable = FALSE;
+ map->graphId = -1;
+ m_maps.append(map);
+ return id;
+}
+
+int DotFilePatcher::addFigure(const QCString &baseName,
+ const QCString &figureName,bool heightCheck)
+{
+ int id = m_maps.count();
+ Map *map = new Map;
+ map->mapFile = figureName;
+ map->urlOnly = heightCheck;
+ map->label = baseName;
+ map->zoomable = FALSE;
+ map->graphId = -1;
+ m_maps.append(map);
+ return id;
+}
+
+int DotFilePatcher::addSVGConversion(const QCString &relPath,bool urlOnly,
+ const QCString &context,bool zoomable,
+ int graphId)
+{
+ int id = m_maps.count();
+ Map *map = new Map;
+ map->relPath = relPath;
+ map->urlOnly = urlOnly;
+ map->context = context;
+ map->zoomable = zoomable;
+ map->graphId = graphId;
+ m_maps.append(map);
+ return id;
+}
+
+int DotFilePatcher::addSVGObject(const QCString &baseName,
+ const QCString &absImgName,
+ const QCString &relPath)
+{
+ int id = m_maps.count();
+ Map *map = new Map;
+ map->mapFile = absImgName;
+ map->relPath = relPath;
+ map->label = baseName;
+ map->zoomable = FALSE;
+ map->graphId = -1;
+ m_maps.append(map);
+ return id;
+}
+
+bool DotFilePatcher::run()
+{
+ //printf("DotFilePatcher::run(): %s\n",m_patchFile.data());
+ bool interactiveSVG_local = Config_getBool(INTERACTIVE_SVG);
+ bool isSVGFile = m_patchFile.right(4)==".svg";
+ int graphId = -1;
+ QCString relPath;
+ if (isSVGFile)
+ {
+ Map *map = m_maps.at(0); // there is only one 'map' for a SVG file
+ interactiveSVG_local = interactiveSVG_local && map->zoomable;
+ graphId = map->graphId;
+ relPath = map->relPath;
+ //printf("DotFilePatcher::addSVGConversion: file=%s zoomable=%d\n",
+ // m_patchFile.data(),map->zoomable);
+ }
+ QString tmpName = QString::fromUtf8(m_patchFile+".tmp");
+ QString patchFile = QString::fromUtf8(m_patchFile);
+ if (!QDir::current().rename(patchFile,tmpName))
+ {
+ err("Failed to rename file %s to %s!\n",m_patchFile.data(),tmpName.data());
+ return FALSE;
+ }
+ QFile fi(tmpName);
+ QFile fo(patchFile);
+ if (!fi.open(IO_ReadOnly))
+ {
+ err("problem opening file %s for patching!\n",tmpName.data());
+ QDir::current().rename(tmpName,patchFile);
+ return FALSE;
+ }
+ if (!fo.open(IO_WriteOnly))
+ {
+ err("problem opening file %s for patching!\n",m_patchFile.data());
+ QDir::current().rename(tmpName,patchFile);
+ return FALSE;
+ }
+ FTextStream t(&fo);
+ const int maxLineLen=100*1024;
+ int lineNr=1;
+ int width,height;
+ bool insideHeader=FALSE;
+ bool replacedHeader=FALSE;
+ bool foundSize=FALSE;
+ while (!fi.atEnd()) // foreach line
+ {
+ QCString line(maxLineLen);
+ int numBytes = fi.readLine(line.rawData(),maxLineLen);
+ if (numBytes<=0)
+ {
+ break;
+ }
+ line.resize(numBytes+1);
+
+ //printf("line=[%s]\n",line.stripWhiteSpace().data());
+ int i;
+ ASSERT(numBytes<maxLineLen);
+ if (isSVGFile)
+ {
+ if (interactiveSVG_local)
+ {
+ if (line.find("<svg")!=-1 && !replacedHeader)
+ {
+ int count;
+ count = sscanf(line.data(),"<svg width=\"%dpt\" height=\"%dpt\"",&width,&height);
+ //printf("width=%d height=%d\n",width,height);
+ foundSize = count==2 && (width>500 || height>450);
+ if (foundSize) insideHeader=TRUE;
+ }
+ else if (insideHeader && !replacedHeader && line.find("<title>")!=-1)
+ {
+ if (foundSize)
+ {
+ // insert special replacement header for interactive SVGs
+ t << "<!--zoomable " << height << " -->\n";
+ t << svgZoomHeader;
+ t << "var viewWidth = " << width << ";\n";
+ t << "var viewHeight = " << height << ";\n";
+ if (graphId>=0)
+ {
+ t << "var sectionId = 'dynsection-" << graphId << "';\n";
+ }
+ t << "</script>\n";
+ t << "<script xlink:href=\"" << relPath << "svgpan.js\"/>\n";
+ t << "<svg id=\"graph\" class=\"graph\">\n";
+ t << "<g id=\"viewport\">\n";
+ }
+ insideHeader=FALSE;
+ replacedHeader=TRUE;
+ }
+ }
+ if (!insideHeader || !foundSize) // copy SVG and replace refs,
+ // unless we are inside the header of the SVG.
+ // Then we replace it with another header.
+ {
+ Map *map = m_maps.at(0); // there is only one 'map' for a SVG file
+ t << replaceRef(line,map->relPath,map->urlOnly,map->context,"_top");
+ }
+ }
+ else if ((i=line.find("<!-- SVG"))!=-1 || (i=line.find("[!-- SVG"))!=-1)
+ {
+ //printf("Found marker at %d\n",i);
+ int mapId=-1;
+ t << line.left(i);
+ int n = sscanf(line.data()+i+1,"!-- SVG %d",&mapId);
+ if (n==1 && mapId>=0 && mapId<(int)m_maps.count())
+ {
+ int e = QMAX(line.find("--]"),line.find("-->"));
+ Map *map = m_maps.at(mapId);
+ //printf("DotFilePatcher::writeSVGFigure: file=%s zoomable=%d\n",
+ // m_patchFile.data(),map->zoomable);
+ if (!writeSVGFigureLink(t,map->relPath,map->label,map->mapFile))
+ {
+ err("Problem extracting size from SVG file %s\n",map->mapFile.data());
+ }
+ if (e!=-1) t << line.mid(e+3);
+ }
+ else // error invalid map id!
+ {
+ err("Found invalid SVG id in file %s!\n",m_patchFile.data());
+ t << line.mid(i);
+ }
+ }
+ else if ((i=line.find("<!-- MAP"))!=-1)
+ {
+ int mapId=-1;
+ t << line.left(i);
+ int n = sscanf(line.data()+i,"<!-- MAP %d",&mapId);
+ if (n==1 && mapId>=0 && mapId<(int)m_maps.count())
+ {
+ QGString result;
+ FTextStream tt(&result);
+ Map *map = m_maps.at(mapId);
+ //printf("patching MAP %d in file %s with contents of %s\n",
+ // mapId,m_patchFile.data(),map->mapFile.data());
+ convertMapFile(tt,map->mapFile,map->relPath,map->urlOnly,map->context);
+ if (!result.isEmpty())
+ {
+ t << "<map name=\"" << map->label << "\" id=\"" << map->label << "\">" << endl;
+ t << result;
+ t << "</map>" << endl;
+ }
+ }
+ else // error invalid map id!
+ {
+ err("Found invalid MAP id in file %s!\n",m_patchFile.data());
+ t << line.mid(i);
+ }
+ }
+ else if ((i=line.find("% FIG"))!=-1)
+ {
+ int mapId=-1;
+ int n = sscanf(line.data()+i+2,"FIG %d",&mapId);
+ //printf("line='%s' n=%d\n",line.data()+i,n);
+ if (n==1 && mapId>=0 && mapId<(int)m_maps.count())
+ {
+ Map *map = m_maps.at(mapId);
+ //printf("patching FIG %d in file %s with contents of %s\n",
+ // mapId,m_patchFile.data(),map->mapFile.data());
+ if (!DotGraph::writeVecGfxFigure(t,map->label,map->mapFile))
+ {
+ err("problem writing FIG %d figure!\n",mapId);
+ return FALSE;
+ }
+ }
+ else // error invalid map id!
+ {
+ err("Found invalid bounding FIG %d in file %s!\n",mapId,m_patchFile.data());
+ t << line;
+ }
+ }
+ else
+ {
+ t << line;
+ }
+ lineNr++;
+ }
+ fi.close();
+ if (isSVGFile && interactiveSVG_local && replacedHeader)
+ {
+ QCString orgName=m_patchFile.left(m_patchFile.length()-4)+"_org.svg";
+ t << substitute(svgZoomFooter,"$orgname",stripPath(orgName));
+ fo.close();
+ // keep original SVG file so we can refer to it, we do need to replace
+ // dummy link by real ones
+ QFile fi(tmpName);
+ QFile fo(orgName);
+ if (!fi.open(IO_ReadOnly))
+ {
+ err("problem opening file %s for reading!\n",tmpName.data());
+ return FALSE;
+ }
+ if (!fo.open(IO_WriteOnly))
+ {
+ err("problem opening file %s for writing!\n",orgName.data());
+ return FALSE;
+ }
+ FTextStream t(&fo);
+ while (!fi.atEnd()) // foreach line
+ {
+ QCString line(maxLineLen);
+ int numBytes = fi.readLine(line.rawData(),maxLineLen);
+ if (numBytes<=0)
+ {
+ break;
+ }
+ line.resize(numBytes+1);
+ Map *map = m_maps.at(0); // there is only one 'map' for a SVG file
+ t << replaceRef(line,map->relPath,map->urlOnly,map->context,"_top");
+ }
+ fi.close();
+ fo.close();
+ }
+ // remove temporary file
+ QDir::current().remove(tmpName);
+ return TRUE;
+}
diff --git a/src/dotfilepatcher.h b/src/dotfilepatcher.h
new file mode 100644
index 0000000..dd5c511
--- /dev/null
+++ b/src/dotfilepatcher.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTFILEPATCHER_H
+#define DOTFILEPATCHER_H
+
+#include "qcstring.h"
+#include "qlist.h"
+
+/** Helper class to insert a set of map file into an output file */
+class DotFilePatcher
+{
+ public:
+ DotFilePatcher(const char *patchFile);
+ int addMap(const QCString &mapFile,const QCString &relPath,
+ bool urlOnly,const QCString &context,const QCString &label);
+ int addFigure(const QCString &baseName,
+ const QCString &figureName,bool heightCheck);
+ int addSVGConversion(const QCString &relPath,bool urlOnly,
+ const QCString &context,bool zoomable,int graphId);
+ int addSVGObject(const QCString &baseName, const QCString &figureName,
+ const QCString &relPath);
+ bool run();
+ QCString file() const;
+
+ private:
+ struct Map
+ {
+ QCString mapFile;
+ QCString relPath;
+ bool urlOnly;
+ QCString context;
+ QCString label;
+ bool zoomable;
+ int graphId;
+ };
+ QList<Map> m_maps;
+ QCString m_patchFile;
+};
+
+#endif
diff --git a/src/dotgfxhierarchytable.cpp b/src/dotgfxhierarchytable.cpp
new file mode 100644
index 0000000..0a7942f
--- /dev/null
+++ b/src/dotgfxhierarchytable.cpp
@@ -0,0 +1,302 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotgfxhierarchytable.h"
+
+#include "language.h"
+#include "util.h"
+#include "message.h"
+#include "doxygen.h"
+#include "classlist.h"
+
+#define OPTIMIZE_OUTPUT_SLICE Config_getBool(OPTIMIZE_OUTPUT_SLICE)
+
+QCString DotGfxHierarchyTable::getBaseName() const
+{
+ QCString baseName;
+ if (m_prefix.isEmpty())
+ baseName.sprintf("inherit_graph_%d", m_graphId);
+ else
+ baseName.sprintf("%sinherit_graph_%d",m_prefix.data(), m_graphId);
+ return baseName;
+}
+
+void DotGfxHierarchyTable::computeTheGraph()
+{
+ QListIterator<DotNode> dnli2(*m_rootNodes);
+ DotNode *node;
+
+ FTextStream md5stream(&m_theGraph);
+ writeGraphHeader(md5stream,theTranslator->trGraphicalHierarchy());
+ md5stream << " rankdir=\"LR\";" << endl;
+ for (dnli2.toFirst();(node=dnli2.current());++dnli2)
+ {
+ if (node->subgraphId()==m_rootSubgraphNode->subgraphId())
+ {
+ node->clearWriteFlag();
+ }
+ }
+ for (dnli2.toFirst();(node=dnli2.current());++dnli2)
+ {
+ if (node->subgraphId()==m_rootSubgraphNode->subgraphId())
+ {
+ node->write(md5stream,Hierarchy,GOF_BITMAP,FALSE,TRUE,TRUE);
+ }
+ }
+ writeGraphFooter(md5stream);
+
+}
+
+QCString DotGfxHierarchyTable::getMapLabel() const
+{
+ return escapeCharsInString(m_rootSubgraphNode->label(),FALSE);
+}
+
+void DotGfxHierarchyTable::createGraph(DotNode *n,FTextStream &out,
+ const char *path,const char *fileName,int id)
+{
+ m_rootSubgraphNode = n;
+ m_graphId = id;
+ m_noDivTag = TRUE;
+ m_zoomable = FALSE;
+ DotGraph::writeGraph(out, GOF_BITMAP, EOF_Html, path, fileName, "", TRUE, 0);
+}
+
+void DotGfxHierarchyTable::writeGraph(FTextStream &out,
+ const char *path,const char *fileName)
+{
+ //printf("DotGfxHierarchyTable::writeGraph(%s)\n",name);
+ //printf("m_rootNodes=%p count=%d\n",m_rootNodes,m_rootNodes->count());
+
+ if (m_rootSubgraphs->count()==0) return;
+
+ QDir d(path);
+ // store the original directory
+ if (!d.exists())
+ {
+ err("Output dir %s does not exist!\n",path); exit(1);
+ }
+
+ // put each connected subgraph of the hierarchy in a row of the HTML output
+ out << "<table border=\"0\" cellspacing=\"10\" cellpadding=\"0\">" << endl;
+
+ QListIterator<DotNode> dnli(*m_rootSubgraphs);
+ DotNode *n;
+ int count=0;
+ for (dnli.toFirst();(n=dnli.current());++dnli)
+ {
+ out << "<tr><td>";
+ createGraph(n,out,path,fileName,count++);
+ out << "</td></tr>" << endl;
+ }
+ out << "</table>" << endl;
+}
+
+void DotGfxHierarchyTable::addHierarchy(DotNode *n,const ClassDef *cd,bool hideSuper)
+{
+ //printf("addHierarchy '%s' baseClasses=%d\n",cd->name().data(),cd->baseClasses()->count());
+ if (cd->subClasses())
+ {
+ BaseClassListIterator bcli(*cd->subClasses());
+ BaseClassDef *bcd;
+ for ( ; (bcd=bcli.current()) ; ++bcli )
+ {
+ ClassDef *bClass=bcd->classDef;
+ //printf(" Trying sub class='%s' usedNodes=%d\n",bClass->name().data(),m_usedNodes->count());
+ if (bClass->isVisibleInHierarchy() && hasVisibleRoot(bClass->baseClasses()))
+ {
+ DotNode *bn;
+ //printf(" Node '%s' Found visible class='%s'\n",n->label().data(),
+ // bClass->name().data());
+ if ((bn=m_usedNodes->find(bClass->name()))) // node already present
+ {
+ if (n->children()==0 || n->children()->findRef(bn)==-1) // no arrow yet
+ {
+ n->addChild(bn,bcd->prot);
+ bn->addParent(n);
+ //printf(" Adding node %s to existing base node %s (c=%d,p=%d)\n",
+ // n->label().data(),
+ // bn->label().data(),
+ // bn->children() ? bn->children()->count() : 0,
+ // bn->parents() ? bn->parents()->count() : 0
+ // );
+ }
+ //else
+ //{
+ // printf(" Class already has an arrow!\n");
+ //}
+ }
+ else
+ {
+ QCString tmp_url="";
+ if (bClass->isLinkable() && !bClass->isHidden())
+ {
+ tmp_url=bClass->getReference()+"$"+bClass->getOutputFileBase();
+ if (!bClass->anchor().isEmpty())
+ {
+ tmp_url+="#"+bClass->anchor();
+ }
+ }
+ QCString tooltip = bClass->briefDescriptionAsTooltip();
+ bn = new DotNode(getNextNodeNumber(),
+ bClass->displayName(),
+ tooltip,
+ tmp_url.data()
+ );
+ n->addChild(bn,bcd->prot);
+ bn->addParent(n);
+ //printf(" Adding node %s to new base node %s (c=%d,p=%d)\n",
+ // n->label().data(),
+ // bn->label().data(),
+ // bn->children() ? bn->children()->count() : 0,
+ // bn->parents() ? bn->parents()->count() : 0
+ // );
+ //printf(" inserting %s (%p)\n",bClass->name().data(),bn);
+ m_usedNodes->insert(bClass->name(),bn); // add node to the used list
+ }
+ if (!bClass->isVisited() && !hideSuper && bClass->subClasses())
+ {
+ bool wasVisited=bClass->isVisited();
+ bClass->setVisited(TRUE);
+ addHierarchy(bn,bClass,wasVisited);
+ }
+ }
+ }
+ }
+ //printf("end addHierarchy\n");
+}
+
+void DotGfxHierarchyTable::addClassList(const ClassSDict *cl)
+{
+ ClassSDict::Iterator cli(*cl);
+ ClassDef *cd;
+ for (cli.toLast();(cd=cli.current());--cli)
+ {
+ //printf("Trying %s subClasses=%d\n",cd->name().data(),cd->subClasses()->count());
+ if (cd->getLanguage()==SrcLangExt_VHDL &&
+ (VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS
+ )
+ {
+ continue;
+ }
+ if (OPTIMIZE_OUTPUT_SLICE && cd->compoundType() != m_classType)
+ {
+ continue;
+ }
+ if (!hasVisibleRoot(cd->baseClasses()) &&
+ cd->isVisibleInHierarchy()
+ ) // root node in the forest
+ {
+ QCString tmp_url="";
+ if (cd->isLinkable() && !cd->isHidden())
+ {
+ tmp_url=cd->getReference()+"$"+cd->getOutputFileBase();
+ if (!cd->anchor().isEmpty())
+ {
+ tmp_url+="#"+cd->anchor();
+ }
+ }
+ //printf("Inserting root class %s\n",cd->name().data());
+ QCString tooltip = cd->briefDescriptionAsTooltip();
+ DotNode *n = new DotNode(getNextNodeNumber(),
+ cd->displayName(),
+ tooltip,
+ tmp_url.data());
+
+ //m_usedNodes->clear();
+ m_usedNodes->insert(cd->name(),n);
+ m_rootNodes->insert(0,n);
+ if (!cd->isVisited() && cd->subClasses())
+ {
+ addHierarchy(n,cd,cd->isVisited());
+ cd->setVisited(TRUE);
+ }
+ }
+ }
+}
+
+DotGfxHierarchyTable::DotGfxHierarchyTable(const char *prefix,ClassDef::CompoundType ct)
+ : m_prefix(prefix)
+ , m_classType(ct)
+{
+ m_rootNodes = new QList<DotNode>;
+ m_usedNodes = new QDict<DotNode>(1009);
+ m_usedNodes->setAutoDelete(TRUE);
+ m_rootSubgraphs = new DotNodeList;
+
+ // build a graph with each class as a node and the inheritance relations
+ // as edges
+ initClassHierarchy(Doxygen::classSDict);
+ initClassHierarchy(Doxygen::hiddenClasses);
+ addClassList(Doxygen::classSDict);
+ addClassList(Doxygen::hiddenClasses);
+ // m_usedNodes now contains all nodes in the graph
+
+ // color the graph into a set of independent subgraphs
+ bool done=FALSE;
+ int curColor=0;
+ QListIterator<DotNode> dnli(*m_rootNodes);
+ while (!done) // there are still nodes to color
+ {
+ DotNode *n;
+ done=TRUE; // we are done unless there are still uncolored nodes
+ for (dnli.toLast();(n=dnli.current());--dnli)
+ {
+ if (n->subgraphId()==-1) // not yet colored
+ {
+ //printf("Starting at node %s (%p): %d\n",n->label().data(),n,curColor);
+ done=FALSE; // still uncolored nodes
+ n->setSubgraphId(curColor);
+ n->markAsVisible();
+ n->colorConnectedNodes(curColor);
+ curColor++;
+ const DotNode *dn=n->findDocNode();
+ if (dn!=0)
+ m_rootSubgraphs->inSort(dn);
+ else
+ m_rootSubgraphs->inSort(n);
+ }
+ }
+ }
+
+ //printf("Number of independent subgraphs: %d\n",curColor);
+ QListIterator<DotNode> dnli2(*m_rootSubgraphs);
+ DotNode *n;
+ for (dnli2.toFirst();(n=dnli2.current());++dnli2)
+ {
+ //printf("Node %s color=%d (c=%d,p=%d)\n",
+ // n->label().data(),n->m_subgraphId,
+ // n->children()?n->children()->count():0,
+ // n->parents()?n->parents()->count():0);
+ int number=0;
+ n->renumberNodes(number);
+ }
+}
+
+DotGfxHierarchyTable::~DotGfxHierarchyTable()
+{
+ //printf("DotGfxHierarchyTable::~DotGfxHierarchyTable\n");
+
+ //QDictIterator<DotNode> di(*m_usedNodes);
+ //DotNode *n;
+ //for (;(n=di.current());++di)
+ //{
+ // printf("Node %p: %s\n",n,n->label().data());
+ //}
+
+ delete m_rootNodes;
+ delete m_usedNodes;
+ delete m_rootSubgraphs;
+}
diff --git a/src/dotgfxhierarchytable.h b/src/dotgfxhierarchytable.h
new file mode 100644
index 0000000..5a5bcad
--- /dev/null
+++ b/src/dotgfxhierarchytable.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTGFXHIERARCHYTABLE_H
+#define DOTGFXHIERARCHYTABLE_H
+
+#include "classdef.h"
+#include "ftextstream.h"
+
+#include "dotgraph.h"
+#include "dotnode.h"
+
+/** Represents a graphical class hierarchy */
+class DotGfxHierarchyTable : public DotGraph
+{
+ public:
+ DotGfxHierarchyTable(const char *prefix="",ClassDef::CompoundType ct=ClassDef::Class);
+ ~DotGfxHierarchyTable();
+ void createGraph(DotNode *rootNode,FTextStream &t,const char *path,
+ const char *fileName,int id);
+ void writeGraph(FTextStream &t,const char *path, const char *fileName);
+ const DotNodeList *subGraphs() const { return m_rootSubgraphs; }
+
+ protected:
+ virtual QCString getBaseName() const;
+ virtual QCString getMapLabel() const;
+ virtual void computeTheGraph();
+
+ private:
+ void addHierarchy(DotNode *n,const ClassDef *cd,bool hide);
+ void addClassList(const ClassSDict *cl);
+
+ int m_graphId;
+ QCString m_prefix;
+ ClassDef::CompoundType m_classType;
+ QList<DotNode> *m_rootNodes;
+ QDict<DotNode> *m_usedNodes;
+ DotNodeList *m_rootSubgraphs;
+ DotNode * m_rootSubgraphNode;
+};
+
+
+#endif
diff --git a/src/dotgraph.cpp b/src/dotgraph.cpp
new file mode 100644
index 0000000..ca6bcca
--- /dev/null
+++ b/src/dotgraph.cpp
@@ -0,0 +1,400 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "config.h"
+#include "doxygen.h"
+#include "index.h"
+#include "md5.h"
+#include "message.h"
+#include "util.h"
+
+#include "dot.h"
+#include "dotrunner.h"
+#include "dotgraph.h"
+#include "dotnode.h"
+
+#define MAP_CMD "cmapx"
+
+QCString DotGraph::DOT_FONTNAME; // will be initialized in initDot
+int DotGraph::DOT_FONTSIZE; // will be initialized in initDot
+
+/*! Checks if a file "baseName".md5 exists. If so the contents
+* are compared with \a md5. If equal FALSE is returned.
+* The .md5 is created or updated after successful creation of the output file.
+*/
+static bool checkMd5Signature(const QCString &baseName,
+ const QCString &md5)
+{
+ QFile f(baseName+".md5");
+ if (f.open(IO_ReadOnly))
+ {
+ // read checksum
+ QCString md5stored(33);
+ int bytesRead=f.readBlock(md5stored.rawData(),32);
+ md5stored[32]='\0';
+ // compare checksum
+ if (bytesRead==32 && md5==md5stored)
+ {
+ // bail out if equal
+ return FALSE;
+ }
+ }
+ f.close();
+ return TRUE;
+}
+
+static bool checkDeliverables(const QCString &file1,
+ const QCString &file2=QCString())
+{
+ bool file1Ok = TRUE;
+ bool file2Ok = TRUE;
+ if (!file1.isEmpty())
+ {
+ QFileInfo fi(file1);
+ file1Ok = (fi.exists() && fi.size()>0);
+ }
+ if (!file2.isEmpty())
+ {
+ QFileInfo fi(file2);
+ file2Ok = (fi.exists() && fi.size()>0);
+ }
+ return file1Ok && file2Ok;
+}
+
+static void removeDotGraph(const QCString &dotName)
+{
+ if (Config_getBool(DOT_CLEANUP))
+ {
+ QDir d;
+ d.remove(dotName);
+ }
+}
+
+static bool insertMapFile(FTextStream &out,const QCString &mapFile,
+ const QCString &relPath,const QCString &mapLabel)
+{
+ QFileInfo fi(mapFile);
+ if (fi.exists() && fi.size()>0) // reuse existing map file
+ {
+ QGString tmpstr;
+ FTextStream tmpout(&tmpstr);
+ convertMapFile(tmpout,mapFile,relPath,FALSE);
+ if (!tmpstr.isEmpty())
+ {
+ out << "<map name=\"" << mapLabel << "\" id=\"" << mapLabel << "\">" << endl;
+ out << tmpstr;
+ out << "</map>" << endl;
+ }
+ return TRUE;
+ }
+ return FALSE; // no map file yet, need to generate it
+}
+
+//--------------------------------------------------------------------
+
+QCString DotGraph::IMG_EXT;
+
+QCString DotGraph::imgName() const
+{
+ return m_baseName + ((m_graphFormat == GOF_BITMAP) ?
+ ("." + IMG_EXT) : (Config_getBool(USE_PDFLATEX) ? ".pdf" : ".eps"));
+}
+
+QCString DotGraph::writeGraph(
+ FTextStream& t, // output stream for the code file (html, ...)
+ GraphOutputFormat gf, // bitmap(png/svg) or ps(eps/pdf)
+ EmbeddedOutputFormat ef, // html, latex, ...
+ const char* path, // output folder
+ const char* fileName, // name of the code file (for code patcher)
+ const char* relPath, // output folder relativ to code file
+ bool generateImageMap, // in case of bitmap, shall there be code generated?
+ int graphId) // number of this graph in the current code, used in svg code
+{
+ m_graphFormat = gf;
+ m_textFormat = ef;
+ m_dir = QDir(path);
+ m_fileName = fileName;
+ m_relPath = relPath;
+ m_generateImageMap = generateImageMap;
+ m_graphId = graphId;
+
+ m_absPath = QCString(m_dir.absPath().data()) + "/";
+ m_baseName = getBaseName();
+
+ computeTheGraph();
+
+ m_regenerate = prepareDotFile();
+
+ if (!m_doNotAddImageToIndex) Doxygen::indexList->addImageFile(imgName());
+
+ generateCode(t);
+
+ return m_baseName;
+}
+
+bool DotGraph::prepareDotFile()
+{
+ if (!m_dir.exists())
+ {
+ err("Output dir %s does not exist!\n", m_dir.path().data()); exit(1);
+ }
+
+ QCString sigStr(33);
+ uchar md5_sig[16];
+ // calculate md5
+ MD5Buffer((const unsigned char*)m_theGraph.data(), m_theGraph.length(), md5_sig);
+ // convert result to a string
+ MD5SigToString(md5_sig, sigStr.rawData(), 33);
+
+ // already queued files are processed again in case the output format has changed
+
+ if (!checkMd5Signature(absBaseName(), sigStr) &&
+ checkDeliverables(absImgName(),
+ m_graphFormat == GOF_BITMAP && m_generateImageMap ? absMapName() : QCString()
+ )
+ )
+ {
+ // all needed files are there
+ removeDotGraph(absDotName());
+ return FALSE;
+ }
+
+ // need to rebuild the image
+
+ // write .dot file because image was new or has changed
+ QFile f(absDotName());
+ if (!f.open(IO_WriteOnly))
+ {
+ err("Could not open file %s for writing\n",f.name().data());
+ return TRUE;
+ }
+ FTextStream t(&f);
+ t << m_theGraph;
+ f.close();
+
+ if (m_graphFormat == GOF_BITMAP)
+ {
+ // run dot to create a bitmap image
+ DotRunner * dotRun = DotManager::instance()->createRunner(absDotName(), sigStr);
+ dotRun->addJob(Config_getEnum(DOT_IMAGE_FORMAT), absImgName());
+ if (m_generateImageMap) dotRun->addJob(MAP_CMD, absMapName());
+ }
+ else if (m_graphFormat == GOF_EPS)
+ {
+ // run dot to create a .eps image
+ DotRunner *dotRun = DotManager::instance()->createRunner(absDotName(), sigStr);
+ if (Config_getBool(USE_PDFLATEX))
+ {
+ dotRun->addJob("pdf",absImgName());
+ }
+ else
+ {
+ dotRun->addJob("ps",absImgName());
+ }
+ }
+ return TRUE;
+}
+
+void DotGraph::generateCode(FTextStream &t)
+{
+ if (m_graphFormat==GOF_BITMAP && m_textFormat==EOF_DocBook)
+ {
+ t << "<para>" << endl;
+ t << " <informalfigure>" << endl;
+ t << " <mediaobject>" << endl;
+ t << " <imageobject>" << endl;
+ t << " <imagedata";
+ t << " width=\"50%\" align=\"center\" valign=\"middle\" scalefit=\"0\" fileref=\"" << m_relPath << m_baseName << "." << IMG_EXT << "\">";
+ t << "</imagedata>" << endl;
+ t << " </imageobject>" << endl;
+ t << " </mediaobject>" << endl;
+ t << " </informalfigure>" << endl;
+ t << "</para>" << endl;
+ }
+ else if (m_graphFormat==GOF_BITMAP && m_generateImageMap) // produce HTML to include the image
+ {
+ if (IMG_EXT=="svg") // add link to SVG file without map file
+ {
+ if (!m_noDivTag) t << "<div class=\"center\">";
+ if (m_regenerate || !writeSVGFigureLink(t,m_relPath,m_baseName,absImgName())) // need to patch the links in the generated SVG file
+ {
+ if (m_regenerate)
+ {
+ DotManager::instance()->addSVGConversion(absImgName(),m_relPath,FALSE,QCString(),m_zoomable,m_graphId);
+ }
+ int mapId = DotManager::instance()->addSVGObject(m_fileName,m_baseName,absImgName(),m_relPath);
+ t << "<!-- SVG " << mapId << " -->" << endl;
+ }
+ if (!m_noDivTag) t << "</div>" << endl;
+ }
+ else // add link to bitmap file with image map
+ {
+ if (!m_noDivTag) t << "<div class=\"center\">";
+ t << "<img src=\"" << relImgName() << "\" border=\"0\" usemap=\"#" << getMapLabel() << "\" alt=\"" << getImgAltText() << "\"/>";
+ if (!m_noDivTag) t << "</div>";
+ t << endl;
+ if (m_regenerate || !insertMapFile(t, absMapName(), m_relPath, getMapLabel()))
+ {
+ int mapId = DotManager::instance()->addMap(m_fileName, absMapName(), m_relPath, m_urlOnly, QCString(), getMapLabel());
+ t << "<!-- MAP " << mapId << " -->" << endl;
+ }
+ }
+ }
+ else if (m_graphFormat==GOF_EPS) // produce tex to include the .eps image
+ {
+ if (m_regenerate || !writeVecGfxFigure(t,m_baseName,absBaseName()))
+ {
+ int figId = DotManager::instance()->addFigure(m_fileName,m_baseName,absBaseName(),FALSE /*TRUE*/);
+ t << endl << "% FIG " << figId << endl;
+ }
+ }
+}
+
+void DotGraph::writeGraphHeader(FTextStream &t,const QCString &title)
+{
+ t << "digraph ";
+ if (title.isEmpty())
+ {
+ t << "\"Dot Graph\"";
+ }
+ else
+ {
+ t << "\"" << convertToXML(title) << "\"";
+ }
+ t << endl << "{" << endl;
+ if (Config_getBool(INTERACTIVE_SVG)) // insert a comment to force regeneration when this
+ // option is toggled
+ {
+ t << " // INTERACTIVE_SVG=YES\n";
+ }
+ t << " // LATEX_PDF_SIZE\n"; // write placeholder for LaTeX PDF bounding box size repacement
+ if (Config_getBool(DOT_TRANSPARENT))
+ {
+ t << " bgcolor=\"transparent\";" << endl;
+ }
+ t << " edge [fontname=\"" << DOT_FONTNAME << "\","
+ "fontsize=\"" << DOT_FONTSIZE << "\","
+ "labelfontname=\"" << DOT_FONTNAME << "\","
+ "labelfontsize=\"" << DOT_FONTSIZE << "\"];\n";
+ t << " node [fontname=\"" << DOT_FONTNAME << "\","
+ "fontsize=\"" << DOT_FONTSIZE << "\",shape=record];\n";
+}
+
+void DotGraph::writeGraphFooter(FTextStream &t)
+{
+ t << "}" << endl;
+}
+
+void DotGraph::computeGraph(DotNode *root,
+ GraphType gt,
+ GraphOutputFormat format,
+ const QCString &rank, // either "LR", "RL", or ""
+ bool renderParents,
+ bool backArrows,
+ const QCString &title,
+ QGString &graphStr)
+{
+ //printf("computeMd5Signature\n");
+ QGString buf;
+ FTextStream md5stream(&buf);
+ writeGraphHeader(md5stream,title);
+ if (!rank.isEmpty())
+ {
+ md5stream << " rankdir=\"" << rank << "\";" << endl;
+ }
+ root->clearWriteFlag();
+ root->write(md5stream, gt, format, gt!=CallGraph && gt!=Dependency, TRUE, backArrows);
+ if (renderParents && root->parents())
+ {
+ QListIterator<DotNode> dnli(*root->parents());
+ const DotNode *pn;
+ for (dnli.toFirst();(pn=dnli.current());++dnli)
+ {
+ if (pn->isVisible())
+ {
+ root->writeArrow(md5stream, // stream
+ gt, // graph type
+ format, // output format
+ pn, // child node
+ pn->edgeInfo()->at(pn->children()->findRef(root)), // edge info
+ FALSE, // topDown?
+ backArrows // point back?
+ );
+ }
+ pn->write(md5stream, // stream
+ gt, // graph type
+ format, // output format
+ TRUE, // topDown?
+ FALSE, // toChildren?
+ backArrows // backward pointing arrows?
+ );
+ }
+ }
+ writeGraphFooter(md5stream);
+
+ graphStr=buf.data();
+}
+
+bool DotGraph::writeVecGfxFigure(FTextStream &out,const QCString &baseName,
+ const QCString &figureName)
+{
+ int width=400,height=550;
+ if (Config_getBool(USE_PDFLATEX))
+ {
+ if (!DotRunner::readBoundingBox(figureName+".pdf",&width,&height,FALSE))
+ {
+ //printf("writeVecGfxFigure()=0\n");
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (!DotRunner::readBoundingBox(figureName+".eps",&width,&height,TRUE))
+ {
+ //printf("writeVecGfxFigure()=0\n");
+ return FALSE;
+ }
+ }
+ //printf("Got PDF/EPS size %d,%d\n",width,height);
+ int maxWidth = 350; /* approx. page width in points, excl. margins */
+ int maxHeight = 550; /* approx. page height in points, excl. margins */
+ out << "\\nopagebreak\n"
+ "\\begin{figure}[H]\n"
+ "\\begin{center}\n"
+ "\\leavevmode\n";
+ if (width>maxWidth || height>maxHeight) // figure too big for page
+ {
+ // c*width/maxWidth > c*height/maxHeight, where c=maxWidth*maxHeight>0
+ if (width*maxHeight>height*maxWidth)
+ {
+ out << "\\includegraphics[width=" << maxWidth << "pt]";
+ }
+ else
+ {
+ out << "\\includegraphics[height=" << maxHeight << "pt]";
+ }
+ }
+ else
+ {
+ out << "\\includegraphics[width=" << width << "pt]";
+ }
+
+ out << "{" << baseName << "}\n"
+ "\\end{center}\n"
+ "\\end{figure}\n";
+
+ //printf("writeVecGfxFigure()=1\n");
+ return TRUE;
+}
diff --git a/src/dotgraph.h b/src/dotgraph.h
new file mode 100644
index 0000000..27d6938
--- /dev/null
+++ b/src/dotgraph.h
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * Copyright (C) 1997-2019 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 DOTGRAPH_H
+#define DOTGRAPH_H
+
+#include <qcstring.h>
+#include <qgstring.h>
+#include <qdir.h>
+
+class FTextStream;
+class DotNode;
+
+enum GraphOutputFormat { GOF_BITMAP, GOF_EPS };
+enum EmbeddedOutputFormat { EOF_Html, EOF_LaTeX, EOF_Rtf, EOF_DocBook };
+enum GraphType { Dependency, Inheritance, Collaboration, Hierarchy, CallGraph };
+
+/** A dot graph */
+class DotGraph
+{
+ public:
+ DotGraph() : m_curNodeNumber(0), m_doNotAddImageToIndex(FALSE), m_noDivTag(FALSE), m_zoomable(TRUE), m_urlOnly(FALSE) {}
+ virtual ~DotGraph() {}
+
+ static QCString DOT_FONTNAME; // will be initialized in initDot
+ static int DOT_FONTSIZE; // will be initialized in initDot
+
+ static bool writeVecGfxFigure(FTextStream& out, const QCString& baseName, const QCString& figureName);
+
+ protected:
+ /** returns node numbers. The Counter is reset by the constructor */
+ int getNextNodeNumber() { return ++m_curNodeNumber; }
+
+ QCString writeGraph(FTextStream &t,
+ GraphOutputFormat gf,
+ EmbeddedOutputFormat ef,
+ const char *path,
+ const char *fileName,
+ const char *relPath,
+ bool writeImageMap=TRUE,
+ int graphId=-1
+ );
+
+ static void writeGraphHeader(FTextStream& t, const QCString& title = QCString());
+ static void writeGraphFooter(FTextStream& t);
+ static void computeGraph(DotNode* root,
+ GraphType gt,
+ GraphOutputFormat format,
+ const QCString& rank, // either "LR", "RL", or ""
+ bool renderParents,
+ bool backArrows,
+ const QCString& title,
+ QGString& graphStr
+ );
+
+ virtual QCString getBaseName() const = 0;
+ virtual QCString absMapName() const { return m_absPath + m_baseName + ".map"; }
+ virtual QCString getMapLabel() const = 0;
+ virtual QCString getImgAltText() const { return ""; }
+
+ virtual void computeTheGraph() = 0;
+
+ static QCString IMG_EXT;
+
+ friend void initDot();
+
+ QCString absBaseName() const { return m_absPath + m_baseName; }
+ QCString absDotName() const { return m_absPath + m_baseName + ".dot"; }
+ QCString imgName() const;
+ QCString absImgName() const { return m_absPath + imgName(); }
+ QCString relImgName() const { return m_relPath + imgName(); }
+
+ // the following variables are used while writing the graph to a .dot file
+ GraphOutputFormat m_graphFormat;
+ EmbeddedOutputFormat m_textFormat;
+ QDir m_dir;
+ QCString m_fileName;
+ QCString m_relPath;
+ bool m_generateImageMap;
+ int m_graphId;
+
+ QCString m_absPath;
+ QCString m_baseName;
+ QGString m_theGraph;
+ bool m_regenerate;
+ bool m_doNotAddImageToIndex;
+ bool m_noDivTag;
+ bool m_zoomable;
+ bool m_urlOnly;
+
+ private:
+ DotGraph(const DotGraph &);
+ DotGraph &operator=(const DotGraph &);
+
+ bool prepareDotFile();
+ void generateCode(FTextStream &t);
+
+ int m_curNodeNumber;
+};
+
+#endif
diff --git a/src/dotgroupcollaboration.cpp b/src/dotgroupcollaboration.cpp
new file mode 100644
index 0000000..be55ac0
--- /dev/null
+++ b/src/dotgroupcollaboration.cpp
@@ -0,0 +1,381 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotgroupcollaboration.h"
+
+#include "dotnode.h"
+#include "classlist.h"
+#include "doxygen.h"
+#include "namespacedef.h"
+#include "pagedef.h"
+#include "util.h"
+#include "config.h"
+
+#define DOT_TRANSPARENT Config_getBool(DOT_TRANSPARENT)
+
+DotGroupCollaboration::DotGroupCollaboration(const GroupDef* gd)
+{
+ QCString tmp_url = gd->getReference()+"$"+gd->getOutputFileBase();
+ m_usedNodes = new QDict<DotNode>(1009);
+ QCString tooltip = gd->briefDescriptionAsTooltip();
+ m_rootNode = new DotNode(getNextNodeNumber(), gd->groupTitle(), tooltip, tmp_url, TRUE );
+ m_rootNode->markAsVisible();
+ m_usedNodes->insert(gd->name(), m_rootNode );
+ m_edges.setAutoDelete(TRUE);
+
+ m_diskName = gd->getOutputFileBase();
+
+ buildGraph( gd );
+}
+
+DotGroupCollaboration::~DotGroupCollaboration()
+{
+ delete m_usedNodes;
+}
+
+void DotGroupCollaboration::buildGraph(const GroupDef* gd)
+{
+ QCString tmp_url;
+ //===========================
+ // hierarchy.
+
+ // Write parents
+ const GroupList *groups = gd->partOfGroups();
+ if ( groups )
+ {
+ GroupListIterator gli(*groups);
+ const GroupDef *d;
+ for (gli.toFirst();(d=gli.current());++gli)
+ {
+ DotNode* nnode = m_usedNodes->find(d->name());
+ if ( !nnode )
+ { // add node
+ tmp_url = d->getReference()+"$"+d->getOutputFileBase();
+ QCString tooltip = d->briefDescriptionAsTooltip();
+ nnode = new DotNode(getNextNodeNumber(), d->groupTitle(), tooltip, tmp_url );
+ nnode->markAsVisible();
+ m_usedNodes->insert(d->name(), nnode );
+ }
+ tmp_url = "";
+ addEdge( nnode, m_rootNode, DotGroupCollaboration::thierarchy, tmp_url, tmp_url );
+ }
+ }
+
+ // Add subgroups
+ if ( gd->getSubGroups() && gd->getSubGroups()->count() )
+ {
+ QListIterator<GroupDef> defli(*gd->getSubGroups());
+ const GroupDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ DotNode* nnode = m_usedNodes->find(def->name());
+ if ( !nnode )
+ { // add node
+ tmp_url = def->getReference()+"$"+def->getOutputFileBase();
+ QCString tooltip = def->briefDescriptionAsTooltip();
+ nnode = new DotNode(getNextNodeNumber(), def->groupTitle(), tooltip, tmp_url );
+ nnode->markAsVisible();
+ m_usedNodes->insert(def->name(), nnode );
+ }
+ tmp_url = "";
+ addEdge( m_rootNode, nnode, DotGroupCollaboration::thierarchy, tmp_url, tmp_url );
+ }
+ }
+
+ //=======================
+ // Write collaboration
+
+ // Add members
+ addMemberList( gd->getMemberList(MemberListType_allMembersList) );
+
+ // Add classes
+ if ( gd->getClasses() && gd->getClasses()->count() )
+ {
+ ClassSDict::Iterator defli(*gd->getClasses());
+ ClassDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
+ if (!def->anchor().isEmpty())
+ {
+ tmp_url+="#"+def->anchor();
+ }
+ addCollaborationMember( def, tmp_url, DotGroupCollaboration::tclass );
+ }
+ }
+
+ // Add namespaces
+ if ( gd->getNamespaces() && gd->getNamespaces()->count() )
+ {
+ NamespaceSDict::Iterator defli(*gd->getNamespaces());
+ NamespaceDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
+ addCollaborationMember( def, tmp_url, DotGroupCollaboration::tnamespace );
+ }
+ }
+
+ // Add files
+ if ( gd->getFiles() && gd->getFiles()->count() )
+ {
+ QListIterator<FileDef> defli(*gd->getFiles());
+ const FileDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
+ addCollaborationMember( def, tmp_url, DotGroupCollaboration::tfile );
+ }
+ }
+
+ // Add pages
+ if ( gd->getPages() && gd->getPages()->count() )
+ {
+ PageSDict::Iterator defli(*gd->getPages());
+ PageDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
+ addCollaborationMember( def, tmp_url, DotGroupCollaboration::tpages );
+ }
+ }
+
+ // Add directories
+ if ( gd->getDirs() && gd->getDirs()->count() )
+ {
+ QListIterator<DirDef> defli(*gd->getDirs());
+ const DirDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension;
+ addCollaborationMember( def, tmp_url, DotGroupCollaboration::tdir );
+ }
+ }
+}
+
+void DotGroupCollaboration::addMemberList( MemberList* ml )
+{
+ if ( !( ml && ml->count()) ) return;
+ MemberListIterator defli(*ml);
+ MemberDef *def;
+ for (;(def=defli.current());++defli)
+ {
+ QCString tmp_url = def->getReference()+"$"+def->getOutputFileBase()+Doxygen::htmlFileExtension
+ +"#"+def->anchor();
+ addCollaborationMember( def, tmp_url, DotGroupCollaboration::tmember );
+ }
+}
+
+DotGroupCollaboration::Edge* DotGroupCollaboration::addEdge(
+ DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType,
+ const QCString& _label, const QCString& _url )
+{
+ // search a existing link.
+ QListIterator<Edge> lli(m_edges);
+ Edge* newEdge = 0;
+ for ( lli.toFirst(); (newEdge=lli.current()); ++lli)
+ {
+ if ( newEdge->pNStart==_pNStart &&
+ newEdge->pNEnd==_pNEnd &&
+ newEdge->eType==_eType
+ )
+ { // edge already found
+ break;
+ }
+ }
+ if ( newEdge==0 ) // new link
+ {
+ newEdge = new Edge(_pNStart,_pNEnd,_eType);
+ m_edges.append( newEdge );
+ }
+
+ if (!_label.isEmpty())
+ {
+ newEdge->links.append(new Link(_label,_url));
+ }
+
+ return newEdge;
+}
+
+void DotGroupCollaboration::addCollaborationMember(
+ const Definition* def, QCString& url, EdgeType eType )
+{
+ // Create group nodes
+ if ( !def->partOfGroups() )
+ return;
+ GroupListIterator gli(*def->partOfGroups());
+ GroupDef *d;
+ QCString tmp_str;
+ for (;(d=gli.current());++gli)
+ {
+ DotNode* nnode = m_usedNodes->find(d->name());
+ if ( nnode != m_rootNode )
+ {
+ if ( nnode==0 )
+ { // add node
+ tmp_str = d->getReference()+"$"+d->getOutputFileBase();
+ QCString tooltip = d->briefDescriptionAsTooltip();
+ nnode = new DotNode(getNextNodeNumber(), d->groupTitle(), tooltip, tmp_str );
+ nnode->markAsVisible();
+ m_usedNodes->insert(d->name(), nnode );
+ }
+ tmp_str = def->qualifiedName();
+ addEdge( m_rootNode, nnode, eType, tmp_str, url );
+ }
+ }
+}
+
+QCString DotGroupCollaboration::getBaseName() const
+{
+ return m_diskName;
+}
+
+void DotGroupCollaboration::computeTheGraph()
+{
+ FTextStream md5stream(&m_theGraph);
+ writeGraphHeader(md5stream,m_rootNode->label());
+
+ // clean write flags
+ QDictIterator<DotNode> dni(*m_usedNodes);
+ DotNode *pn;
+ for (dni.toFirst();(pn=dni.current());++dni)
+ {
+ pn->clearWriteFlag();
+ }
+
+ // write other nodes.
+ for (dni.toFirst();(pn=dni.current());++dni)
+ {
+ pn->write(md5stream,Inheritance,m_graphFormat,TRUE,FALSE,FALSE);
+ }
+
+ // write edges
+ QListIterator<Edge> eli(m_edges);
+ Edge* edge;
+ for (eli.toFirst();(edge=eli.current());++eli)
+ {
+ edge->write( md5stream );
+ }
+
+ writeGraphFooter(md5stream);
+
+}
+
+QCString DotGroupCollaboration::getMapLabel() const
+{
+ return escapeCharsInString(m_baseName, FALSE);
+}
+
+QCString DotGroupCollaboration::writeGraph( FTextStream &t,
+ GraphOutputFormat graphFormat, EmbeddedOutputFormat textFormat,
+ const char *path, const char *fileName, const char *relPath,
+ bool generateImageMap,int graphId)
+{
+ m_doNotAddImageToIndex = TRUE;
+
+ return DotGraph::writeGraph(t, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
+}
+
+void DotGroupCollaboration::Edge::write( FTextStream &t ) const
+{
+ const char* linkTypeColor[] = {
+ "darkorchid3"
+ ,"orange"
+ ,"blueviolet"
+ ,"darkgreen"
+ ,"firebrick4"
+ ,"grey75"
+ ,"midnightblue"
+ };
+ QCString arrowStyle = "dir=\"none\", style=\"dashed\"";
+ t << " Node" << pNStart->number();
+ t << "->";
+ t << "Node" << pNEnd->number();
+
+ t << " [shape=plaintext";
+ if (links.count()>0) // there are links
+ {
+ t << ", ";
+ // HTML-like edge labels crash on my Mac with Graphviz 2.0! and
+ // are not supported by older version of dot.
+ //
+ //t << label=<<TABLE BORDER=\"0\" CELLBORDER=\"0\">";
+ //QListIterator<Link> lli(links);
+ //Link *link;
+ //for( lli.toFirst(); (link=lli.current()); ++lli)
+ //{
+ // t << "<TR><TD";
+ // if ( !link->url.isEmpty() )
+ // t << " HREF=\"" << link->url << "\"";
+ // t << ">" << link->label << "</TD></TR>";
+ //}
+ //t << "</TABLE>>";
+
+ t << "label=\"";
+ QListIterator<Link> lli(links);
+ Link *link;
+ bool first=TRUE;
+ int count=0;
+ const int maxLabels = 10;
+ for( lli.toFirst(); (link=lli.current()) && count<maxLabels; ++lli,++count)
+ {
+ if (first) first=FALSE; else t << "\\n";
+ t << DotNode::convertLabel(link->label);
+ }
+ if (count==maxLabels) t << "\\n...";
+ t << "\"";
+
+ }
+ switch( eType )
+ {
+ case thierarchy:
+ arrowStyle = "dir=\"back\", style=\"solid\"";
+ break;
+ default:
+ t << ", color=\"" << linkTypeColor[(int)eType] << "\"";
+ break;
+ }
+ t << ", " << arrowStyle;
+ t << "];" << endl;
+}
+
+bool DotGroupCollaboration::isTrivial() const
+{
+ return m_usedNodes->count() <= 1;
+}
+
+void DotGroupCollaboration::writeGraphHeader(FTextStream &t,
+ const QCString &title) const
+{
+ t << "digraph ";
+ if (title.isEmpty())
+ {
+ t << "\"Dot Graph\"";
+ }
+ else
+ {
+ t << "\"" << convertToXML(title) << "\"";
+ }
+ t << endl;
+ t << "{" << endl;
+ if (DOT_TRANSPARENT)
+ {
+ t << " bgcolor=\"transparent\";" << endl;
+ }
+ t << " edge [fontname=\"" << DOT_FONTNAME << "\",fontsize=\"" << DOT_FONTSIZE << "\","
+ "labelfontname=\"" << DOT_FONTNAME << "\",labelfontsize=\"" << DOT_FONTSIZE << "\"];\n";
+ t << " node [fontname=\"" << DOT_FONTNAME << "\",fontsize=\"" << DOT_FONTSIZE << "\",shape=box];\n";
+ t << " rankdir=LR;\n";
+}
diff --git a/src/dotgroupcollaboration.h b/src/dotgroupcollaboration.h
new file mode 100644
index 0000000..539637f
--- /dev/null
+++ b/src/dotgroupcollaboration.h
@@ -0,0 +1,85 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTGROUPCOLLABORATION_H
+#define DOTGROUPCOLLABORATION_H
+
+#include "dotgraph.h"
+#include "qlist.h"
+#include "groupdef.h"
+
+/** Representation of a group collaboration graph */
+class DotGroupCollaboration : public DotGraph
+{
+ public :
+ DotGroupCollaboration(const GroupDef* gd);
+ ~DotGroupCollaboration();
+ QCString writeGraph(FTextStream &t, GraphOutputFormat gf,EmbeddedOutputFormat ef,
+ const char *path,const char *fileName,const char *relPath,
+ bool writeImageMap=TRUE,int graphId=-1);
+ bool isTrivial() const;
+
+ protected:
+ virtual QCString getBaseName() const;
+ virtual QCString getMapLabel() const;
+ virtual void computeTheGraph();
+
+ private :
+ enum EdgeType
+ {
+ tmember = 0,
+ tclass,
+ tnamespace,
+ tfile,
+ tpages,
+ tdir,
+ thierarchy
+ };
+
+ struct Link
+ {
+ Link(const QCString lab,const QCString &u) : label(lab), url(u) {}
+ QCString label;
+ QCString url;
+ };
+
+ struct Edge
+ {
+ Edge(DotNode *start,DotNode *end,EdgeType type)
+ : pNStart(start), pNEnd(end), eType(type)
+ { links.setAutoDelete(TRUE); }
+
+ DotNode* pNStart;
+ DotNode* pNEnd;
+ EdgeType eType;
+
+ QList<Link> links;
+ void write( FTextStream &t ) const;
+ };
+
+ void buildGraph(const GroupDef* gd);
+ void addCollaborationMember(const Definition* def, QCString& url, EdgeType eType );
+ void addMemberList( class MemberList* ml );
+ void writeGraphHeader(FTextStream &t,const QCString &title) const;
+ Edge* addEdge( DotNode* _pNStart, DotNode* _pNEnd, EdgeType _eType,
+ const QCString& _label, const QCString& _url );
+
+ DotNode *m_rootNode;
+ QDict<DotNode> *m_usedNodes;
+ QCString m_diskName;
+ QList<Edge> m_edges;
+};
+
+#endif
diff --git a/src/dotincldepgraph.cpp b/src/dotincldepgraph.cpp
new file mode 100644
index 0000000..23588db
--- /dev/null
+++ b/src/dotincldepgraph.cpp
@@ -0,0 +1,238 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotincldepgraph.h"
+#include "dotnode.h"
+#include "util.h"
+#include "config.h"
+
+void DotInclDepGraph::buildGraph(DotNode *n,const FileDef *fd,int distance)
+{
+ QList<IncludeInfo> *includeFiles = m_inverse ? fd->includedByFileList() : fd->includeFileList();
+ if (includeFiles)
+ {
+ QListIterator<IncludeInfo> ili(*includeFiles);
+ IncludeInfo *ii;
+ for (;(ii=ili.current());++ili)
+ {
+ const FileDef *bfd = ii->fileDef;
+ QCString in = ii->includeName;
+ //printf(">>>> in='%s' bfd=%p\n",ii->includeName.data(),bfd);
+ bool doc=TRUE,src=FALSE;
+ if (bfd)
+ {
+ in = bfd->absFilePath();
+ doc = bfd->isLinkable() && !bfd->isHidden();
+ src = bfd->generateSourceFile();
+ }
+ if (doc || src || !Config_getBool(HIDE_UNDOC_RELATIONS))
+ {
+ QCString url="";
+ if (bfd) url=bfd->getOutputFileBase().copy();
+ if (!doc && src)
+ {
+ url=bfd->getSourceFileBase();
+ }
+ DotNode *bn = m_usedNodes->find(in);
+ if (bn) // file is already a node in the graph
+ {
+ n->addChild(bn,0,0,0);
+ bn->addParent(n);
+ bn->setDistance(distance);
+ }
+ else
+ {
+ QCString tmp_url;
+ QCString tooltip;
+ if (bfd)
+ {
+ tmp_url=doc || src ? bfd->getReference()+"$"+url : QCString();
+ tooltip = bfd->briefDescriptionAsTooltip();
+ }
+ bn = new DotNode(getNextNodeNumber(),// n
+ ii->includeName, // label
+ tooltip, // tip
+ tmp_url, // url
+ FALSE, // rootNode
+ 0); // cd
+ n->addChild(bn,0,0,0);
+ bn->addParent(n);
+ m_usedNodes->insert(in,bn);
+ bn->setDistance(distance);
+
+ if (bfd) buildGraph(bn,bfd,distance+1);
+ }
+ }
+ }
+ }
+}
+
+void DotInclDepGraph::determineVisibleNodes(QList<DotNode> &queue, int &maxNodes)
+{
+ while (queue.count()>0 && maxNodes>0)
+ {
+ DotNode *n = queue.take(0);
+ if (!n->isVisible() && n->distance()<=Config_getInt(MAX_DOT_GRAPH_DEPTH)) // not yet processed
+ {
+ n->markAsVisible();
+ maxNodes--;
+ // add direct children
+ if (n->children())
+ {
+ QListIterator<DotNode> li(*n->children());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ queue.append(dn);
+ }
+ }
+ }
+ }
+}
+
+void DotInclDepGraph::determineTruncatedNodes(QList<DotNode> &queue)
+{
+ while (queue.count()>0)
+ {
+ DotNode *n = queue.take(0);
+ if (n->isVisible() && n->isTruncated()==DotNode::Unknown)
+ {
+ bool truncated = FALSE;
+ if (n->children())
+ {
+ QListIterator<DotNode> li(*n->children());
+ const DotNode *dn;
+ for (li.toFirst();(dn=li.current());++li)
+ {
+ if (!dn->isVisible())
+ {
+ truncated = TRUE;
+ }
+ else
+ {
+ queue.append(dn);
+ }
+ }
+ }
+ n->markAsTruncated(truncated);
+ }
+ }
+}
+
+DotInclDepGraph::DotInclDepGraph(const FileDef *fd,bool inverse)
+{
+ m_inverse = inverse;
+ ASSERT(fd!=0);
+ m_inclDepFileName = fd->includeDependencyGraphFileName();
+ m_inclByDepFileName = fd->includedByDependencyGraphFileName();
+ QCString tmp_url=fd->getReference()+"$"+fd->getOutputFileBase();
+ QCString tooltip = fd->briefDescriptionAsTooltip();
+ m_startNode = new DotNode(getNextNodeNumber(),
+ fd->docName(),
+ tooltip,
+ tmp_url.data(),
+ TRUE); // root node
+ m_startNode->setDistance(0);
+ m_usedNodes = new QDict<DotNode>(1009);
+ m_usedNodes->insert(fd->absFilePath(),m_startNode);
+ buildGraph(m_startNode,fd,1);
+
+ int maxNodes = Config_getInt(DOT_GRAPH_MAX_NODES);
+ QList<DotNode> openNodeQueue;
+ openNodeQueue.append(m_startNode);
+ determineVisibleNodes(openNodeQueue,maxNodes);
+ openNodeQueue.clear();
+ openNodeQueue.append(m_startNode);
+ determineTruncatedNodes(openNodeQueue);
+}
+
+DotInclDepGraph::~DotInclDepGraph()
+{
+ DotNode::deleteNodes(m_startNode);
+ delete m_usedNodes;
+}
+
+QCString DotInclDepGraph::getBaseName() const
+{
+ if (m_inverse)
+ {
+ return m_inclByDepFileName;
+ }
+ else
+ {
+ return m_inclDepFileName;
+ }
+}
+
+void DotInclDepGraph::computeTheGraph()
+{
+ computeGraph(m_startNode, Dependency, m_graphFormat, "", FALSE,
+ m_inverse, m_startNode->label(), m_theGraph);
+}
+
+QCString DotInclDepGraph::getMapLabel() const
+{
+ if (m_inverse)
+ {
+ return escapeCharsInString(m_startNode->label(),FALSE) + "dep";
+ }
+ else
+ {
+ return escapeCharsInString(m_startNode->label(),FALSE);
+ }
+}
+
+QCString DotInclDepGraph::writeGraph(FTextStream &out,
+ GraphOutputFormat graphFormat,
+ EmbeddedOutputFormat textFormat,
+ const char *path,
+ const char *fileName,
+ const char *relPath,
+ bool generateImageMap,
+ int graphId)
+{
+ return DotGraph::writeGraph(out, graphFormat, textFormat, path, fileName, relPath, generateImageMap, graphId);
+}
+
+bool DotInclDepGraph::isTrivial() const
+{
+ return m_startNode->children()==0;
+}
+
+bool DotInclDepGraph::isTooBig() const
+{
+ int numNodes = m_startNode->children() ? m_startNode->children()->count() : 0;
+ return numNodes>=Config_getInt(DOT_GRAPH_MAX_NODES);
+}
+
+void DotInclDepGraph::writeXML(FTextStream &t)
+{
+ QDictIterator<DotNode> dni(*m_usedNodes);
+ DotNode *node;
+ for (;(node=dni.current());++dni)
+ {
+ node->writeXML(t,FALSE);
+ }
+}
+
+void DotInclDepGraph::writeDocbook(FTextStream &t)
+{
+ QDictIterator<DotNode> dni(*m_usedNodes);
+ DotNode *node;
+ for (;(node=dni.current());++dni)
+ {
+ node->writeDocbook(t,FALSE);
+ }
+}
diff --git a/src/dotincldepgraph.h b/src/dotincldepgraph.h
new file mode 100644
index 0000000..b664ccb
--- /dev/null
+++ b/src/dotincldepgraph.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTINCLDEPGRAPH_H
+#define DOTINCLDEPGRAPH_H
+
+#include "qcstring.h"
+#include "filedef.h"
+
+#include "dotgraph.h"
+
+/** Representation of an include dependency graph */
+class DotInclDepGraph : public DotGraph
+{
+ public:
+ DotInclDepGraph(const FileDef *fd,bool inverse);
+ ~DotInclDepGraph();
+ QCString writeGraph(FTextStream &t, GraphOutputFormat gf, EmbeddedOutputFormat ef,
+ const char *path,const char *fileName,const char *relPath,
+ bool writeImageMap=TRUE,int graphId=-1);
+ bool isTrivial() const;
+ bool isTooBig() const;
+ void writeXML(FTextStream &t);
+ void writeDocbook(FTextStream &t);
+
+ protected:
+ virtual QCString getBaseName() const;
+ virtual QCString getMapLabel() const;
+ virtual void computeTheGraph();
+
+ private:
+ QCString diskName() const;
+ void buildGraph(DotNode *n,const FileDef *fd,int distance);
+ void determineVisibleNodes(QList<DotNode> &queue,int &maxNodes);
+ void determineTruncatedNodes(QList<DotNode> &queue);
+
+ DotNode *m_startNode;
+ QDict<DotNode> *m_usedNodes;
+ QCString m_inclDepFileName;
+ QCString m_inclByDepFileName;
+ bool m_inverse;
+};
+
+#endif
diff --git a/src/dotnode.cpp b/src/dotnode.cpp
new file mode 100644
index 0000000..ae06fb2
--- /dev/null
+++ b/src/dotnode.cpp
@@ -0,0 +1,950 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotnode.h"
+
+#include "ftextstream.h"
+#include "classdef.h"
+#include "config.h"
+#include "memberlist.h"
+#include "membergroup.h"
+#include "language.h"
+#include "doxygen.h"
+#include "util.h"
+
+/** Helper struct holding the properties of a edge in a dot graph. */
+struct EdgeProperties
+{
+ const char * const *edgeColorMap;
+ const char * const *arrowStyleMap;
+ const char * const *edgeStyleMap;
+};
+
+/*! mapping from protection levels to color names */
+static const char *normalEdgeColorMap[] =
+{
+ "midnightblue", // Public
+ "darkgreen", // Protected
+ "firebrick4", // Private
+ "darkorchid3", // "use" relation
+ "grey75", // Undocumented
+ "orange", // template relation
+ "orange" // type constraint
+};
+
+static const char *normalArrowStyleMap[] =
+{
+ "empty", // Public
+ "empty", // Protected
+ "empty", // Private
+ "open", // "use" relation
+ 0, // Undocumented
+ 0 // template relation
+};
+
+static const char *normalEdgeStyleMap[] =
+{
+ "solid", // inheritance
+ "dashed" // usage
+};
+
+static const char *umlEdgeColorMap[] =
+{
+ "midnightblue", // Public
+ "darkgreen", // Protected
+ "firebrick4", // Private
+ "grey25", // "use" relation
+ "grey75", // Undocumented
+ "orange", // template relation
+ "orange" // type constraint
+};
+
+static const char *umlArrowStyleMap[] =
+{
+ "onormal", // Public
+ "onormal", // Protected
+ "onormal", // Private
+ "odiamond", // "use" relation
+ 0, // Undocumented
+ 0 // template relation
+};
+
+static const char *umlEdgeStyleMap[] =
+{
+ "solid", // inheritance
+ "solid" // usage
+};
+
+static EdgeProperties normalEdgeProps =
+{
+ normalEdgeColorMap, normalArrowStyleMap, normalEdgeStyleMap
+};
+
+static EdgeProperties umlEdgeProps =
+{
+ umlEdgeColorMap, umlArrowStyleMap, umlEdgeStyleMap
+};
+
+static QCString escapeTooltip(const QCString &tooltip)
+{
+ QCString result;
+ const char *p=tooltip.data();
+ if (p==0) return result;
+ char c;
+ while ((c=*p++))
+ {
+ switch(c)
+ {
+ case '"': result+="\\\""; break;
+ case '\\': result+="\\\\"; break;
+ default: result+=c; break;
+ }
+ }
+ return result;
+}
+
+static void writeBoxMemberList(FTextStream &t,
+ char prot,MemberList *ml,const ClassDef *scope,
+ bool isStatic=FALSE,const QDict<void> *skipNames=0)
+{
+ (void)isStatic;
+ if (ml)
+ {
+ MemberListIterator mlia(*ml);
+ MemberDef *mma;
+ int totalCount=0;
+ for (mlia.toFirst();(mma = mlia.current());++mlia)
+ {
+ if (mma->getClassDef()==scope &&
+ (skipNames==0 || skipNames->find(mma->name())==0))
+ {
+ totalCount++;
+ }
+ }
+
+ int count=0;
+ for (mlia.toFirst();(mma = mlia.current());++mlia)
+ {
+ if (mma->getClassDef() == scope &&
+ (skipNames==0 || skipNames->find(mma->name())==0))
+ {
+ int numFields = Config_getInt(UML_LIMIT_NUM_FIELDS);
+ if (numFields>0 && (totalCount>numFields*3/2 && count>=numFields))
+ {
+ t << theTranslator->trAndMore(QCString().sprintf("%d",totalCount-count)) << "\\l";
+ break;
+ }
+ else
+ {
+ t << prot << " ";
+ t << DotNode::convertLabel(mma->name());
+ if (!mma->isObjCMethod() &&
+ (mma->isFunction() || mma->isSlot() || mma->isSignal())) t << "()";
+ t << "\\l";
+ count++;
+ }
+ }
+ }
+ // write member groups within the memberlist
+ MemberGroupList *mgl = ml->getMemberGroupList();
+ if (mgl)
+ {
+ MemberGroupListIterator mgli(*mgl);
+ MemberGroup *mg;
+ for (mgli.toFirst();(mg=mgli.current());++mgli)
+ {
+ if (mg->members())
+ {
+ writeBoxMemberList(t,prot,mg->members(),scope,isStatic,skipNames);
+ }
+ }
+ }
+ }
+}
+
+QCString DotNode::convertLabel(const QCString &l)
+{
+ QString bBefore("\\_/<({[: =-+@%#~?$"); // break before character set
+ QString bAfter(">]),:;|"); // break after character set
+ QString p(l);
+ if (p.isEmpty()) return QCString();
+ QString result;
+ QChar c,pc=0;
+ uint idx = 0;
+ int len=p.length();
+ int charsLeft=len;
+ int sinceLast=0;
+ int foldLen=17; // ideal text length
+ while (idx < p.length())
+ {
+ c = p[idx++];
+ QString replacement;
+ switch(c)
+ {
+ case '\\': replacement="\\\\"; break;
+ case '\n': replacement="\\n"; break;
+ case '<': replacement="\\<"; break;
+ case '>': replacement="\\>"; break;
+ case '|': replacement="\\|"; break;
+ case '{': replacement="\\{"; break;
+ case '}': replacement="\\}"; break;
+ case '"': replacement="\\\""; break;
+ default: replacement=c; break;
+ }
+ // Some heuristics to insert newlines to prevent too long
+ // boxes and at the same time prevent ugly breaks
+ if (c=='\n')
+ {
+ result+=replacement;
+ foldLen = (3*foldLen+sinceLast+2)/4;
+ sinceLast=1;
+ }
+ else if ((pc!=':' || c!=':') && charsLeft>foldLen/3 && sinceLast>foldLen && bBefore.contains(c))
+ {
+ result+="\\l";
+ result+=replacement;
+ foldLen = (foldLen+sinceLast+1)/2;
+ sinceLast=1;
+ }
+ else if (charsLeft>1+foldLen/4 && sinceLast>foldLen+foldLen/3 &&
+ !isupper(c) && p[idx].category()==QChar::Letter_Uppercase)
+ {
+ result+=replacement;
+ result+="\\l";
+ foldLen = (foldLen+sinceLast+1)/2;
+ sinceLast=0;
+ }
+ else if (charsLeft>foldLen/3 && sinceLast>foldLen && bAfter.contains(c) && (c!=':' || p[idx]!=':'))
+ {
+ result+=replacement;
+ result+="\\l";
+ foldLen = (foldLen+sinceLast+1)/2;
+ sinceLast=0;
+ }
+ else
+ {
+ result+=replacement;
+ sinceLast++;
+ }
+ charsLeft--;
+ pc=c;
+ }
+ return result.utf8();
+}
+
+static QCString stripProtectionPrefix(const QCString &s)
+{
+ if (!s.isEmpty() && (s[0]=='-' || s[0]=='+' || s[0]=='~' || s[0]=='#'))
+ {
+ return s.mid(1);
+ }
+ else
+ {
+ return s;
+ }
+}
+
+DotNode::DotNode(int n,const char *lab,const char *tip, const char *url,
+ bool isRoot,const ClassDef *cd)
+ : m_subgraphId(-1)
+ , m_number(n)
+ , m_label(lab)
+ , m_tooltip(tip)
+ , m_url(url)
+ , m_parents(0)
+ , m_children(0)
+ , m_edgeInfo(0)
+ , m_deleted(FALSE)
+ , m_written(FALSE)
+ , m_hasDoc(FALSE)
+ , m_isRoot(isRoot)
+ , m_classDef(cd)
+ , m_visible(FALSE)
+ , m_truncated(Unknown)
+ , m_distance(1000)
+ , m_renumbered(false)
+{
+}
+
+DotNode::~DotNode()
+{
+ delete m_children;
+ delete m_parents;
+ delete m_edgeInfo;
+}
+
+void DotNode::addChild(DotNode *n,
+ int edgeColor,
+ int edgeStyle,
+ const char *edgeLab,
+ const char *edgeURL,
+ int edgeLabCol
+)
+{
+ if (m_children==0)
+ {
+ m_children = new QList<DotNode>;
+ m_edgeInfo = new QList<EdgeInfo>;
+ m_edgeInfo->setAutoDelete(TRUE);
+ }
+ m_children->append(n);
+ EdgeInfo *ei = new EdgeInfo(
+ edgeColor,
+ edgeStyle,
+ edgeLab,
+ edgeURL,
+ edgeLabCol==-1 ? edgeColor : edgeLabCol);
+ m_edgeInfo->append(ei);
+}
+
+void DotNode::addParent(DotNode *n)
+{
+ if (m_parents==0)
+ {
+ m_parents = new QList<DotNode>;
+ }
+ m_parents->append(n);
+}
+
+void DotNode::removeChild(DotNode *n)
+{
+ if (m_children) m_children->remove(n);
+}
+
+void DotNode::removeParent(DotNode *n)
+{
+ if (m_parents) m_parents->remove(n);
+}
+
+void DotNode::deleteNode(DotNodeList &deletedList,SDict<DotNode> *skipNodes)
+{
+ if (m_deleted) return; // avoid recursive loops in case the graph has cycles
+ m_deleted=TRUE;
+ if (m_parents!=0) // delete all parent nodes of this node
+ {
+ QListIterator<DotNode> dnlip(*m_parents);
+ DotNode *pn;
+ for (dnlip.toFirst();(pn=dnlip.current());++dnlip)
+ {
+ //pn->removeChild(this);
+ pn->deleteNode(deletedList,skipNodes);
+ }
+ }
+ if (m_children!=0) // delete all child nodes of this node
+ {
+ QListIterator<DotNode> dnlic(*m_children);
+ DotNode *cn;
+ for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
+ {
+ //cn->removeParent(this);
+ cn->deleteNode(deletedList,skipNodes);
+ }
+ }
+ // add this node to the list of deleted nodes.
+ //printf("skipNodes=%p find(%p)=%p\n",skipNodes,this,skipNodes ? skipNodes->find((int)this) : 0);
+ if (skipNodes==0 || skipNodes->find((char*)this)==0)
+ {
+ //printf("deleting\n");
+ deletedList.append(this);
+ }
+}
+
+void DotNode::setDistance(int distance)
+{
+ if (distance<m_distance) m_distance = distance;
+}
+
+inline int DotNode::findParent( DotNode *n )
+{
+ if ( !m_parents ) return -1;
+ return m_parents->find(n);
+}
+
+/*! helper function that deletes all nodes in a connected graph, given
+* one of the graph's nodes
+*/
+void DotNode::deleteNodes(DotNode *node,SDict<DotNode> *skipNodes)
+{
+ //printf("deleteNodes skipNodes=%p\n",skipNodes);
+ static DotNodeList deletedNodes;
+ deletedNodes.setAutoDelete(TRUE);
+ node->deleteNode(deletedNodes,skipNodes); // collect nodes to be deleted.
+ deletedNodes.clear(); // actually remove the nodes.
+}
+
+void DotNode::writeBox(FTextStream &t,
+ GraphType gt,
+ GraphOutputFormat /*format*/,
+ bool hasNonReachableChildren) const
+{
+ const char *labCol =
+ m_url.isEmpty() ? "grey75" : // non link
+ (hasNonReachableChildren ? "red" : "black");
+ t << " Node" << m_number << " [label=\"";
+
+ if (m_classDef && Config_getBool(UML_LOOK) && (gt==Inheritance || gt==Collaboration))
+ {
+ // add names shown as relations to a dictionary, so we don't show
+ // them as attributes as well
+ QDict<void> arrowNames(17);
+ if (m_edgeInfo)
+ {
+ // for each edge
+ QListIterator<EdgeInfo> li(*m_edgeInfo);
+ EdgeInfo *ei;
+ for (li.toFirst();(ei=li.current());++li)
+ {
+ if (!ei->label().isEmpty()) // labels joined by \n
+ {
+ int li=ei->label().find('\n');
+ int p=0;
+ QCString lab;
+ while ((li=ei->label().find('\n',p))!=-1)
+ {
+ lab = stripProtectionPrefix(ei->label().mid(p,li-p));
+ arrowNames.insert(lab,(void*)0x8);
+ p=li+1;
+ }
+ lab = stripProtectionPrefix(ei->label().right(ei->label().length()-p));
+ arrowNames.insert(lab,(void*)0x8);
+ }
+ }
+ }
+
+ //printf("DotNode::writeBox for %s\n",m_classDef->name().data());
+ t << "{" << convertLabel(m_label);
+ t << "\\n|";
+ writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubAttribs),m_classDef,FALSE,&arrowNames);
+ writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubStaticAttribs),m_classDef,TRUE,&arrowNames);
+ writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_properties),m_classDef,FALSE,&arrowNames);
+ writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacAttribs),m_classDef,FALSE,&arrowNames);
+ writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacStaticAttribs),m_classDef,TRUE,&arrowNames);
+ writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proAttribs),m_classDef,FALSE,&arrowNames);
+ writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proStaticAttribs),m_classDef,TRUE,&arrowNames);
+ if (Config_getBool(EXTRACT_PRIVATE))
+ {
+ writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priAttribs),m_classDef,FALSE,&arrowNames);
+ writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priStaticAttribs),m_classDef,TRUE,&arrowNames);
+ }
+ t << "|";
+ writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubMethods),m_classDef);
+ writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubStaticMethods),m_classDef,TRUE);
+ writeBoxMemberList(t,'+',m_classDef->getMemberList(MemberListType_pubSlots),m_classDef);
+ writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacMethods),m_classDef);
+ writeBoxMemberList(t,'~',m_classDef->getMemberList(MemberListType_pacStaticMethods),m_classDef,TRUE);
+ writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proMethods),m_classDef);
+ writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proStaticMethods),m_classDef,TRUE);
+ writeBoxMemberList(t,'#',m_classDef->getMemberList(MemberListType_proSlots),m_classDef);
+ if (Config_getBool(EXTRACT_PRIVATE))
+ {
+ writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priMethods),m_classDef);
+ writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priStaticMethods),m_classDef,TRUE);
+ writeBoxMemberList(t,'-',m_classDef->getMemberList(MemberListType_priSlots),m_classDef);
+ }
+ if (m_classDef->getLanguage()!=SrcLangExt_Fortran &&
+ m_classDef->getMemberGroupSDict())
+ {
+ MemberGroupSDict::Iterator mgdi(*m_classDef->getMemberGroupSDict());
+ MemberGroup *mg;
+ for (mgdi.toFirst();(mg=mgdi.current());++mgdi)
+ {
+ if (mg->members())
+ {
+ writeBoxMemberList(t,'*',mg->members(),m_classDef,FALSE,&arrowNames);
+ }
+ }
+ }
+ t << "}";
+ }
+ else // standard look
+ {
+ t << convertLabel(m_label);
+ }
+ t << "\",height=0.2,width=0.4";
+ if (m_isRoot)
+ {
+ t << ",color=\"black\", fillcolor=\"grey75\", style=\"filled\", fontcolor=\"black\"";
+ }
+ else
+ {
+ if (!Config_getBool(DOT_TRANSPARENT))
+ {
+ t << ",color=\"" << labCol << "\", fillcolor=\"";
+ t << "white";
+ t << "\", style=\"filled\"";
+ }
+ else
+ {
+ t << ",color=\"" << labCol << "\"";
+ }
+ if (!m_url.isEmpty())
+ {
+ int anchorPos = m_url.findRev('#');
+ if (anchorPos==-1)
+ {
+ t << ",URL=\"" << m_url << Doxygen::htmlFileExtension << "\"";
+ }
+ else
+ {
+ t << ",URL=\"" << m_url.left(anchorPos) << Doxygen::htmlFileExtension
+ << m_url.right(m_url.length()-anchorPos) << "\"";
+ }
+ }
+ }
+ if (!m_tooltip.isEmpty())
+ {
+ t << ",tooltip=\"" << escapeTooltip(m_tooltip) << "\"";
+ }
+ else
+ {
+ t << ",tooltip=\" \""; // space in tooltip is required otherwise still something like 'Node0' is used
+ }
+ t << "];" << endl;
+}
+
+void DotNode::writeArrow(FTextStream &t,
+ GraphType gt,
+ GraphOutputFormat format,
+ const DotNode *cn,
+ const EdgeInfo *ei,
+ bool topDown,
+ bool pointBack) const
+{
+ t << " Node";
+ if (topDown)
+ t << cn->number();
+ else
+ t << m_number;
+ t << " -> Node";
+ if (topDown)
+ t << m_number;
+ else
+ t << cn->number();
+ t << " [";
+
+ const EdgeProperties *eProps = Config_getBool(UML_LOOK) ? &umlEdgeProps : &normalEdgeProps;
+ QCString aStyle = eProps->arrowStyleMap[ei->color()];
+ bool umlUseArrow = aStyle=="odiamond";
+
+ if (pointBack && !umlUseArrow) t << "dir=\"back\",";
+ t << "color=\"" << eProps->edgeColorMap[ei->color()]
+ << "\",fontsize=\"" << DotGraph::DOT_FONTSIZE << "\",";
+ t << "style=\"" << eProps->edgeStyleMap[ei->style()] << "\"";
+ if (!ei->label().isEmpty())
+ {
+ t << ",label=\" " << convertLabel(ei->label()) << "\" ";
+ }
+ if (Config_getBool(UML_LOOK) &&
+ eProps->arrowStyleMap[ei->color()] &&
+ (gt==Inheritance || gt==Collaboration)
+ )
+ {
+ bool rev = pointBack;
+ if (umlUseArrow) rev=!rev; // UML use relates has arrow on the start side
+ if (rev)
+ t << ",arrowtail=\"" << eProps->arrowStyleMap[ei->color()] << "\"";
+ else
+ t << ",arrowhead=\"" << eProps->arrowStyleMap[ei->color()] << "\"";
+ }
+
+ if (format==GOF_BITMAP) t << ",fontname=\"" << DotGraph::DOT_FONTNAME << "\"";
+ t << "];" << endl;
+}
+
+void DotNode::write(FTextStream &t,
+ GraphType gt,
+ GraphOutputFormat format,
+ bool topDown,
+ bool toChildren,
+ bool backArrows) const
+{
+ //printf("DotNode::write(%d) name=%s this=%p written=%d visible=%d\n",m_distance,m_label.data(),this,m_written,m_visible);
+ if (m_written) return; // node already written to the output
+ if (!m_visible) return; // node is not visible
+ writeBox(t,gt,format,m_truncated==Truncated);
+ m_written=TRUE;
+ QList<DotNode> *nl = toChildren ? m_children : m_parents;
+ if (nl)
+ {
+ if (toChildren)
+ {
+ QListIterator<DotNode> dnli1(*nl);
+ QListIterator<EdgeInfo> dnli2(*m_edgeInfo);
+ const DotNode *cn;
+ for (dnli1.toFirst();(cn=dnli1.current());++dnli1,++dnli2)
+ {
+ if (cn->isVisible())
+ {
+ //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",cn->label().data());
+ writeArrow(t,gt,format,cn,dnli2.current(),topDown,backArrows);
+ }
+ cn->write(t,gt,format,topDown,toChildren,backArrows);
+ }
+ }
+ else // render parents
+ {
+ QListIterator<DotNode> dnli(*nl);
+ DotNode *pn;
+ for (dnli.toFirst();(pn=dnli.current());++dnli)
+ {
+ if (pn->isVisible())
+ {
+ //printf("write arrow %s%s%s\n",label().data(),backArrows?"<-":"->",pn->label().data());
+ writeArrow(t,
+ gt,
+ format,
+ pn,
+ pn->edgeInfo()->at(pn->children()->findRef(this)),
+ FALSE,
+ backArrows
+ );
+ }
+ pn->write(t,gt,format,TRUE,FALSE,backArrows);
+ }
+ }
+ }
+ //printf("end DotNode::write(%d) name=%s\n",distance,m_label.data());
+}
+
+void DotNode::writeXML(FTextStream &t,bool isClassGraph) const
+{
+ t << " <node id=\"" << m_number << "\">" << endl;
+ t << " <label>" << convertToXML(m_label) << "</label>" << endl;
+ if (!m_url.isEmpty())
+ {
+ QCString url(m_url);
+ const char *refPtr = url.data();
+ char *urlPtr = strchr(url.rawData(),'$');
+ if (urlPtr)
+ {
+ *urlPtr++='\0';
+ t << " <link refid=\"" << convertToXML(urlPtr) << "\"";
+ if (*refPtr!='\0')
+ {
+ t << " external=\"" << convertToXML(refPtr) << "\"";
+ }
+ t << "/>" << endl;
+ }
+ }
+ if (m_children)
+ {
+ QListIterator<DotNode> nli(*m_children);
+ QListIterator<EdgeInfo> eli(*m_edgeInfo);
+ DotNode *childNode;
+ EdgeInfo *edgeInfo;
+ for (;(childNode=nli.current());++nli,++eli)
+ {
+ edgeInfo=eli.current();
+ t << " <childnode refid=\"" << childNode->number() << "\" relation=\"";
+ if (isClassGraph)
+ {
+ switch(edgeInfo->color())
+ {
+ case EdgeInfo::Blue: t << "public-inheritance"; break;
+ case EdgeInfo::Green: t << "protected-inheritance"; break;
+ case EdgeInfo::Red: t << "private-inheritance"; break;
+ case EdgeInfo::Purple: t << "usage"; break;
+ case EdgeInfo::Orange: t << "template-instance"; break;
+ case EdgeInfo::Orange2: t << "type-constraint"; break;
+ case EdgeInfo::Grey: ASSERT(0); break;
+ }
+ }
+ else // include graph
+ {
+ t << "include";
+ }
+ t << "\">" << endl;
+ if (!edgeInfo->label().isEmpty())
+ {
+ int p=0;
+ int ni;
+ while ((ni=edgeInfo->label().find('\n',p))!=-1)
+ {
+ t << " <edgelabel>"
+ << convertToXML(edgeInfo->label().mid(p,ni-p))
+ << "</edgelabel>" << endl;
+ p=ni+1;
+ }
+ t << " <edgelabel>"
+ << convertToXML(edgeInfo->label().right(edgeInfo->label().length()-p))
+ << "</edgelabel>" << endl;
+ }
+ t << " </childnode>" << endl;
+ }
+ }
+ t << " </node>" << endl;
+}
+
+void DotNode::writeDocbook(FTextStream &t,bool isClassGraph) const
+{
+ t << " <node id=\"" << m_number << "\">" << endl;
+ t << " <label>" << convertToXML(m_label) << "</label>" << endl;
+ if (!m_url.isEmpty())
+ {
+ QCString url(m_url);
+ const char *refPtr = url.data();
+ char *urlPtr = strchr(url.rawData(),'$');
+ if (urlPtr)
+ {
+ *urlPtr++='\0';
+ t << " <link refid=\"" << convertToXML(urlPtr) << "\"";
+ if (*refPtr!='\0')
+ {
+ t << " external=\"" << convertToXML(refPtr) << "\"";
+ }
+ t << "/>" << endl;
+ }
+ }
+ if (m_children)
+ {
+ QListIterator<DotNode> nli(*m_children);
+ QListIterator<EdgeInfo> eli(*m_edgeInfo);
+ DotNode *childNode;
+ EdgeInfo *edgeInfo;
+ for (;(childNode=nli.current());++nli,++eli)
+ {
+ edgeInfo=eli.current();
+ t << " <childnode refid=\"" << childNode->number() << "\" relation=\"";
+ if (isClassGraph)
+ {
+ switch(edgeInfo->color())
+ {
+ case EdgeInfo::Blue: t << "public-inheritance"; break;
+ case EdgeInfo::Green: t << "protected-inheritance"; break;
+ case EdgeInfo::Red: t << "private-inheritance"; break;
+ case EdgeInfo::Purple: t << "usage"; break;
+ case EdgeInfo::Orange: t << "template-instance"; break;
+ case EdgeInfo::Orange2: t << "type-constraint"; break;
+ case EdgeInfo::Grey: ASSERT(0); break;
+ }
+ }
+ else // include graph
+ {
+ t << "include";
+ }
+ t << "\">" << endl;
+ if (!edgeInfo->label().isEmpty())
+ {
+ int p=0;
+ int ni;
+ while ((ni=edgeInfo->label().find('\n',p))!=-1)
+ {
+ t << " <edgelabel>"
+ << convertToXML(edgeInfo->label().mid(p,ni-p))
+ << "</edgelabel>" << endl;
+ p=ni+1;
+ }
+ t << " <edgelabel>"
+ << convertToXML(edgeInfo->label().right(edgeInfo->label().length()-p))
+ << "</edgelabel>" << endl;
+ }
+ t << " </childnode>" << endl;
+ }
+ }
+ t << " </node>" << endl;
+}
+
+
+void DotNode::writeDEF(FTextStream &t) const
+{
+ const char* nodePrefix = " node-";
+
+ t << " node = {" << endl;
+ t << nodePrefix << "id = " << m_number << ';' << endl;
+ t << nodePrefix << "label = '" << m_label << "';" << endl;
+
+ if (!m_url.isEmpty())
+ {
+ QCString url(m_url);
+ const char *refPtr = url.data();
+ char *urlPtr = strchr(url.rawData(),'$');
+ if (urlPtr)
+ {
+ *urlPtr++='\0';
+ t << nodePrefix << "link = {" << endl << " "
+ << nodePrefix << "link-id = '" << urlPtr << "';" << endl;
+
+ if (*refPtr!='\0')
+ {
+ t << " " << nodePrefix << "link-external = '"
+ << refPtr << "';" << endl;
+ }
+ t << " };" << endl;
+ }
+ }
+ if (m_children)
+ {
+ QListIterator<DotNode> nli(*m_children);
+ QListIterator<EdgeInfo> eli(*m_edgeInfo);
+ DotNode *childNode;
+ EdgeInfo *edgeInfo;
+ for (;(childNode=nli.current());++nli,++eli)
+ {
+ edgeInfo=eli.current();
+ t << " node-child = {" << endl;
+ t << " child-id = '" << childNode->number() << "';" << endl;
+ t << " relation = ";
+
+ switch(edgeInfo->color())
+ {
+ case EdgeInfo::Blue: t << "public-inheritance"; break;
+ case EdgeInfo::Green: t << "protected-inheritance"; break;
+ case EdgeInfo::Red: t << "private-inheritance"; break;
+ case EdgeInfo::Purple: t << "usage"; break;
+ case EdgeInfo::Orange: t << "template-instance"; break;
+ case EdgeInfo::Orange2: t << "type-constraint"; break;
+ case EdgeInfo::Grey: ASSERT(0); break;
+ }
+ t << ';' << endl;
+
+ if (!edgeInfo->label().isEmpty())
+ {
+ t << " edgelabel = <<_EnD_oF_dEf_TeXt_" << endl
+ << edgeInfo->label() << endl
+ << "_EnD_oF_dEf_TeXt_;" << endl;
+ }
+ t << " }; /* node-child */" << endl;
+ } /* for (;childNode...) */
+ }
+ t << " }; /* node */" << endl;
+}
+
+
+void DotNode::clearWriteFlag()
+{
+ m_written=FALSE;
+ if (m_parents!=0)
+ {
+ QListIterator<DotNode> dnlip(*m_parents);
+ DotNode *pn;
+ for (dnlip.toFirst();(pn=dnlip.current());++dnlip)
+ {
+ if (pn->isWritten())
+ {
+ pn->clearWriteFlag();
+ }
+ }
+ }
+ if (m_children!=0)
+ {
+ QListIterator<DotNode> dnlic(*m_children);
+ DotNode *cn;
+ for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
+ {
+ if (cn->isWritten())
+ {
+ cn->clearWriteFlag();
+ }
+ }
+ }
+}
+
+void DotNode::colorConnectedNodes(int curColor)
+{
+ if (m_children)
+ {
+ QListIterator<DotNode> dnlic(*m_children);
+ DotNode *cn;
+ for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
+ {
+ if (cn->subgraphId()==-1) // uncolored child node
+ {
+ cn->setSubgraphId(curColor);
+ cn->markAsVisible();
+ cn->colorConnectedNodes(curColor);
+ //printf("coloring node %s (%p): %d\n",cn->label().data(),cn,cn->subgraphId());
+ }
+ }
+ }
+
+ if (m_parents)
+ {
+ QListIterator<DotNode> dnlip(*m_parents);
+ DotNode *pn;
+ for (dnlip.toFirst();(pn=dnlip.current());++dnlip)
+ {
+ if (pn->subgraphId()==-1) // uncolored parent node
+ {
+ pn->setSubgraphId(curColor);
+ pn->markAsVisible();
+ pn->colorConnectedNodes(curColor);
+ //printf("coloring node %s (%p): %d\n",pn->label().data(),pn,pn->subgraphId());
+ }
+ }
+ }
+}
+
+void DotNode::renumberNodes(int &number)
+{
+ m_number = number++;
+ if (m_children)
+ {
+ QListIterator<DotNode> dnlic(*m_children);
+ DotNode *cn;
+ for (dnlic.toFirst();(cn=dnlic.current());++dnlic)
+ {
+ if (!cn->isRenumbered())
+ {
+ cn->markRenumbered();
+ cn->renumberNodes(number);
+ }
+ }
+ }
+}
+
+const DotNode *DotNode::findDocNode() const
+{
+ if (!m_url.isEmpty()) return this;
+ //printf("findDocNode(): '%s'\n",m_label.data());
+ if (m_parents)
+ {
+ QListIterator<DotNode> dnli(*m_parents);
+ DotNode *pn;
+ for (dnli.toFirst();(pn=dnli.current());++dnli)
+ {
+ if (!pn->hasDocumentation())
+ {
+ pn->markHasDocumentation();
+ const DotNode *dn = pn->findDocNode();
+ if (dn) return dn;
+ }
+ }
+ }
+ if (m_children)
+ {
+ QListIterator<DotNode> dnli(*m_children);
+ DotNode *cn;
+ for (dnli.toFirst();(cn=dnli.current());++dnli)
+ {
+ if (!cn->hasDocumentation())
+ {
+ cn->markHasDocumentation();
+ const DotNode *dn = cn->findDocNode();
+ if (dn) return dn;
+ }
+ }
+ }
+ return 0;
+}
+
+//--------------------------------------------------------------
+
+int DotNodeList::compareValues(const DotNode *n1,const DotNode *n2) const
+{
+ return qstricmp(n1->label(),n2->label());
+}
+
+
+
diff --git a/src/dotnode.h b/src/dotnode.h
new file mode 100644
index 0000000..334fdef
--- /dev/null
+++ b/src/dotnode.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTNODE_H
+#define DOTNODE_H
+
+#include "sortdict.h"
+
+#include "dotgraph.h"
+
+class ClassDef;
+class DotNodeList;
+class FTextStream;
+
+/** Attributes of an edge of a dot graph */
+class EdgeInfo
+{
+ public:
+ enum Colors { Blue=0, Green=1, Red=2, Purple=3, Grey=4, Orange=5, Orange2=6 };
+ enum Styles { Solid=0, Dashed=1 };
+ EdgeInfo(int color,int style,const QCString &lab,const QCString &url,int labColor)
+ : m_color(color), m_style(style), m_label(lab), m_url(url), m_labColor(labColor) {}
+ ~EdgeInfo() {}
+ int color() const { return m_color; }
+ int style() const { return m_style; }
+ QCString label() const { return m_label; }
+ QCString url() const { return m_url; }
+ int labelColor() const { return m_labColor; }
+ private:
+ int m_color;
+ int m_style;
+ QCString m_label;
+ QCString m_url;
+ int m_labColor;
+};
+
+/** A node in a dot graph */
+class DotNode
+{
+ public:
+ static void deleteNodes(DotNode* node, SDict<DotNode>* skipNodes = 0);
+ static QCString convertLabel(const QCString& l);
+ DotNode(int n,const char *lab,const char *tip,const char *url,
+ bool rootNode=FALSE,const ClassDef *cd=0);
+ ~DotNode();
+
+ enum TruncState { Unknown, Truncated, Untruncated };
+
+ void addChild(DotNode *n,
+ int edgeColor=EdgeInfo::Purple,
+ int edgeStyle=EdgeInfo::Solid,
+ const char *edgeLab=0,
+ const char *edgeURL=0,
+ int edgeLabCol=-1);
+ void addParent(DotNode *n);
+ void deleteNode(DotNodeList &deletedList,SDict<DotNode> *skipNodes=0);
+ void removeChild(DotNode *n);
+ void removeParent(DotNode *n);
+ int findParent( DotNode *n );
+
+ void write(FTextStream &t,GraphType gt,GraphOutputFormat f,
+ bool topDown,bool toChildren,bool backArrows) const;
+ void writeXML(FTextStream &t,bool isClassGraph) const;
+ void writeDocbook(FTextStream &t,bool isClassGraph) const;
+ void writeDEF(FTextStream &t) const;
+ void writeBox(FTextStream &t,GraphType gt,GraphOutputFormat f,
+ bool hasNonReachableChildren) const;
+ void writeArrow(FTextStream &t,GraphType gt,GraphOutputFormat f,const DotNode *cn,
+ const EdgeInfo *ei,bool topDown, bool pointBack=TRUE) const;
+
+ QCString label() const { return m_label; }
+ int number() const { return m_number; }
+ bool isVisible() const { return m_visible; }
+ TruncState isTruncated() const { return m_truncated; }
+ int distance() const { return m_distance; }
+ int subgraphId() const { return m_subgraphId; }
+ bool isRenumbered() const { return m_renumbered; }
+ bool hasDocumentation() const { return m_hasDoc; }
+ bool isWritten() const { return m_written; }
+
+ void clearWriteFlag();
+ void renumberNodes(int &number);
+ void markRenumbered() { m_renumbered = true; }
+ void markHasDocumentation() { m_hasDoc = true; }
+ void setSubgraphId(int id) { m_subgraphId = id; }
+
+ void colorConnectedNodes(int curColor);
+ void setDistance(int distance);
+ const DotNode *findDocNode() const; // only works for acyclic graphs!
+ void markAsVisible(bool b=TRUE) { m_visible=b; }
+ void markAsTruncated(bool b=TRUE) { m_truncated=b ? Truncated : Untruncated; }
+ const QList<DotNode> *children() const { return m_children; }
+ const QList<DotNode> *parents() const { return m_parents; }
+ const QList<EdgeInfo> *edgeInfo() const { return m_edgeInfo; }
+
+ private:
+ int m_number;
+ QCString m_label; //!< label text
+ QCString m_tooltip; //!< node's tooltip
+ QCString m_url; //!< url of the node (format: remote$local)
+ QList<DotNode> *m_parents; //!< list of parent nodes (incoming arrows)
+ QList<DotNode> *m_children; //!< list of child nodes (outgoing arrows)
+ QList<EdgeInfo> *m_edgeInfo; //!< edge info for each child
+ bool m_deleted; //!< used to mark a node as deleted
+ mutable bool m_written; //!< used to mark a node as written
+ bool m_hasDoc; //!< used to mark a node as documented
+ bool m_isRoot; //!< indicates if this is a root node
+ const ClassDef * m_classDef; //!< class representing this node (can be 0)
+ bool m_visible; //!< is the node visible in the output
+ TruncState m_truncated; //!< does the node have non-visible children/parents
+ int m_distance; //!< shortest path to the root node
+ bool m_renumbered;//!< indicates if the node has been renumbered (to prevent endless loops)
+ int m_subgraphId;
+};
+
+/** Class representing a list of DotNode objects. */
+class DotNodeList : public QList<DotNode>
+{
+ public:
+ DotNodeList() : QList<DotNode>() {}
+ ~DotNodeList() {}
+ private:
+ int compareValues(const DotNode *n1,const DotNode *n2) const;
+};
+
+#endif
diff --git a/src/dotrunner.cpp b/src/dotrunner.cpp
new file mode 100644
index 0000000..3a621c7
--- /dev/null
+++ b/src/dotrunner.cpp
@@ -0,0 +1,294 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 "dotrunner.h"
+
+#include "util.h"
+#include "portable.h"
+#include "dot.h"
+#include "message.h"
+#include "ftextstream.h"
+#include "config.h"
+
+// the graphicx LaTeX has a limitation of maximum size of 16384
+// To be on the save side we take it a little bit smaller i.e. 150 inch * 72 dpi
+// It is anyway hard to view these size of images
+#define MAX_LATEX_GRAPH_INCH 150
+#define MAX_LATEX_GRAPH_SIZE (MAX_LATEX_GRAPH_INCH * 72)
+
+
+// since dot silently reproduces the input file when it does not
+// support the PNG format, we need to check the result.
+static void checkPngResult(const char *imgName)
+{
+ FILE *f = portable_fopen(imgName,"rb");
+ if (f)
+ {
+ char data[4];
+ if (fread(data,1,4,f)==4)
+ {
+ if (!(data[1]=='P' && data[2]=='N' && data[3]=='G'))
+ {
+ err("Image '%s' produced by dot is not a valid PNG!\n"
+ "You should either select a different format "
+ "(DOT_IMAGE_FORMAT in the config file) or install a more "
+ "recent version of graphviz (1.7+)\n",imgName
+ );
+ }
+ }
+ else
+ {
+ err("Could not read image '%s' generated by dot!\n",imgName);
+ }
+ fclose(f);
+ }
+ else
+ {
+ err("Could not open image '%s' generated by dot!\n",imgName);
+ }
+}
+
+static bool resetPDFSize(const int width,const int height, const char *base)
+{
+ QString tmpName = QString::fromUtf8(QCString(base)+".tmp");
+ QString patchFile = QString::fromUtf8(QCString(base)+".dot");
+ if (!QDir::current().rename(patchFile,tmpName))
+ {
+ err("Failed to rename file %s to %s!\n",patchFile.data(),tmpName.data());
+ return FALSE;
+ }
+ QFile fi(tmpName);
+ QFile fo(patchFile);
+ if (!fi.open(IO_ReadOnly))
+ {
+ err("problem opening file %s for patching!\n",tmpName.data());
+ QDir::current().rename(tmpName,patchFile);
+ return FALSE;
+ }
+ if (!fo.open(IO_WriteOnly))
+ {
+ err("problem opening file %s for patching!\n",patchFile.data());
+ QDir::current().rename(tmpName,patchFile);
+ fi.close();
+ return FALSE;
+ }
+ FTextStream t(&fo);
+ const int maxLineLen=100*1024;
+ while (!fi.atEnd()) // foreach line
+ {
+ QCString line(maxLineLen);
+ int numBytes = fi.readLine(line.rawData(),maxLineLen);
+ if (numBytes<=0)
+ {
+ break;
+ }
+ line.resize(numBytes+1);
+ if (line.find("LATEX_PDF_SIZE") != -1)
+ {
+ double scale = (width > height ? width : height)/double(MAX_LATEX_GRAPH_INCH);
+ t << " size=\""<<width/scale << "," <<height/scale <<"\";\n";
+ }
+ else
+ t << line;
+ }
+ fi.close();
+ fo.close();
+ // remove temporary file
+ QDir::current().remove(tmpName);
+ return TRUE;
+}
+
+bool DotRunner::readBoundingBox(const char *fileName,int *width,int *height,bool isEps)
+{
+ const char *bb = isEps ? "%%PageBoundingBox:" : "/MediaBox [";
+ int bblen = strlen(bb);
+ FILE *f = portable_fopen(fileName,"rb");
+ if (!f)
+ {
+ //printf("readBoundingBox: could not open %s\n",fileName);
+ return FALSE;
+ }
+ const int maxLineLen=1024;
+ char buf[maxLineLen];
+ while (fgets(buf,maxLineLen,f)!=NULL)
+ {
+ const char *p = strstr(buf,bb);
+ if (p) // found PageBoundingBox or /MediaBox string
+ {
+ int x,y;
+ fclose(f);
+ if (sscanf(p+bblen,"%d %d %d %d",&x,&y,width,height)!=4)
+ {
+ //printf("readBoundingBox sscanf fail\n");
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ err("Failed to extract bounding box from generated diagram file %s\n",fileName);
+ fclose(f);
+ return FALSE;
+}
+
+bool DotRunner::DOT_CLEANUP;
+bool DotRunner::DOT_MULTI_TARGETS;
+DotConstString DotRunner::DOT_EXE;
+
+DotRunner::DotRunner(const QCString& absDotName, const QCString& md5Hash)
+ : m_file(absDotName), m_md5Hash(md5Hash), m_cleanUp(DOT_CLEANUP)
+{
+ m_jobs.setAutoDelete(TRUE);
+}
+
+void DotRunner::addJob(const char *format,const char *output)
+{
+ QListIterator<DotJob> li(m_jobs);
+ DotJob *s;
+ for (li.toFirst(); (s = li.current()); ++li)
+ {
+ if (qstrcmp(s->format.data(), format) != 0) continue;
+ if (qstrcmp(s->output.data(), output) != 0) continue;
+ // we have this job already
+ return;
+ }
+ QCString args = QCString("-T")+format+" -o \""+output+"\"";
+ m_jobs.append(new DotJob(format, output, args));
+}
+
+QCString getBaseNameOfOutput(QCString const& output)
+{
+ int index = output.findRev('.');
+ if (index < 0) return output;
+ return output.left(index);
+}
+
+bool DotRunner::run()
+{
+ int exitCode=0;
+
+ QCString dotArgs;
+ QListIterator<DotJob> li(m_jobs);
+ DotJob *s;
+
+ // create output
+ if (DOT_MULTI_TARGETS)
+ {
+ dotArgs=QCString("\"")+m_file.data()+"\"";
+ for (li.toFirst();(s=li.current());++li)
+ {
+ dotArgs+=' ';
+ dotArgs+=s->args.data();
+ }
+ if ((exitCode=portable_system(DOT_EXE.data(),dotArgs,FALSE))!=0) goto error;
+ }
+ else
+ {
+ for (li.toFirst();(s=li.current());++li)
+ {
+ dotArgs=QCString("\"")+m_file.data()+"\" "+s->args.data();
+ if ((exitCode=portable_system(DOT_EXE.data(),dotArgs,FALSE))!=0) goto error;
+ }
+ }
+
+ // check output
+ // As there should be only one pdf file be generated, we don't need code for regenerating multiple pdf files in one call
+ for (li.toFirst();(s=li.current());++li)
+ {
+ if (qstrncmp(s->format.data(), "pdf", 3) == 0)
+ {
+ int width=0,height=0;
+ if (!readBoundingBox(s->output.data(),&width,&height,FALSE)) goto error;
+ if ((width > MAX_LATEX_GRAPH_SIZE) || (height > MAX_LATEX_GRAPH_SIZE))
+ {
+ if (!resetPDFSize(width,height,getBaseNameOfOutput(s->output.data()))) goto error;
+ dotArgs=QCString("\"")+m_file.data()+"\" "+s->args.data();
+ if ((exitCode=portable_system(DOT_EXE.data(),dotArgs,FALSE))!=0) goto error;
+ }
+ }
+
+ if (qstrncmp(s->format.data(), "png", 3) == 0)
+ {
+ checkPngResult(s->output.data());
+ }
+ }
+
+ // remove .dot files
+ if (m_cleanUp)
+ {
+ //printf("removing dot file %s\n",m_file.data());
+ portable_unlink(m_file.data());
+ }
+
+ // create checksum file
+ if (!m_md5Hash.isEmpty())
+ {
+ QCString md5Name = getBaseNameOfOutput(m_file.data()) + ".md5";
+ FILE *f = portable_fopen(md5Name,"w");
+ if (f)
+ {
+ fwrite(m_md5Hash.data(),1,32,f);
+ fclose(f);
+ }
+ }
+ return TRUE;
+error:
+ err("Problems running dot: exit code=%d, command='%s', arguments='%s'\n",
+ exitCode,DOT_EXE.data(),dotArgs.data());
+ return FALSE;
+}
+
+
+//--------------------------------------------------------------------
+
+void DotRunnerQueue::enqueue(DotRunner *runner)
+{
+ QMutexLocker locker(&m_mutex);
+ m_queue.enqueue(runner);
+ m_bufferNotEmpty.wakeAll();
+}
+
+DotRunner *DotRunnerQueue::dequeue()
+{
+ QMutexLocker locker(&m_mutex);
+ while (m_queue.isEmpty())
+ {
+ // wait until something is added to the queue
+ m_bufferNotEmpty.wait(&m_mutex);
+ }
+ DotRunner *result = m_queue.dequeue();
+ return result;
+}
+
+uint DotRunnerQueue::count() const
+{
+ QMutexLocker locker(&m_mutex);
+ return m_queue.count();
+}
+
+//--------------------------------------------------------------------
+
+DotWorkerThread::DotWorkerThread(DotRunnerQueue *queue)
+ : m_queue(queue)
+{
+}
+
+void DotWorkerThread::run()
+{
+ DotRunner *runner;
+ while ((runner=m_queue->dequeue()))
+ {
+ runner->run();
+ }
+}
diff --git a/src/dotrunner.h b/src/dotrunner.h
new file mode 100644
index 0000000..4128fe8
--- /dev/null
+++ b/src/dotrunner.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+*
+* Copyright (C) 1997-2019 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 DOTRUNNER_H
+#define DOTRUNNER_H
+
+#include "qcstring.h"
+#include "qlist.h"
+#include "qwaitcondition.h"
+#include "qthread.h"
+#include "qqueue.h"
+#include "qmutex.h"
+
+/** Minimal constant string class that is thread safe, once initialized. */
+class DotConstString
+{
+ public:
+ DotConstString() { m_str=0;}
+ ~DotConstString() { delete[] m_str;}
+ DotConstString(char const* s) : m_str(0) { set(s); }
+ DotConstString(const QCString &s) : m_str(0) { set(s); }
+ DotConstString(const DotConstString &s) : m_str(0) { set(s.data()); }
+ const char *data() const { return m_str; }
+ bool isEmpty() const { return m_str==0 || m_str[0]=='\0'; }
+ void init(const char *s) { set(s); }
+
+ private:
+ void set(char const* s)
+ {
+ delete[] m_str;
+ m_str=0;
+ if (s)
+ {
+ m_str=new char[strlen(s) + 1];
+ qstrcpy(m_str,s);
+ }
+ }
+
+ void set(const QCString &s)
+ {
+ delete[] m_str;
+ m_str=0;
+ if (!s.isEmpty())
+ {
+ m_str=new char[s.length()+1];
+ qstrcpy(m_str,s.data());
+ }
+ }
+
+ DotConstString &operator=(const DotConstString &);
+
+ char *m_str;
+};
+
+/** Helper class to run dot from doxygen from multiple threads. */
+class DotRunner
+{
+ public:
+ struct DotJob
+ {
+ DotJob(const DotConstString & format,
+ const DotConstString & output,
+ const DotConstString & args)
+ : format(format), output(output), args(args) {}
+ DotConstString format;
+ DotConstString output;
+ DotConstString args;
+ };
+
+ /** Creates a runner for a dot \a file. */
+ DotRunner(const QCString& absDotName, const QCString& md5Hash);
+
+ /** Adds an additional job to the run.
+ * Performing multiple jobs one file can be faster.
+ */
+ void addJob(const char *format,const char *output);
+
+ /** Prevent cleanup of the dot file (for user provided dot files) */
+ void preventCleanUp() { m_cleanUp = FALSE; }
+
+ /** Runs dot for all jobs added. */
+ bool run();
+
+ // DotConstString const& getFileName() { return m_file; }
+ DotConstString const& getMd5Hash() { return m_md5Hash; }
+
+ static bool readBoundingBox(const char* fileName, int* width, int* height, bool isEps);
+
+ private:
+ DotConstString m_file;
+ DotConstString m_md5Hash;
+ bool m_cleanUp;
+ QList<DotJob> m_jobs;
+
+ static bool DOT_CLEANUP;
+ static bool DOT_MULTI_TARGETS;
+ static DotConstString DOT_EXE;
+ friend void initDot();
+
+};
+
+/** Queue of dot jobs to run. */
+// all methods are thread save
+class DotRunnerQueue
+{
+ public:
+ void enqueue(DotRunner *runner);
+ DotRunner *dequeue();
+ uint count() const;
+ private:
+ QWaitCondition m_bufferNotEmpty;
+ QQueue<DotRunner> m_queue;
+ mutable QMutex m_mutex;
+};
+
+/** Worker thread to execute a dot run */
+class DotWorkerThread : public QThread
+{
+ public:
+ DotWorkerThread(DotRunnerQueue *queue);
+ void run();
+ private:
+ DotRunnerQueue *m_queue;
+};
+
+#endif
diff --git a/src/doxygen.cpp b/src/doxygen.cpp
index 30c2001..6bf67a0 100644
--- a/src/doxygen.cpp
+++ b/src/doxygen.cpp
@@ -174,6 +174,7 @@ QCString Doxygen::spaces;
bool Doxygen::generatingXmlOutput = FALSE;
bool Doxygen::markdownSupport = TRUE;
GenericsSDict *Doxygen::genericsDict;
+DocGroup Doxygen::docGroup;
// locally accessible globals
static QDict<Entry> g_classEntries(1009);
@@ -804,7 +805,7 @@ static void buildFileList(Entry *root)
{
const char *fn = root->fileName.data();
QCString text(4096);
- text.sprintf("the name `%s' supplied as "
+ text.sprintf("the name '%s' supplied as "
"the argument in the \\file statement ",
qPrint(root->name));
if (ambig) // name is ambiguous
@@ -857,7 +858,7 @@ static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
)
{ // explicit request
QCString text;
- text.sprintf("the name `%s' supplied as "
+ text.sprintf("the name '%s' supplied as "
"the argument of the \\class, \\struct, \\union, or \\include command ",
qPrint(includeFile)
);
@@ -1287,7 +1288,7 @@ static void addClassToContext(Entry *root)
QCString namespaceName;
extractNamespaceName(fullName,className,namespaceName);
- //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
+ //printf("New class: fullname %s namespace '%s' name='%s' brief='%s' docs='%s'\n",
// fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
QCString tagName;
@@ -1320,7 +1321,7 @@ static void addClassToContext(Entry *root)
}
cd=createClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
- Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
+ Debug::print(Debug::Classes,0," New class '%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
qPrint(fullName),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
@@ -1368,7 +1369,7 @@ static void addClassToContext(Entry *root)
}
if (fd && (root->section & Entry::COMPOUND_MASK))
{
- //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
+ //printf(">> Inserting class '%s' in file '%s' (root->fileName='%s')\n",
// cd->name().data(),
// fd->name().data(),
// root->fileName.data()
@@ -1862,7 +1863,7 @@ static const NamespaceDef *findUsedNamespace(const NamespaceSDict *unl,
{
QCString uScope=und->name()+"::";
usingNd = getResolvedNamespace(uScope+name);
- //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
+ //printf("Also trying with scope='%s' usingNd=%p\n",(uScope+name).data(),usingNd);
}
}
return usingNd;
@@ -1899,7 +1900,7 @@ static void findUsingDirectives(Entry *root)
}
}
- // find the scope in which the `using' namespace is defined by prepending
+ // find the scope in which the 'using' namespace is defined by prepending
// the possible scopes in which the using statement was found, starting
// with the most inner scope and going to the most outer scope (i.e.
// file scope).
@@ -1909,7 +1910,7 @@ static void findUsingDirectives(Entry *root)
QCString scope=scopeOffset>0 ?
nsName.left(scopeOffset)+"::" : QCString();
usingNd = getResolvedNamespace(scope+name);
- //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
+ //printf("Trying with scope='%s' usingNd=%p\n",(scope+name).data(),usingNd);
if (scopeOffset==0)
{
scopeOffset=-1;
@@ -2058,7 +2059,7 @@ static void findUsingDeclarations(Entry *root)
}
// Assume the using statement was used to import a class.
- // Find the scope in which the `using' namespace is defined by prepending
+ // Find the scope in which the 'using' namespace is defined by prepending
// the possible scopes in which the using statement was found, starting
// with the most inner scope and going to the most outer scope (i.e.
// file scope).
@@ -2069,7 +2070,7 @@ static void findUsingDeclarations(Entry *root)
// vector -> std::vector
if (usingCd==0)
{
- usingCd = getResolvedClass(nd,fd,name); // try via resolving (see also bug757509)
+ usingCd = const_cast<ClassDef*>(getResolvedClass(nd,fd,name)); // try via resolving (see also bug757509)
}
if (usingCd==0)
{
@@ -2079,7 +2080,7 @@ static void findUsingDeclarations(Entry *root)
//printf("%s -> %p\n",root->name.data(),usingCd);
if (usingCd==0) // definition not in the input => add an artificial class
{
- Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
+ Debug::print(Debug::Classes,0," New using class '%s' (sec=0x%08x)! #tArgLists=%d\n",
qPrint(name),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
usingCd = createClassDef(
"<using>",1,1,
@@ -2135,7 +2136,7 @@ static void findUsingDeclImports(Entry *root)
{
QCString scope=root->name.left(i);
QCString memName=root->name.right(root->name.length()-i-2);
- ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
+ const ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
if (bcd)
{
//printf("found class %s memName=%s\n",bcd->name().data(),memName.data());
@@ -2266,7 +2267,7 @@ static MemberDef *addVariableToClass(
}
Debug::print(Debug::Variables,0,
" class variable:\n"
- " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
+ " '%s' '%s'::'%s' '%s' prot=%d ann=%d init='%s'\n",
qPrint(root->type),
qPrint(qualScope),
qPrint(name),
@@ -2327,7 +2328,8 @@ static MemberDef *addVariableToClass(
{
//printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
// md->getClassDef(),cd,root->type.data(),md->typeString());
- if (md->getClassDef()==cd &&
+ if (!md->isAlias() &&
+ md->getClassDef()==cd &&
removeRedundantWhiteSpace(root->type)==md->typeString())
// member already in the scope
{
@@ -2434,7 +2436,7 @@ static MemberDef *addVariableToFile(
{
Debug::print(Debug::Variables,0,
" global variable:\n"
- " file='%s' type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
+ " file='%s' type='%s' scope='%s' name='%s' args='%s' prot=`%d mtype=%d lang=%d\n",
qPrint(root->fileName),
qPrint(root->type),
qPrint(scope),
@@ -2555,7 +2557,7 @@ static MemberDef *addVariableToFile(
MemberDef *md;
for (mni.toFirst();(md=mni.current());++mni)
{
- if (
+ if (!md->isAlias() &&
((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
root->fileName==md->getFileDef()->absFilePath()
) // both variable names in the same file
@@ -2835,7 +2837,7 @@ static void addVariable(Entry *root,int isFuncPtr=-1)
Debug::print(Debug::Variables,0,
"VARIABLE_SEC: \n"
- " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
+ " type='%s' name='%s' args='%s' bodyLine=%d mGrpId=%d relates='%s'\n",
qPrint(root->type),
qPrint(root->name),
qPrint(root->args),
@@ -2861,7 +2863,7 @@ static void addVariable(Entry *root,int isFuncPtr=-1)
root->name=root->args.mid(i,l);
root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
}
- //printf("new: type=`%s' name=`%s' args=`%s'\n",
+ //printf("new: type='%s' name='%s' args='%s'\n",
// root->type.data(),root->name.data(),root->args.data());
}
else
@@ -3016,7 +3018,7 @@ static void addVariable(Entry *root,int isFuncPtr=-1)
}
}
- //printf("name=`%s' scope=%s scope.right=%s\n",
+ //printf("name='%s' scope=%s scope.right=%s\n",
// name.data(),scope.data(),
// scope.right(scope.length()-si).data());
addVariableToClass(root, // entry
@@ -3199,8 +3201,8 @@ static void addInterfaceOrServiceToServiceOrSingleton(
Debug::print(Debug::Functions,0,
" Interface Member:\n"
- " `%s' `%s' proto=%d\n"
- " def=`%s'\n",
+ " '%s' '%s' proto=%d\n"
+ " def='%s'\n",
qPrint(root->type),
qPrint(rname),
root->proto,
@@ -3242,7 +3244,7 @@ static void buildInterfaceAndServiceList(Entry *root)
{
Debug::print(Debug::Functions,0,
"EXPORTED_INTERFACE_SEC:\n"
- " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
+ " '%s' '%s'::'%s' '%s' relates='%s' relatesType='%d' file='%s' line='%d' bodyLine='%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
qPrint(root->type),
qPrint(root->parent()->name),
qPrint(root->name),
@@ -3345,7 +3347,7 @@ static void addMethodToClass(Entry *root,ClassDef *cd,
fileName = root->tagInfo->tagName;
}
- //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
+ //printf("root->name='%s; root->args='%s' root->argList='%s'\n",
// root->name.data(),root->args.data(),argListToString(root->argList).data()
// );
@@ -3446,8 +3448,8 @@ static void addMethodToClass(Entry *root,ClassDef *cd,
Debug::print(Debug::Functions,0,
" Func Member:\n"
- " `%s' `%s'::`%s' `%s' proto=%d\n"
- " def=`%s'\n",
+ " '%s' '%s'::'%s' '%s' proto=%d\n"
+ " def='%s'\n",
qPrint(root->type),
qPrint(qualScope),
qPrint(rname),
@@ -3487,7 +3489,7 @@ static void buildFunctionList(Entry *root)
{
Debug::print(Debug::Functions,0,
"FUNCTION_SEC:\n"
- " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
+ " '%s' '%s'::'%s' '%s' relates='%s' relatesType='%d' file='%s' line='%d' bodyLine='%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
qPrint(root->type),
qPrint(root->parent()->name),
qPrint(root->name),
@@ -3648,9 +3650,9 @@ static void buildFunctionList(Entry *root)
)
{
GroupDef *gd=0;
- if (root->groups->getFirst()!=0)
+ if (root->groups->getFirst() && !root->groups->getFirst()->groupname.isEmpty())
{
- gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
+ gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname);
}
//printf("match!\n");
//printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
@@ -3747,7 +3749,7 @@ static void buildFunctionList(Entry *root)
if (!found) /* global function is unique with respect to the file */
{
Debug::print(Debug::Functions,0," --> new function %s found!\n",qPrint(rname));
- //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
+ //printf("New function type='%s' name='%s' args='%s' bodyLine=%d\n",
// root->type.data(),rname.data(),root->args.data(),root->bodyLine);
// new global function
@@ -3825,8 +3827,8 @@ static void buildFunctionList(Entry *root)
}
Debug::print(Debug::Functions,0,
" Global Function:\n"
- " `%s' `%s'::`%s' `%s' proto=%d\n"
- " def=`%s'\n",
+ " '%s' '%s'::'%s' '%s' proto=%d\n"
+ " def='%s'\n",
qPrint(root->type),
qPrint(root->parent()->name),
qPrint(rname),
@@ -3892,7 +3894,7 @@ static void buildFunctionList(Entry *root)
}
}
- //printf("unrelated function %d `%s' `%s' `%s'\n",
+ //printf("unrelated function %d '%s' '%s' '%s'\n",
// root->parent->section,root->type.data(),rname.data(),root->args.data());
}
else
@@ -3919,7 +3921,7 @@ static void findFriends()
MemberName *fn;
for (;(fn=fnli.current());++fnli) // for each global function name
{
- //printf("Function name=`%s'\n",fn->memberName());
+ //printf("Function name='%s'\n",fn->memberName());
MemberName *mn;
if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
{ // there are members with the same name
@@ -4146,7 +4148,7 @@ static void transferRelatedFunctionDocumentation()
/* find a matching function declaration and definition for this function */
for (mni.toFirst();(md=mni.current());++mni) // for each global function
{
- //printf(" Function `%s'\n",md->name().data());
+ //printf(" Function '%s'\n",md->name().data());
MemberName *rmn;
if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
{
@@ -4155,7 +4157,7 @@ static void transferRelatedFunctionDocumentation()
MemberNameIterator rmni(*rmn);
for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
{
- //printf(" Member found: related=`%d'\n",rmd->isRelated());
+ //printf(" Member found: related='%d'\n",rmd->isRelated());
if ((rmd->isRelated() || rmd->isForeign()) && // related function
!md->isAlias() && !rmd->isAlias() &&
matchArguments2( md->getOuterScope(), md->getFileDef(), md->argumentList(),
@@ -4164,7 +4166,7 @@ static void transferRelatedFunctionDocumentation()
)
)
{
- //printf(" Found related member `%s'\n",md->name().data());
+ //printf(" Found related member '%s'\n",md->name().data());
if (rmd->relatedAlso())
md->setRelatedAlso(rmd->relatedAlso());
else if (rmd->isForeign())
@@ -4228,11 +4230,11 @@ static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,co
FileDef *fd=cd->getFileDef();
if (context && cd!=context)
{
- result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
+ result = const_cast<ClassDef*>(getResolvedClass(context,0,name,0,0,TRUE,TRUE));
}
if (result==0)
{
- result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
+ result = const_cast<ClassDef*>(getResolvedClass(cd,fd,name,0,0,TRUE,TRUE));
}
if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
{
@@ -4300,7 +4302,7 @@ static void findUsedClassesForClass(Entry *root,
while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,root->lang)!=-1)
{
// find the type (if any) that matches usedClassName
- ClassDef *typeCd = getResolvedClass(masterCd,
+ const ClassDef *typeCd = getResolvedClass(masterCd,
masterCd->getFileDef(),
usedClassName,
0,0,
@@ -4344,7 +4346,7 @@ static void findUsedClassesForClass(Entry *root,
if (arg->name==usedName) // type is a template argument
{
found=TRUE;
- Debug::print(Debug::Classes,0," New used class `%s'\n", qPrint(usedName));
+ Debug::print(Debug::Classes,0," New used class '%s'\n", qPrint(usedName));
ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
if (usedCd==0)
@@ -4361,7 +4363,7 @@ static void findUsedClassesForClass(Entry *root,
Doxygen::hiddenClasses->append(usedName,usedCd);
}
if (isArtificial) usedCd->setArtificial(TRUE);
- Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", qPrint(usedCd->name()));
+ Debug::print(Debug::Classes,0," Adding used class '%s' (1)\n", qPrint(usedCd->name()));
instanceCd->addUsedClass(usedCd,md->name(),md->protection());
usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
}
@@ -4377,7 +4379,7 @@ static void findUsedClassesForClass(Entry *root,
if (usedCd)
{
found=TRUE;
- Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", qPrint(usedCd->name()));
+ Debug::print(Debug::Classes,0," Adding used class '%s' (2)\n", qPrint(usedCd->name()));
instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
}
@@ -4397,7 +4399,7 @@ static void findUsedClassesForClass(Entry *root,
{
type+=md->argsString();
}
- Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", qPrint(type));
+ Debug::print(Debug::Classes,0," New undocumented used class '%s'\n", qPrint(type));
usedCd = createClassDef(
masterCd->getDefFileName(),masterCd->getDefLine(),
masterCd->getDefColumn(),
@@ -4409,7 +4411,7 @@ static void findUsedClassesForClass(Entry *root,
if (usedCd)
{
if (isArtificial) usedCd->setArtificial(TRUE);
- Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", qPrint(usedCd->name()));
+ Debug::print(Debug::Classes,0," Adding used class '%s' (3)\n", qPrint(usedCd->name()));
instanceCd->addUsedClass(usedCd,md->name(),md->protection());
usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
}
@@ -4673,7 +4675,7 @@ static bool findClassRelation(
QCString biName=bi->name;
bool explicitGlobalScope=FALSE;
- //printf("findClassRelation: biName=`%s'\n",biName.data());
+ //printf("findClassRelation: biName='%s'\n",biName.data());
if (biName.left(2)=="::") // explicit global scope
{
biName=biName.right(biName.length()-2);
@@ -4689,7 +4691,7 @@ static bool findClassRelation(
int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
do // try all parent scope prefixes, starting with the largest scope
{
- //printf("scopePrefix=`%s' biName=`%s'\n",
+ //printf("scopePrefix='%s' biName='%s'\n",
// scopeName.left(scopeOffset).data(),biName.data());
QCString baseClassName=biName;
@@ -4701,19 +4703,20 @@ static bool findClassRelation(
//baseClassName=stripTemplateSpecifiersFromScope
// (removeRedundantWhiteSpace(baseClassName),TRUE,
// &stripped);
- MemberDef *baseClassTypeDef=0;
+ const MemberDef *baseClassTypeDef=0;
QCString templSpec;
- ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
+ ClassDef *baseClass=const_cast<ClassDef*>(
+ getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
cd->getFileDef(),
baseClassName,
&baseClassTypeDef,
&templSpec,
mode==Undocumented,
TRUE
- );
+ ));
//printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
// baseClassName.data(),baseClass,cd,explicitGlobalScope);
- //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
+ //printf(" scope='%s' baseClassName='%s' baseClass=%s templSpec=%s\n",
// cd ? cd->name().data():"<none>",
// baseClassName.data(),
// baseClass?baseClass->name().data():"<none>",
@@ -4761,14 +4764,15 @@ static bool findClassRelation(
{
templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
- baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
- cd->getFileDef(),
- baseClassName,
- &baseClassTypeDef,
- 0, //&templSpec,
- mode==Undocumented,
- TRUE
- );
+ baseClass=const_cast<ClassDef*>(
+ getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
+ cd->getFileDef(),
+ baseClassName,
+ &baseClassTypeDef,
+ 0, //&templSpec,
+ mode==Undocumented,
+ TRUE
+ ));
//printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
// baseClass,baseClassName.data(),templSpec.data());
}
@@ -4797,14 +4801,15 @@ static bool findClassRelation(
QCString tmpTemplSpec;
// replace any namespace aliases
replaceNamespaceAliases(baseClassName,si);
- baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
+ baseClass=const_cast<ClassDef*>(
+ getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
cd->getFileDef(),
baseClassName,
&baseClassTypeDef,
&tmpTemplSpec,
mode==Undocumented,
TRUE
- );
+ ));
found=baseClass!=0 && baseClass!=cd;
if (found) templSpec = tmpTemplSpec;
}
@@ -4844,7 +4849,7 @@ static bool findClassRelation(
//printf("3. found=%d\n",found);
if (found)
{
- Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
+ Debug::print(Debug::Classes,0," Documented base class '%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
// add base class to this class
// if templSpec is not empty then we should "instantiate"
@@ -4899,7 +4904,7 @@ static bool findClassRelation(
else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
{
Debug::print(Debug::Classes,0,
- " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
+ " New undocumented base class '%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
);
baseClass=0;
@@ -4959,7 +4964,7 @@ static bool findClassRelation(
}
else
{
- Debug::print(Debug::Classes,0," Base class `%s' not found\n",qPrint(biName));
+ Debug::print(Debug::Classes,0," Base class '%s' not found\n",qPrint(biName));
}
}
else
@@ -4984,7 +4989,7 @@ static bool findClassRelation(
{
scopeOffset=0;
}
- //printf("new scopeOffset=`%d'",scopeOffset);
+ //printf("new scopeOffset='%d'",scopeOffset);
} while (scopeOffset>=0);
if (parentNode==0)
@@ -5329,8 +5334,8 @@ static void generateXRefPages()
}
//----------------------------------------------------------------------
-// Copy the documentation in entry `root' to member definition `md' and
-// set the function declaration of the member to `funcDecl'. If the boolean
+// Copy the documentation in entry 'root' to member definition 'md' and
+// set the function declaration of the member to 'funcDecl'. If the boolean
// over_load is set the standard overload text is added.
static void addMemberDocs(Entry *root,
@@ -5340,7 +5345,7 @@ static void addMemberDocs(Entry *root,
NamespaceSDict *
)
{
- //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
+ //printf("addMemberDocs: '%s'::'%s' '%s' funcDecl='%s' mSpec=%d\n",
// root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
QCString fDecl=funcDecl;
// strip extern specifier
@@ -5476,18 +5481,18 @@ static void addMemberDocs(Entry *root,
// find a class definition given the scope name and (optionally) a
// template list specifier
-static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
+static const ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
const char *scopeName)
{
- ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
+ const ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
return tcd;
}
//----------------------------------------------------------------------
-// Adds the documentation contained in `root' to a global function
-// with name `name' and argument list `args' (for overloading) and
-// function declaration `decl' to the corresponding member definition.
+// Adds the documentation contained in 'root' to a global function
+// with name 'name' and argument list 'args' (for overloading) and
+// function declaration 'decl' to the corresponding member definition.
static bool findGlobalMember(Entry *root,
const QCString &namespaceName,
@@ -5542,16 +5547,16 @@ static bool findGlobalMember(Entry *root,
if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
(nd && nd->name()==namespaceName) || // or in the same namespace
- viaUsingDirective // member in `using' namespace
+ viaUsingDirective // member in 'using' namespace
)
{
- Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
+ Debug::print(Debug::FindMembers,0,"4. Try to add member '%s' to scope '%s'\n",
qPrint(md->name()),qPrint(namespaceName));
NamespaceDef *rnd = 0;
if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
- ArgumentList *mdAl = md->argumentList();
+ const ArgumentList *mdAl = const_cast<const MemberDef *>(md)->argumentList();
bool matching=
(mdAl==0 && root->argList->count()==0) ||
md->isVariable() || md->isTypedef() || /* in case of function pointers */
@@ -5641,7 +5646,7 @@ static bool findGlobalMember(Entry *root,
)
{
warn(root->fileName,root->startLine,
- "documented symbol `%s' was not declared or defined.",decl
+ "documented symbol '%s' was not declared or defined.",decl
);
}
}
@@ -5822,7 +5827,7 @@ static void findMember(Entry *root,
)
{
Debug::print(Debug::FindMembers,0,
- "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
+ "findMember(root=%p,funcDecl='%s',related='%s',overload=%d,"
"isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
"spec=%lld lang=%x\n",
root,qPrint(funcDecl),qPrint(root->relates),overloaded,isFunc,root->mGrpId,
@@ -5891,7 +5896,7 @@ static void findMember(Entry *root,
" ::","::"
).stripWhiteSpace();
- //printf("funcDecl=`%s'\n",funcDecl.data());
+ //printf("funcDecl='%s'\n",funcDecl.data());
if (isFriend && funcDecl.left(6)=="class ")
{
//printf("friend class\n");
@@ -5906,18 +5911,18 @@ static void findMember(Entry *root,
else
{
// extract information from the declarations
- parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
+ parseFuncDecl(funcDecl,root->lang,scopeName,funcType,funcName,
funcArgs,funcTempList,exceptions
);
}
- //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
+ //printf("scopeName='%s' funcType='%s' funcName='%s' funcArgs='%s'\n",
// scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
// the class name can also be a namespace name, we decide this later.
// if a related class name is specified and the class name could
// not be derived from the function declaration, then use the
// related field.
- //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
+ //printf("scopeName='%s' className='%s' namespaceName='%s'\n",
// scopeName.data(),className.data(),namespaceName.data());
if (!root->relates.isEmpty())
{ // related member, prefix user specified scope
@@ -5993,13 +5998,13 @@ static void findMember(Entry *root,
// split scope into a namespace and a class part
extractNamespaceName(scopeName,className,namespaceName,TRUE);
- //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
+ //printf("scopeName='%s' className='%s' namespaceName='%s'\n",
// scopeName.data(),className.data(),namespaceName.data());
//namespaceName=removeAnonymousScopes(namespaceName);
if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
- //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
+ //printf("namespaceName='%s' className='%s'\n",namespaceName.data(),className.data());
// merge class and namespace scopes again
scopeName.resize(0);
if (!namespaceName.isEmpty())
@@ -6022,7 +6027,7 @@ static void findMember(Entry *root,
{
scopeName=className;
}
- //printf("new scope=`%s'\n",scopeName.data());
+ //printf("new scope='%s'\n",scopeName.data());
QCString tempScopeName=scopeName;
ClassDef *cd=getClass(scopeName);
@@ -6041,7 +6046,7 @@ static void findMember(Entry *root,
//printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
// scopeName.data(),cd,root->tArgLists,tempScopeName.data());
- //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+ //printf("scopeName='%s' className='%s'\n",scopeName.data(),className.data());
// rebuild the function declaration (needed to get the scope right).
if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
{
@@ -6062,7 +6067,7 @@ static void findMember(Entry *root,
{
funcDecl=tempScopeName+"::"+funcName+funcTempList;
}
- else // variable => add `argument' list
+ else // variable => add 'argument' list
{
funcDecl=tempScopeName+"::"+funcName+funcArgs;
}
@@ -6076,7 +6081,7 @@ static void findMember(Entry *root,
{
funcDecl=funcType+" "+funcName+funcTempList;
}
- else // variable => add `argument' list
+ else // variable => add 'argument' list
{
funcDecl=funcType+" "+funcName+funcArgs;
}
@@ -6099,16 +6104,16 @@ static void findMember(Entry *root,
Debug::print(Debug::FindMembers,0,
"findMember() Parse results:\n"
- " namespaceName=`%s'\n"
+ " namespaceName='%s'\n"
" className=`%s`\n"
- " funcType=`%s'\n"
- " funcSpec=`%s'\n"
- " funcName=`%s'\n"
- " funcArgs=`%s'\n"
- " funcTempList=`%s'\n"
- " funcDecl=`%s'\n"
- " related=`%s'\n"
- " exceptions=`%s'\n"
+ " funcType='%s'\n"
+ " funcSpec='%s'\n"
+ " funcName='%s'\n"
+ " funcArgs='%s'\n"
+ " funcTempList='%s'\n"
+ " funcDecl='%s'\n"
+ " related='%s'\n"
+ " exceptions='%s'\n"
" isRelated=%d\n"
" isMemberOf=%d\n"
" isFriend=%d\n"
@@ -6123,7 +6128,7 @@ static void findMember(Entry *root,
if (!funcName.isEmpty()) // function name is valid
{
Debug::print(Debug::FindMembers,0,
- "1. funcName=`%s'\n",funcName.data());
+ "1. funcName='%s'\n",funcName.data());
if (funcName.left(9)=="operator ") // strip class scope from cast operator
{
funcName = substitute(funcName,className+"::","");
@@ -6154,7 +6159,7 @@ static void findMember(Entry *root,
ClassDef *cd=md->getClassDef();
Debug::print(Debug::FindMembers,0,
"3. member definition found, "
- "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
+ "scope needed='%s' scope='%s' args='%s' fileName=%s\n",
qPrint(scopeName),cd ? qPrint(cd->name()) : "<none>",
qPrint(md->argsString()),
qPrint(root->fileName));
@@ -6223,7 +6228,7 @@ static void findMember(Entry *root,
}
Debug::print(Debug::FindMembers,0,
- "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
+ "5. matching '%s'<=>'%s' className=%s namespaceName=%s\n",
qPrint(argListToString(argList,TRUE)),qPrint(argListToString(root->argList,TRUE)),
qPrint(className),qPrint(namespaceName)
);
@@ -6477,7 +6482,7 @@ static void findMember(Entry *root,
declMd ? declMd->protection() : root->protection,
root->virt,root->stat,Member,
mtype,tArgList,root->argList,root->metaData);
- //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
+ //printf("new specialized member %s args='%s'\n",md->name().data(),funcArgs.data());
md->setTagInfo(root->tagInfo);
md->setLanguage(root->lang);
md->setId(root->id);
@@ -6540,7 +6545,7 @@ static void findMember(Entry *root,
// new overloaded member function
ArgumentList *tArgList =
getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
- //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
+ //printf("new related member %s args='%s'\n",md->name().data(),funcArgs.data());
MemberDef *md=createMemberDef(
root->fileName,root->startLine,root->startColumn,
funcType,funcName,funcArgs,exceptions,
@@ -6595,7 +6600,7 @@ static void findMember(Entry *root,
" scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
if (className.isEmpty()) className=root->relates;
ClassDef *cd;
- //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+ //printf("scopeName='%s' className='%s'\n",scopeName.data(),className.data());
if ((cd=getClass(scopeName)))
{
bool newMember=TRUE; // assume we have a new member
@@ -6668,7 +6673,7 @@ static void findMember(Entry *root,
funcDecl=funcType + " " + funcName;
}
- //printf("New related name `%s' `%d'\n",funcName.data(),
+ //printf("New related name '%s' '%d'\n",funcName.data(),
// root->argList ? (int)root->argList->count() : -1);
// first note that we pass:
@@ -6709,7 +6714,7 @@ static void findMember(Entry *root,
- //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
+ //printf("Related member name='%s' decl='%s' bodyLine='%d'\n",
// funcName.data(),funcDecl.data(),root->bodyLine);
// try to find the matching line number of the body from the
@@ -6721,10 +6726,10 @@ static void findMember(Entry *root,
if (rmn)
{
MemberNameIterator rmni(*rmn);
- MemberDef *rmd;
+ const MemberDef *rmd;
while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
{
- ArgumentList *rmdAl = rmd->argumentList();
+ const ArgumentList *rmdAl = rmd->argumentList();
// check for matching argument lists
if (
matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
@@ -6805,7 +6810,7 @@ static void findMember(Entry *root,
else
{
warn_undoc(root->fileName,root->startLine,
- "class `%s' for related function `%s' is not "
+ "class '%s' for related function '%s' is not "
"documented.",
className.data(),funcName.data()
);
@@ -6815,12 +6820,12 @@ static void findMember(Entry *root,
{
localObjCMethod:
ClassDef *cd;
- //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
+ //printf("scopeName='%s' className='%s'\n",scopeName.data(),className.data());
if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClass(scopeName)))
{
Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
" scopeName=%s className=%s\n",qPrint(root->name),qPrint(scopeName),qPrint(className));
- //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
+ //printf("Local objective C method '%s' of class '%s' found\n",root->name.data(),cd->name().data());
MemberDef *md=createMemberDef(
root->fileName,root->startLine,root->startColumn,
funcType,funcName,funcArgs,exceptions,
@@ -6872,14 +6877,14 @@ localObjCMethod:
if (className.isEmpty() && !globMem)
{
warn(root->fileName,root->startLine,
- "class for member `%s' cannot "
+ "class for member '%s' cannot "
"be found.", funcName.data()
);
}
else if (!className.isEmpty() && !globMem)
{
warn(root->fileName,root->startLine,
- "member `%s' of class `%s' cannot be found",
+ "member '%s' of class '%s' cannot be found",
funcName.data(),className.data());
}
}
@@ -6901,7 +6906,7 @@ static void filterMemberDocumentation(Entry *root)
{
int i=-1,l;
Debug::print(Debug::FindMembers,0,
- "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
+ "findMemberDocumentation(): root->type='%s' root->inside='%s' root->name='%s' root->args='%s' section=%x root->spec=%lld root->mGrpId=%d\n",
qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
);
//printf("root->parent()->name=%s\n",root->parent()->name.data());
@@ -6935,7 +6940,7 @@ static void filterMemberDocumentation(Entry *root)
//printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
if (root->section==Entry::MEMBERDOC_SEC)
{
- //printf("Documentation for inline member `%s' found args=`%s'\n",
+ //printf("Documentation for inline member '%s' found args='%s'\n",
// root->name.data(),root->args.data());
//if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
if (root->type.isEmpty())
@@ -6963,7 +6968,7 @@ static void filterMemberDocumentation(Entry *root)
)
)
{
- //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
+ //printf("Documentation for member '%s' found args='%s' excp='%s'\n",
// root->name.data(),root->args.data(),root->exception.data());
//if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
//printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
@@ -7087,7 +7092,7 @@ static void findEnums(Entry *root)
bool isGlobal;
bool isRelated=FALSE;
bool isMemberOf=FALSE;
- //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
+ //printf("Found enum with name '%s' relates=%s\n",root->name.data(),root->relates.data());
int i;
QCString name;
@@ -7124,7 +7129,7 @@ static void findEnums(Entry *root)
if (cd && !name.isEmpty()) // found a enum inside a compound
{
- //printf("Enum `%s'::`%s'\n",cd->name().data(),name.data());
+ //printf("Enum '%s'::'%s'\n",cd->name().data(),name.data());
fd=0;
mnsd=Doxygen::memberNameSDict;
isGlobal=FALSE;
@@ -7265,7 +7270,7 @@ static void addEnumValuesToEnums(Entry *root)
MemberNameSDict *mnsd=0;
bool isGlobal;
bool isRelated=FALSE;
- //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
+ //printf("Found enum with name '%s' relates=%s\n",root->name.data(),root->relates.data());
int i;
QCString name;
@@ -7301,21 +7306,21 @@ static void addEnumValuesToEnums(Entry *root)
if (cd && !name.isEmpty()) // found a enum inside a compound
{
- //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
+ //printf("Enum in class '%s'::'%s'\n",cd->name().data(),name.data());
fd=0;
mnsd=Doxygen::memberNameSDict;
isGlobal=FALSE;
}
else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
{
- //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
+ //printf("Enum in namespace '%s'::'%s'\n",nd->name().data(),name.data());
mnsd=Doxygen::functionNameSDict;
isGlobal=TRUE;
}
else // found a global enum
{
fd=root->fileDef();
- //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
+ //printf("Enum in file '%s': '%s'\n",fd->name().data(),name.data());
mnsd=Doxygen::functionNameSDict;
isGlobal=TRUE;
}
@@ -7330,7 +7335,7 @@ static void addEnumValuesToEnums(Entry *root)
MemberDef *md;
for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
{
- if (md->isEnumerate() && root->children())
+ if (!md->isAlias() && md->isEnumerate() && root->children())
{
//printf(" enum with %d children\n",root->children()->count());
EntryListIterator eli(*root->children()); // for each enum value
@@ -7482,7 +7487,7 @@ static void findEnumDocumentation(Entry *root)
&& root->name.at(0)!='@' // skip anonymous enums
)
{
- //printf("Found docs for enum with name `%s' in context %s\n",
+ //printf("Found docs for enum with name '%s' in context %s\n",
// root->name.data(),root->parent->name.data());
int i;
QCString name;
@@ -7491,7 +7496,7 @@ static void findEnumDocumentation(Entry *root)
{
name=root->name.right(root->name.length()-i-2); // extract name
scope=root->name.left(i); // extract scope
- //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
+ //printf("Scope='%s' Name='%s'\n",scope.data(),name.data());
}
else // just the name
{
@@ -7511,7 +7516,7 @@ static void findEnumDocumentation(Entry *root)
bool found=FALSE;
if (cd)
{
- //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
+ //printf("Enum: scope='%s' name='%s'\n",cd->name(),name.data());
QCString className=cd->name().copy();
MemberName *mn=Doxygen::memberNameSDict->find(name);
if (mn)
@@ -7602,7 +7607,7 @@ static void findEnumDocumentation(Entry *root)
if (!found)
{
warn(root->fileName,root->startLine,
- "Documentation for undefined enum `%s' found.",
+ "Documentation for undefined enum '%s' found.",
name.data()
);
}
@@ -7728,9 +7733,9 @@ static void vhdlCorrectMemberProperties()
//----------------------------------------------------------------------
-// computes the relation between all members. For each member `m'
-// the members that override the implementation of `m' are searched and
-// the member that `m' overrides is searched.
+// computes the relation between all members. For each member 'm'
+// the members that override the implementation of 'm' are searched and
+// the member that 'm' overrides is searched.
static void computeMemberRelations()
{
@@ -7750,7 +7755,7 @@ static void computeMemberRelations()
if (mcd && mcd->baseClasses())
{
const ClassDef *bmcd = bmd->getClassDef();
- //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
+ //printf("Check relation between '%s'::'%s' (%p) and '%s'::'%s' (%p)\n",
// mcd->name().data(),md->name().data(),md,
// bmcd->name().data(),bmd->name().data(),bmd
// );
@@ -7768,7 +7773,7 @@ static void computeMemberRelations()
//printf(" derived scope\n");
ArgumentList *bmdAl = bmd->argumentList();
ArgumentList *mdAl = md->argumentList();
- //printf(" Base argList=`%s'\n Super argList=`%s'\n",
+ //printf(" Base argList='%s'\n Super argList='%s'\n",
// argListToString(bmdAl.pointer()).data(),
// argListToString(mdAl.pointer()).data()
// );
@@ -8097,7 +8102,7 @@ static void addSourceReferences()
(fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
)
{
- //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
+ //printf("Found member '%s' in file '%s' at line '%d' def=%s\n",
// md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
}
@@ -8122,7 +8127,7 @@ static void addSourceReferences()
(fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
)
{
- //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
+ //printf("Found member '%s' in file '%s' at line '%d' def=%s\n",
// md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
}
@@ -8302,7 +8307,7 @@ static void inheritDocumentation()
MemberDef *md;
for (;(md=mni.current());++mni)
{
- //printf("%04d Member `%s'\n",count++,md->name().data());
+ //printf("%04d Member '%s'\n",count++,md->name().data());
if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
{ // no documentation yet
MemberDef *bmd = md->reimplements();
@@ -8518,7 +8523,7 @@ static void flushCachedTemplateRelations()
{
if (fmd->isTypedefValCached())
{
- ClassDef *cd = fmd->getCachedTypedefVal();
+ const ClassDef *cd = fmd->getCachedTypedefVal();
if (cd->isTemplate()) fmd->invalidateTypedefValCache();
}
}
@@ -8532,7 +8537,7 @@ static void flushCachedTemplateRelations()
{
if (fmd->isTypedefValCached())
{
- ClassDef *cd = fmd->getCachedTypedefVal();
+ const ClassDef *cd = fmd->getCachedTypedefVal();
if (cd->isTemplate()) fmd->invalidateTypedefValCache();
}
}
@@ -8595,7 +8600,7 @@ static void findDefineDocumentation(Entry *root)
root->section==Entry::DEFINE_SEC) && !root->name.isEmpty()
)
{
- //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
+ //printf("found define '%s' '%s' brief='%s' doc='%s'\n",
// root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
if (root->tagInfo && !root->name.isEmpty()) // define read from a tag file
@@ -8605,7 +8610,7 @@ static void findDefineDocumentation(Entry *root)
Public,Normal,FALSE,Member,MemberType_Define,0,0,"");
md->setTagInfo(root->tagInfo);
md->setLanguage(root->lang);
- //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
+ //printf("Searching for '%s' fd=%p\n",filePathName.data(),fd);
md->setFileDef(root->parent()->fileDef());
//printf("Adding member=%s\n",md->name().data());
MemberName *mn;
@@ -8950,7 +8955,7 @@ static void resolveUserReferences()
SectionInfo *si;
for (;(si=sdi.current());++sdi)
{
- //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
+ //printf("si->label='%s' si->definition=%s si->fileName='%s'\n",
// si->label.data(),si->definition?si->definition->name().data():"<none>",
// si->fileName.data());
PageDef *pd=0;
@@ -9252,7 +9257,7 @@ static void generateConfigFile(const char *configFile,bool shortList,
{
if (!updateOnly)
{
- msg("\n\nConfiguration file `%s' created.\n\n",configFile);
+ msg("\n\nConfiguration file '%s' created.\n\n",configFile);
msg("Now edit the configuration file and enter\n\n");
if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
msg(" doxygen %s\n\n",configFile);
@@ -9262,7 +9267,7 @@ static void generateConfigFile(const char *configFile,bool shortList,
}
else
{
- msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
+ msg("\n\nConfiguration file '%s' updated.\n\n",configFile);
}
}
}
@@ -9325,15 +9330,15 @@ static void readTagFile(Entry *root,const char *tl)
QFileInfo fi(fileName);
if (!fi.exists() || !fi.isFile())
{
- err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
+ err("Tag file '%s' does not exist or is not a file. Skipping it...\n",
fileName.data());
return;
}
if (!destName.isEmpty())
- msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
+ msg("Reading tag file '%s', location '%s'...\n",fileName.data(),destName.data());
else
- msg("Reading tag file `%s'...\n",fileName.data());
+ msg("Reading tag file '%s'...\n",fileName.data());
parseTagFile(root,fi.absFilePath().utf8());
}
@@ -9692,8 +9697,8 @@ static QCString resolveSymlink(QCString path)
static QDict<void> g_pathsVisited(1009);
//----------------------------------------------------------------------------
-// Read all files matching at least one pattern in `patList' in the
-// directory represented by `fi'.
+// Read all files matching at least one pattern in 'patList' in the
+// directory represented by 'fi'.
// The directory is read iff the recusiveFlag is set.
// The contents of all files is append to the input string
@@ -9803,7 +9808,7 @@ int readDir(QFileInfo *fi,
//----------------------------------------------------------------------------
// read a file or all files in a directory and append their contents to the
-// input string. The names of the files are appended to the `fiList' list.
+// input string. The names of the files are appended to the 'fiList' list.
int readFileOrDirectory(const char *s,
FileNameList *fnList,
@@ -10033,7 +10038,7 @@ void readAliases()
{
QCString name=alias.left(i).stripWhiteSpace();
QCString value=alias.right(alias.length()-i-1);
- //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
+ //printf("Alias: found name='%s' value='%s'\n",name.data(),value.data());
if (!name.isEmpty())
{
QCString *dn=Doxygen::aliasDict[name];
@@ -10122,9 +10127,9 @@ static void devUsage()
//----------------------------------------------------------------------------
// print the usage of doxygen
-static void usage(const char *name)
+static void usage(const char *name,const char *versionString)
{
- msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
+ msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2019\n\n",versionString);
msg("You can use doxygen in a number of ways:\n\n");
msg("1) Use doxygen to generate a template configuration file:\n");
msg(" %s [-s] -g [configName]\n\n",name);
@@ -10146,17 +10151,17 @@ static void usage(const char *name)
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("8) Use doxygen to show a list of built-in emojis.\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("If configName is omitted 'Doxyfile' will be used as a default.\n\n");
msg("-v print version string\n");
}
//----------------------------------------------------------------------------
-// read the argument of option `c' from the comment argument list and
-// update the option index `optind'.
+// read the argument of option 'c' from the comment argument list and
+// update the option index 'optind'.
static const char *getArg(int argc,char **argv,int &optind)
{
@@ -10341,6 +10346,16 @@ static int computeIdealCacheParam(uint v)
void readConfiguration(int argc, char **argv)
{
+ QCString versionString;
+ if (strlen(getGitVersion())>0)
+ {
+ versionString = QCString(getVersion())+" ("+getGitVersion()+")";
+ }
+ else
+ {
+ versionString = getVersion();
+ }
+
/**************************************************************************
* Handle arguments *
**************************************************************************/
@@ -10584,26 +10599,26 @@ void readConfiguration(int argc, char **argv)
g_dumpSymbolMap = TRUE;
break;
case 'v':
- msg("%s\n",versionString);
+ msg("%s\n",versionString.data());
cleanUpDoxygen();
exit(0);
break;
case '-':
if (qstrcmp(&argv[optind][2],"help")==0)
{
- usage(argv[0]);
+ usage(argv[0],versionString);
exit(0);
}
else if (qstrcmp(&argv[optind][2],"version")==0)
{
- msg("%s\n",versionString);
+ msg("%s\n",versionString.data());
cleanUpDoxygen();
exit(0);
}
else
{
err("Unknown option \"-%s\"\n",&argv[optind][1]);
- usage(argv[0]);
+ usage(argv[0],versionString);
exit(1);
}
break;
@@ -10619,12 +10634,12 @@ void readConfiguration(int argc, char **argv)
break;
case 'h':
case '?':
- usage(argv[0]);
+ usage(argv[0],versionString);
exit(0);
break;
default:
err("Unknown option \"-%c\"\n",argv[optind][1]);
- usage(argv[0]);
+ usage(argv[0],versionString);
exit(1);
}
optind++;
@@ -10654,7 +10669,7 @@ void readConfiguration(int argc, char **argv)
else
{
err("Doxyfile not found and no input file specified!\n");
- usage(argv[0]);
+ usage(argv[0],versionString);
exit(1);
}
}
@@ -10668,7 +10683,7 @@ void readConfiguration(int argc, char **argv)
else
{
err("configuration file %s not found!\n",argv[optind]);
- usage(argv[0]);
+ usage(argv[0],versionString);
exit(1);
}
}
@@ -11143,14 +11158,14 @@ void parseInput()
dir.setPath(QDir::currentDirPath());
if (!dir.mkdir(outputDirectory))
{
- err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
+ err("tag OUTPUT_DIRECTORY: Output directory '%s' does not "
"exist and cannot be created\n",outputDirectory.data());
cleanUpDoxygen();
exit(1);
}
else
{
- msg("Notice: Output directory `%s' does not exist. "
+ msg("Notice: Output directory '%s' does not exist. "
"I have created it for you.\n", outputDirectory.data());
}
dir.cd(outputDirectory);
@@ -11270,9 +11285,7 @@ void parseInput()
if (layoutFile.open(IO_ReadOnly))
{
msg("Parsing layout file %s...\n",layoutFileName.data());
- QTextStream t(&layoutFile);
- t.setEncoding(QTextStream::Latin1);
- LayoutDocManager::instance().parse(t,layoutFileName);
+ LayoutDocManager::instance().parse(layoutFileName);
}
else if (!defaultLayoutUsed)
{
@@ -11652,6 +11665,7 @@ void generateOutput()
}
initSearchIndexer();
+ initDot();
bool generateHtml = Config_getBool(GENERATE_HTML);
bool generateLatex = Config_getBool(GENERATE_LATEX);
diff --git a/src/doxygen.h b/src/doxygen.h
index 4ff8a56..c8eee7c 100644
--- a/src/doxygen.h
+++ b/src/doxygen.h
@@ -27,6 +27,7 @@
#include "membergroup.h"
#include "dirdef.h"
#include "memberlist.h"
+#include "docgroup.h"
class RefList;
class PageSList;
@@ -76,10 +77,10 @@ class StringDict : public QDict<QCString>
struct LookupInfo
{
LookupInfo() : classDef(0), typeDef(0) {}
- LookupInfo(ClassDef *cd,MemberDef *td,QCString ts,QCString rt)
+ LookupInfo(const ClassDef *cd,const MemberDef *td,QCString ts,QCString rt)
: classDef(cd), typeDef(td), templSpec(ts),resolvedType(rt) {}
- ClassDef *classDef;
- MemberDef *typeDef;
+ const ClassDef *classDef;
+ const MemberDef *typeDef;
QCString templSpec;
QCString resolvedType;
};
@@ -150,6 +151,7 @@ class Doxygen
static bool generatingXmlOutput;
static bool markdownSupport;
static GenericsSDict *genericsDict;
+ static DocGroup docGroup;
};
void initDoxygen();
diff --git a/src/filedef.cpp b/src/filedef.cpp
index f721c9f..9a82c8a 100644
--- a/src/filedef.cpp
+++ b/src/filedef.cpp
@@ -26,6 +26,7 @@
#include "language.h"
#include "outputlist.h"
#include "dot.h"
+#include "dotincldepgraph.h"
#include "message.h"
#include "docparser.h"
#include "searchindex.h"
@@ -1394,7 +1395,7 @@ void FileDefImpl::insertMember(MemberDef *md)
break;
default:
err("FileDefImpl::insertMembers(): "
- "member `%s' with class scope `%s' inserted in file scope `%s'!\n",
+ "member '%s' with class scope '%s' inserted in file scope '%s'!\n",
md->name().data(),
md->getClassDef() ? md->getClassDef()->name().data() : "<global>",
name().data());
diff --git a/src/filename.cpp b/src/filename.cpp
index ae3b596..637fe33 100644
--- a/src/filename.cpp
+++ b/src/filename.cpp
@@ -70,7 +70,7 @@ void FileName::generateDiskNames()
QCString path = fd->getPath();
if (!fd->isReference())
{
- //printf("i=%d j=%d fd->path=`%s' fd->name=`%s'\n",i,j,fd->path.left(i).data(),fd->name().data());
+ //printf("i=%d j=%d fd->path='%s' fd->name='%s'\n",i,j,fd->path.left(i).data(),fd->name().data());
if (i==(int)path.length())
{
//warning("Input file %s found multiple times!\n"
diff --git a/src/fortrancode.l b/src/fortrancode.l
index 926a3ff..3e443b5 100644
--- a/src/fortrancode.l
+++ b/src/fortrancode.l
@@ -269,7 +269,7 @@ static void endCodeLine()
g_code->endCodeLine();
}
-/*! write a code fragment `text' that may span multiple lines, inserting
+/*! write a code fragment 'text' that may span multiple lines, inserting
* line numbers for each line.
*/
static void codifyLines(char *text)
@@ -750,6 +750,10 @@ LANGUAGE_BIND_SPEC BIND{BS}"("{BS}C{BS}(,{BS}NAME{BS}"="{BS}"\""(.*)"\""{BS})?")
{
if ((yy_my_start == 1) && ((yytext[0] == 'c') || (yytext[0] == 'C'))) YY_FTN_REJECT;
}
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
/* font class is defined e.g. in doxygen.css */
startFontClass("keywordflow");
codifyLines(yytext);
diff --git a/src/fortranscanner.l b/src/fortranscanner.l
index 0ad03e3..ea75836 100644
--- a/src/fortranscanner.l
+++ b/src/fortranscanner.l
@@ -32,7 +32,7 @@
*
* - Do not like constructs like aa{BS} or {BS}bb. Should try to handle blank space
* with separate rule?: It seems it is often necessary, because we may parse something like
- * "functionA" or "MyInterface". So constructs like `(^|[ \t])interface({BS_}{ID})?/[ \t\n]'
+ * "functionA" or "MyInterface". So constructs like '(^|[ \t])interface({BS_}{ID})?/[ \t\n]'
* are desired.
*
* - Must track yyLineNr when using REJECT, unput() or similar commands.
@@ -2304,7 +2304,7 @@ static void initEntry()
current->virt = virt;
current->stat = gstat;
current->lang = SrcLangExt_Fortran;
- initGroupInfo(current);
+ Doxygen::docGroup.initGroupInfo(current);
}
/**
@@ -2712,7 +2712,7 @@ static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, Fortra
global_scope = rt;
startScope(rt); // implies current_root = rt
initParser();
- groupEnterFile(yyFileName,yyLineNr);
+ Doxygen::docGroup.enterFile(yyFileName,yyLineNr);
current = new Entry;
current->lang = SrcLangExt_Fortran;
@@ -2729,7 +2729,7 @@ static void parseMain(const char *fileName,const char *fileBuf,Entry *rt, Fortra
}
fortranscannerYYlex();
- groupLeaveFile(yyFileName,yyLineNr);
+ Doxygen::docGroup.leaveFile(yyFileName,yyLineNr);
if (global_scope && global_scope != (Entry *) -1) endScope(current_root, TRUE); // TRUE - global root
diff --git a/src/ftvhelp.h b/src/ftvhelp.h
index 4c3f986..9bcaa5b 100644
--- a/src/ftvhelp.h
+++ b/src/ftvhelp.h
@@ -73,7 +73,7 @@ class FTVHelp : public IndexIntf
};
#define JAVASCRIPT_LICENSE_TEXT \
- "/*\n@ @licstart The following is the entire license notice for the\n" \
+ "/*\n@licstart The following is the entire license notice for the\n" \
"JavaScript code in this file.\n\nCopyright (C) 1997-2019 by Dimitri van Heesch\n\n" \
"This program is free software; you can redistribute it and/or modify\n" \
"it under the terms of version 2 of the GNU General Public License as published by\n" \
diff --git a/src/groupdef.cpp b/src/groupdef.cpp
index 01c4cc4..9baf0aa 100644
--- a/src/groupdef.cpp
+++ b/src/groupdef.cpp
@@ -33,6 +33,7 @@
#include "docparser.h"
#include "searchindex.h"
#include "dot.h"
+#include "dotgroupcollaboration.h"
#include "vhdldocgen.h"
#include "layout.h"
#include "arguments.h"
@@ -532,7 +533,7 @@ bool GroupDefImpl::insertMember(MemberDef *md,bool docOnly)
break;
default:
err("GroupDefImpl::insertMembers(): "
- "member `%s' (typeid=%d) with scope `%s' inserted in group scope `%s'!\n",
+ "member '%s' (typeid=%d) with scope '%s' inserted in group scope '%s'!\n",
md->name().data(),md->memberType(),
md->getClassDef() ? md->getClassDef()->name().data() : "",
name().data());
@@ -650,7 +651,7 @@ bool GroupDefImpl::findGroup(const GroupDef *def) const
void GroupDefImpl::addGroup(const GroupDef *def)
{
- //printf("adding group `%s' to group `%s'\n",def->name().data(),name().data());
+ //printf("adding group '%s' to group '%s'\n",def->name().data(),name().data());
//if (Config_getBool(SORT_MEMBER_DOCS))
// groupList->inSort(def);
//else
@@ -1485,7 +1486,7 @@ void addNamespaceToGroups(Entry *root,NamespaceDef *nd)
for (;(g=gli.current());++gli)
{
GroupDef *gd=0;
- //printf("group `%s'\n",s->data());
+ //printf("group '%s'\n",s->data());
if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
{
if (gd->addNamespace(nd)) nd->makePartOfGroup(gd);
@@ -1502,7 +1503,7 @@ void addDirToGroups(Entry *root,DirDef *dd)
for (;(g=gli.current());++gli)
{
GroupDef *gd=0;
- //printf("group `%s'\n",g->groupname.data());
+ //printf("group '%s'\n",g->groupname.data());
if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
{
gd->addDir(dd);
diff --git a/src/htags.cpp b/src/htags.cpp
index 7f5870d..51cd6d9 100644
--- a/src/htags.cpp
+++ b/src/htags.cpp
@@ -91,6 +91,10 @@ bool Htags::execute(const QCString &htmldir)
//printf("CommandLine=[%s]\n",commandLine.data());
portable_sysTimerStart();
bool result=portable_system("htags",commandLine,FALSE)==0;
+ if (!result)
+ {
+ err("Problems running %s. Check your installation\n", "htags");
+ }
portable_sysTimerStop();
QDir::setCurrent(oldDir);
return result;
diff --git a/src/htmldocvisitor.cpp b/src/htmldocvisitor.cpp
index e7d9d57..e1ff3e9 100644
--- a/src/htmldocvisitor.cpp
+++ b/src/htmldocvisitor.cpp
@@ -403,9 +403,15 @@ void HtmlDocVisitor::visit(DocStyleChange *s)
case DocStyleChange::Strike:
if (s->enable()) m_t << "<strike" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</strike>";
break;
+ case DocStyleChange::Del:
+ if (s->enable()) m_t << "<del" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</del>";
+ break;
case DocStyleChange::Underline:
if (s->enable()) m_t << "<u" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</u>";
break;
+ case DocStyleChange::Ins:
+ if (s->enable()) m_t << "<ins" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</ins>";
+ break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "<em" << htmlAttribsToString(s->attribs()) << ">"; else m_t << "</em>";
break;
@@ -775,7 +781,7 @@ void HtmlDocVisitor::visit(DocInclude *inc)
void HtmlDocVisitor::visit(DocIncOperator *op)
{
- //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
+ //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
// op->type(),op->isFirst(),op->isLast(),op->text().data());
if (op->isFirst())
{
@@ -784,7 +790,9 @@ void HtmlDocVisitor::visit(DocIncOperator *op)
pushEnabled();
m_hide=TRUE;
}
- SrcLangExt langExt = getLanguageFromFileName(m_langExt);
+ QCString locLangExt = getFileNameExtension(op->includeFileName());
+ if (locLangExt.isEmpty()) locLangExt = m_langExt;
+ SrcLangExt langExt = getLanguageFromFileName(locLangExt);
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
@@ -796,7 +804,7 @@ void HtmlDocVisitor::visit(DocIncOperator *op)
QFileInfo cfi( op->includeFileName() );
fd = createFileDef( cfi.dirPath().utf8(), cfi.fileName().utf8() );
}
- Doxygen::parserManager->getParser(m_langExt)
+ Doxygen::parserManager->getParser(locLangExt)
->parseCode(
m_ci,
op->context(),
@@ -2028,10 +2036,8 @@ void HtmlDocVisitor::visitPre(DocParamList *pl)
m_t << "<td class=\"paramtype\">";
QListIterator<DocNode> li(pl->paramTypes());
DocNode *type;
- bool first=TRUE;
for (li.toFirst();(type=li.current());++li)
{
- if (!first) m_t << "&#160;|&#160;"; else first=FALSE;
if (type->kind()==DocNode::Kind_Word)
{
visit((DocWord*)type);
@@ -2040,6 +2046,10 @@ void HtmlDocVisitor::visitPre(DocParamList *pl)
{
visit((DocLinkedWord*)type);
}
+ else if (type->kind()==DocNode::Kind_Sep)
+ {
+ m_t << "&#160;" << ((DocSeparator *)type)->chars() << "&#160;";
+ }
}
m_t << "</td>";
}
@@ -2116,14 +2126,6 @@ void HtmlDocVisitor::visitPost(DocInternalRef *)
m_t << " ";
}
-void HtmlDocVisitor::visitPre(DocCopy *)
-{
-}
-
-void HtmlDocVisitor::visitPost(DocCopy *)
-{
-}
-
void HtmlDocVisitor::visitPre(DocText *)
{
}
diff --git a/src/htmldocvisitor.h b/src/htmldocvisitor.h
index 1c08c03..c994bac 100644
--- a/src/htmldocvisitor.h
+++ b/src/htmldocvisitor.h
@@ -127,8 +127,6 @@ class HtmlDocVisitor : public DocVisitor
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp
index 0067fa1..402b4e4 100644
--- a/src/htmlgen.cpp
+++ b/src/htmlgen.cpp
@@ -28,6 +28,12 @@
#include "diagram.h"
#include "version.h"
#include "dot.h"
+#include "dotcallgraph.h"
+#include "dotclassgraph.h"
+#include "dotdirdeps.h"
+#include "dotgfxhierarchytable.h"
+#include "dotgroupcollaboration.h"
+#include "dotincldepgraph.h"
#include "language.h"
#include "htmlhelp.h"
#include "docparser.h"
@@ -51,6 +57,7 @@ static QCString g_header;
static QCString g_footer;
static QCString g_mathjax_code;
+static bool DoxyCodeLineOpen = FALSE;
// note: this is only active if DISABLE_INDEX=YES, if DISABLE_INDEX is disabled, this
// part will be rendered inside menu.js
@@ -524,7 +531,12 @@ void HtmlCodeGenerator::writeLineNumber(const char *ref,const char *filename,
qsnprintf(lineNumber,maxLineNrStr,"%5d",l);
qsnprintf(lineAnchor,maxLineNrStr,"l%05d",l);
- m_t << "<div class=\"line\">";
+ if (!DoxyCodeLineOpen)
+ {
+ m_t << "<div class=\"line\">";
+ DoxyCodeLineOpen = TRUE;
+ }
+
m_t << "<a name=\"" << lineAnchor << "\"></a><span class=\"lineno\">";
if (filename)
{
@@ -655,12 +667,16 @@ void HtmlCodeGenerator::writeTooltip(const char *id, const DocLinkInfo &docInfo,
}
-void HtmlCodeGenerator::startCodeLine(bool hasLineNumbers)
+void HtmlCodeGenerator::startCodeLine(bool)
{
if (m_streamSet)
{
- if (!hasLineNumbers) m_t << "<div class=\"line\">";
m_col=0;
+ if (!DoxyCodeLineOpen)
+ {
+ m_t << "<div class=\"line\">";
+ DoxyCodeLineOpen = TRUE;
+ }
}
}
@@ -673,7 +689,11 @@ void HtmlCodeGenerator::endCodeLine()
m_t << " ";
m_col++;
}
- m_t << "</div>";
+ if (DoxyCodeLineOpen)
+ {
+ m_t << "</div>\n";
+ DoxyCodeLineOpen = FALSE;
+ }
}
}
@@ -858,7 +878,7 @@ void HtmlGenerator::writeSearchData(const char *dir)
{
searchCss = mgr.getAsString("search.css");
}
- searchCss = substitute(replaceColorMarkers(searchCss),"$doxygenversion",versionString);
+ searchCss = substitute(replaceColorMarkers(searchCss),"$doxygenversion",getVersion());
t << searchCss;
Doxygen::indexList->addStyleSheetFile("search/search.css");
}
@@ -867,20 +887,20 @@ void HtmlGenerator::writeSearchData(const char *dir)
void HtmlGenerator::writeStyleSheetFile(QFile &file)
{
FTextStream t(&file);
- t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",versionString));
+ t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",getVersion()));
}
void HtmlGenerator::writeHeaderFile(QFile &file, const char * /*cssname*/)
{
FTextStream t(&file);
- t << "<!-- HTML header for doxygen " << versionString << "-->" << endl;
+ t << "<!-- HTML header for doxygen " << getVersion() << "-->" << endl;
t << ResourceMgr::instance().getAsString("header.html");
}
void HtmlGenerator::writeFooterFile(QFile &file)
{
FTextStream t(&file);
- t << "<!-- HTML footer for doxygen " << versionString << "-->" << endl;
+ t << "<!-- HTML footer for doxygen " << getVersion() << "-->" << endl;
t << ResourceMgr::instance().getAsString("footer.html");
}
@@ -905,7 +925,7 @@ void HtmlGenerator::startFile(const char *name,const char *,
t << substituteHtmlKeywords(g_header,convertToHtml(filterTitle(title)),relPath);
t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
- << versionString << " -->" << endl;
+ << getVersion() << " -->" << endl;
//static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
static bool searchEngine = Config_getBool(SEARCHENGINE);
if (searchEngine /*&& !generateTreeView*/)
@@ -970,7 +990,7 @@ QCString HtmlGenerator::writeLogoAsString(const char *path)
"<img class=\"footer\" src=\"";
result += path;
result += "doxygen.png\" alt=\"doxygen\"/></a> ";
- result += versionString;
+ result += getVersion();
result += " ";
return result;
}
@@ -1023,7 +1043,7 @@ void HtmlGenerator::writeStyleInfo(int part)
//t << "H1 { text-align: center; border-width: thin none thin none;" << endl;
//t << " border-style : double; border-color : blue; padding-left : 1em; padding-right : 1em }" << endl;
- t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",versionString));
+ t << replaceColorMarkers(substitute(ResourceMgr::instance().getAsString("doxygen.css"),"$doxygenversion",getVersion()));
endPlainFile();
Doxygen::indexList->addStyleSheetFile("doxygen.css");
}
@@ -1775,7 +1795,7 @@ void HtmlGenerator::startDotGraph()
startSectionHeader(t,relPath,m_sectionCount);
}
-void HtmlGenerator::endDotGraph(const DotClassGraph &g)
+void HtmlGenerator::endDotGraph(DotClassGraph &g)
{
bool generateLegend = Config_getBool(GENERATE_LEGEND);
bool umlLook = Config_getBool(UML_LOOK);
@@ -1803,7 +1823,7 @@ void HtmlGenerator::startInclDepGraph()
startSectionHeader(t,relPath,m_sectionCount);
}
-void HtmlGenerator::endInclDepGraph(const DotInclDepGraph &g)
+void HtmlGenerator::endInclDepGraph(DotInclDepGraph &g)
{
endSectionHeader(t);
startSectionSummary(t,m_sectionCount);
@@ -1821,7 +1841,7 @@ void HtmlGenerator::startGroupCollaboration()
startSectionHeader(t,relPath,m_sectionCount);
}
-void HtmlGenerator::endGroupCollaboration(const DotGroupCollaboration &g)
+void HtmlGenerator::endGroupCollaboration(DotGroupCollaboration &g)
{
endSectionHeader(t);
startSectionSummary(t,m_sectionCount);
@@ -1839,7 +1859,7 @@ void HtmlGenerator::startCallGraph()
startSectionHeader(t,relPath,m_sectionCount);
}
-void HtmlGenerator::endCallGraph(const DotCallGraph &g)
+void HtmlGenerator::endCallGraph(DotCallGraph &g)
{
endSectionHeader(t);
startSectionSummary(t,m_sectionCount);
@@ -1857,7 +1877,7 @@ void HtmlGenerator::startDirDepGraph()
startSectionHeader(t,relPath,m_sectionCount);
}
-void HtmlGenerator::endDirDepGraph(const DotDirDeps &g)
+void HtmlGenerator::endDirDepGraph(DotDirDeps &g)
{
endSectionHeader(t);
startSectionSummary(t,m_sectionCount);
@@ -1870,7 +1890,7 @@ void HtmlGenerator::endDirDepGraph(const DotDirDeps &g)
m_sectionCount++;
}
-void HtmlGenerator::writeGraphicalHierarchy(const DotGfxHierarchyTable &g)
+void HtmlGenerator::writeGraphicalHierarchy(DotGfxHierarchyTable &g)
{
g.writeGraph(t,dir,fileName);
}
@@ -2441,7 +2461,7 @@ void HtmlGenerator::writeSearchPage()
t << substituteHtmlKeywords(g_header,"Search","");
t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
- << versionString << " -->" << endl;
+ << getVersion() << " -->" << endl;
t << "<script type=\"text/javascript\">\n";
t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
t << "var searchBox = new SearchBox(\"searchBox\", \""
@@ -2495,7 +2515,7 @@ void HtmlGenerator::writeExternalSearchPage()
t << substituteHtmlKeywords(g_header,"Search","");
t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
- << versionString << " -->" << endl;
+ << getVersion() << " -->" << endl;
t << "<script type=\"text/javascript\">\n";
t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&amp;dn=gpl-2.0.txt GPL-v2 */\n";
t << "var searchBox = new SearchBox(\"searchBox\", \""
@@ -2634,6 +2654,19 @@ void HtmlGenerator::endConstraintList()
t << "</div>" << endl;
}
+void HtmlGenerator::startCodeFragment()
+{
+ t << PREFRAG_START;
+}
+
+void HtmlGenerator::endCodeFragment()
+{
+ //endCodeLine checks is there is still an open code line, if so closes it.
+ endCodeLine();
+
+ t << PREFRAG_END;
+}
+
void HtmlGenerator::lineBreak(const char *style)
{
if (style)
diff --git a/src/htmlgen.h b/src/htmlgen.h
index 4bf975d..2db5b74 100644
--- a/src/htmlgen.h
+++ b/src/htmlgen.h
@@ -212,8 +212,8 @@ class HtmlGenerator : public OutputGenerator
void writeRuler() { t << "<hr/>"; }
void writeAnchor(const char *,const char *name)
{ t << "<a name=\"" << name <<"\" id=\"" << name << "\"></a>"; }
- void startCodeFragment() { t << PREFRAG_START; }
- void endCodeFragment() { t << PREFRAG_END; }
+ void startCodeFragment();
+ void endCodeFragment();
void startEmphasis() { t << "<em>"; }
void endEmphasis() { t << "</em>"; }
void startBold() { t << "<b>"; }
@@ -283,16 +283,16 @@ class HtmlGenerator : public OutputGenerator
void endDescTableData();
void startDotGraph();
- void endDotGraph(const DotClassGraph &g);
+ void endDotGraph(DotClassGraph &g);
void startInclDepGraph();
- void endInclDepGraph(const DotInclDepGraph &g);
+ void endInclDepGraph(DotInclDepGraph &g);
void startGroupCollaboration();
- void endGroupCollaboration(const DotGroupCollaboration &g);
+ void endGroupCollaboration(DotGroupCollaboration &g);
void startCallGraph();
- void endCallGraph(const DotCallGraph &g);
+ void endCallGraph(DotCallGraph &g);
void startDirDepGraph();
- void endDirDepGraph(const DotDirDeps &g);
- void writeGraphicalHierarchy(const DotGfxHierarchyTable &g);
+ void endDirDepGraph(DotDirDeps &g);
+ void writeGraphicalHierarchy(DotGfxHierarchyTable &g);
void startTextBlock(bool)
{ t << "<div class=\"textblock\">"; }
diff --git a/src/index.cpp b/src/index.cpp
index a577d9a..0631ee4 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -40,6 +40,7 @@
#include "htmlhelp.h"
#include "ftvhelp.h"
#include "dot.h"
+#include "dotgfxhierarchytable.h"
#include "pagedef.h"
#include "dirdef.h"
#include "vhdldocgen.h"
@@ -619,7 +620,7 @@ static void writeDirTreeNode(OutputList &ol, DirDef *dd, int level, FTVHelp* ftv
(tocExpand && // or toc expand and
dd->getFiles() && dd->getFiles()->count()>0 // there are files
);
- //printf("gd=`%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count());
+ //printf("gd='%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count());
if (addToIndex)
{
Doxygen::indexList->addContentsItem(isDir,dd->shortName(),dd->getReference(),dd->getOutputFileBase(),0,TRUE,TRUE);
@@ -4005,7 +4006,7 @@ static void writeGroupTreeNode(OutputList &ol, GroupDef *gd, int level, FTVHelp*
}
bool isDir = hasSubGroups || hasSubPages || numSubItems>0;
- //printf("gd=`%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count());
+ //printf("gd='%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count());
if (addToIndex)
{
Doxygen::indexList->addContentsItem(isDir,gd->groupTitle(),gd->getReference(),gd->getOutputFileBase(),0,isDir,TRUE);
@@ -4730,7 +4731,7 @@ static void writeIndex(OutputList &ol)
ol.parseText(/*projPrefix+*/theTranslator->trExceptionIndex());
ol.endIndexSection(isCompoundIndex);
}
- if (documentedFiles>0)
+ if (Config_getBool(SHOW_FILES) && (documentedFiles>0))
{
ol.startIndexSection(isFileIndex);
ol.parseText(/*projPrefix+*/theTranslator->trFileIndex());
diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp
index 2e979bd..a0bbf73 100644
--- a/src/latexdocvisitor.cpp
+++ b/src/latexdocvisitor.cpp
@@ -292,9 +292,11 @@ void LatexDocVisitor::visit(DocStyleChange *s)
if (s->enable()) m_t << "{\\bfseries{"; else m_t << "}}";
break;
case DocStyleChange::Strike:
+ case DocStyleChange::Del:
if (s->enable()) m_t << "\\sout{"; else m_t << "}";
break;
case DocStyleChange::Underline:
+ case DocStyleChange::Ins:
if (s->enable()) m_t << "\\uline{"; else m_t << "}";
break;
case DocStyleChange::Italic:
@@ -557,7 +559,7 @@ void LatexDocVisitor::visit(DocInclude *inc)
void LatexDocVisitor::visit(DocIncOperator *op)
{
- //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
+ //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
// op->type(),op->isFirst(),op->isLast(),op->text().data());
if (op->isFirst())
{
@@ -566,20 +568,22 @@ void LatexDocVisitor::visit(DocIncOperator *op)
pushEnabled();
m_hide = TRUE;
}
- SrcLangExt langExt = getLanguageFromFileName(m_langExt);
+ QCString locLangExt = getFileNameExtension(op->includeFileName());
+ if (locLangExt.isEmpty()) locLangExt = m_langExt;
+ SrcLangExt langExt = getLanguageFromFileName(locLangExt);
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide)
{
- FileDef *fd;
+ FileDef *fd = 0;
if (!op->includeFileName().isEmpty())
{
QFileInfo cfi( op->includeFileName() );
fd = createFileDef( cfi.dirPath().utf8(), cfi.fileName().utf8() );
}
- Doxygen::parserManager->getParser(m_langExt)
+ Doxygen::parserManager->getParser(locLangExt)
->parseCode(m_ci,op->context(),op->text(),langExt,
op->isExample(),op->exampleFile(),
fd, // fileDef
@@ -1584,10 +1588,8 @@ void LatexDocVisitor::visitPre(DocParamList *pl)
{
QListIterator<DocNode> li(pl->paramTypes());
DocNode *type;
- bool first=TRUE;
for (li.toFirst();(type=li.current());++li)
{
- if (!first) m_t << " | "; else first=FALSE;
if (type->kind()==DocNode::Kind_Word)
{
visit((DocWord*)type);
@@ -1596,6 +1598,10 @@ void LatexDocVisitor::visitPre(DocParamList *pl)
{
visit((DocLinkedWord*)type);
}
+ else if (type->kind()==DocNode::Kind_Sep)
+ {
+ m_t << " " << ((DocSeparator *)type)->chars() << " ";
+ }
}
if (useTable) m_t << " & ";
}
@@ -1696,14 +1702,6 @@ void LatexDocVisitor::visitPost(DocInternalRef *ref)
endLink(0,ref->file(),ref->anchor());
}
-void LatexDocVisitor::visitPre(DocCopy *)
-{
-}
-
-void LatexDocVisitor::visitPost(DocCopy *)
-{
-}
-
void LatexDocVisitor::visitPre(DocText *)
{
}
diff --git a/src/latexdocvisitor.h b/src/latexdocvisitor.h
index 7ea8ae1..71fb5be 100644
--- a/src/latexdocvisitor.h
+++ b/src/latexdocvisitor.h
@@ -128,8 +128,6 @@ class LatexDocVisitor : public DocVisitor
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
diff --git a/src/latexgen.cpp b/src/latexgen.cpp
index ad983a2..e6c6861 100644
--- a/src/latexgen.cpp
+++ b/src/latexgen.cpp
@@ -27,6 +27,11 @@
#include "language.h"
#include "version.h"
#include "dot.h"
+#include "dotcallgraph.h"
+#include "dotclassgraph.h"
+#include "dotdirdeps.h"
+#include "dotgroupcollaboration.h"
+#include "dotincldepgraph.h"
#include "pagedef.h"
#include "docparser.h"
#include "latexdocvisitor.h"
@@ -480,7 +485,7 @@ static void writeDefaultHeaderPart1(FTextStream &t)
if (Config_getBool(LATEX_BATCHMODE))
t << "\\batchmode\n";
- // to overcome problems wit too many open files
+ // to overcome problems with too many open files
t << "\\let\\mypdfximage\\pdfximage"
"\\def\\pdfximage{\\immediate\\mypdfximage}";
@@ -492,6 +497,14 @@ static void writeDefaultHeaderPart1(FTextStream &t)
documentClass = "book";
t << "\\documentclass[twoside]{" << documentClass << "}\n"
"\n";
+ t << "%% moved from doxygen.sty due to workaround for LaTex 2019 version and unmaintained tabu package\n"
+ "\\usepackage{ifthen}\n"
+ "\\ifx\\requestedLaTeXdate\\undefined\n"
+ "\\usepackage{array}\n"
+ "\\else\n"
+ "\\usepackage{array}[=2016-10-06]\n"
+ "\\fi\n"
+ "%%\n";
// Load required packages
t << "% Packages required by doxygen\n"
@@ -763,7 +776,7 @@ static void writeDefaultHeaderPart3(FTextStream &t)
{
// part 3
// Finalize project number
- t << " Doxygen " << versionString << "}\\\\\n";
+ t << " Doxygen " << getVersion() << "}\\\\\n";
if (Config_getBool(LATEX_TIMESTAMP))
t << "\\vspace*{0.5cm}\n"
"{\\small " << dateToString(TRUE) << "}\\\\\n";
@@ -832,7 +845,7 @@ static void writeDefaultFooter(FTextStream &t)
void LatexGenerator::writeHeaderFile(QFile &f)
{
FTextStream t(&f);
- t << "% Latex header for doxygen " << versionString << endl;
+ t << "% Latex header for doxygen " << getVersion() << endl;
writeDefaultHeaderPart1(t);
t << "Your title here";
writeDefaultHeaderPart2(t);
@@ -843,14 +856,14 @@ void LatexGenerator::writeHeaderFile(QFile &f)
void LatexGenerator::writeFooterFile(QFile &f)
{
FTextStream t(&f);
- t << "% Latex footer for doxygen " << versionString << endl;
+ t << "% Latex footer for doxygen " << getVersion() << endl;
writeDefaultFooter(t);
}
void LatexGenerator::writeStyleSheetFile(QFile &f)
{
FTextStream t(&f);
- t << "% stylesheet for doxygen " << versionString << endl;
+ t << "% stylesheet for doxygen " << getVersion() << endl;
writeDefaultStyleSheet(t);
}
@@ -1324,6 +1337,15 @@ void LatexGenerator::writeStyleInfo(int part)
startPlainFile("doxygen.sty");
writeDefaultStyleSheet(t);
endPlainFile();
+
+ // workaround for the problem caused by change in LaTeX in version 2019
+ // in the unmaintained tabu package
+ startPlainFile("tabu_doxygen.sty");
+ t << ResourceMgr::instance().getAsString("tabu_doxygen.sty");
+ endPlainFile();
+ startPlainFile("longtable_doxygen.sty");
+ t << ResourceMgr::instance().getAsString("longtable_doxygen.sty");
+ endPlainFile();
}
void LatexGenerator::newParagraph()
@@ -1376,7 +1398,7 @@ void LatexGenerator::startHtmlLink(const char *url)
if (Config_getBool(PDF_HYPERLINKS))
{
t << "\\href{";
- t << url;
+ t << latexFilterURL(url);
t << "}";
}
t << "{\\texttt{ ";
@@ -2034,7 +2056,7 @@ void LatexGenerator::startDotGraph()
newParagraph();
}
-void LatexGenerator::endDotGraph(const DotClassGraph &g)
+void LatexGenerator::endDotGraph(DotClassGraph &g)
{
g.writeGraph(t,GOF_EPS,EOF_LaTeX,Config_getString(LATEX_OUTPUT),fileName,relPath);
}
@@ -2043,7 +2065,7 @@ void LatexGenerator::startInclDepGraph()
{
}
-void LatexGenerator::endInclDepGraph(const DotInclDepGraph &g)
+void LatexGenerator::endInclDepGraph(DotInclDepGraph &g)
{
g.writeGraph(t,GOF_EPS,EOF_LaTeX,Config_getString(LATEX_OUTPUT),fileName,relPath);
}
@@ -2052,7 +2074,7 @@ void LatexGenerator::startGroupCollaboration()
{
}
-void LatexGenerator::endGroupCollaboration(const DotGroupCollaboration &g)
+void LatexGenerator::endGroupCollaboration(DotGroupCollaboration &g)
{
g.writeGraph(t,GOF_EPS,EOF_LaTeX,Config_getString(LATEX_OUTPUT),fileName,relPath);
}
@@ -2061,7 +2083,7 @@ void LatexGenerator::startCallGraph()
{
}
-void LatexGenerator::endCallGraph(const DotCallGraph &g)
+void LatexGenerator::endCallGraph(DotCallGraph &g)
{
g.writeGraph(t,GOF_EPS,EOF_LaTeX,Config_getString(LATEX_OUTPUT),fileName,relPath);
}
@@ -2070,7 +2092,7 @@ void LatexGenerator::startDirDepGraph()
{
}
-void LatexGenerator::endDirDepGraph(const DotDirDeps &g)
+void LatexGenerator::endDirDepGraph(DotDirDeps &g)
{
g.writeGraph(t,GOF_EPS,EOF_LaTeX,Config_getString(LATEX_OUTPUT),fileName,relPath);
}
diff --git a/src/latexgen.h b/src/latexgen.h
index b06a382..6430dbc 100644
--- a/src/latexgen.h
+++ b/src/latexgen.h
@@ -273,16 +273,16 @@ class LatexGenerator : public OutputGenerator
void lastIndexPage();
void startDotGraph();
- void endDotGraph(const DotClassGraph &);
+ void endDotGraph(DotClassGraph &);
void startInclDepGraph();
- void endInclDepGraph(const DotInclDepGraph &);
+ void endInclDepGraph(DotInclDepGraph &);
void startCallGraph();
void startGroupCollaboration();
- void endGroupCollaboration(const DotGroupCollaboration &g);
- void endCallGraph(const DotCallGraph &);
+ void endGroupCollaboration(DotGroupCollaboration &g);
+ void endCallGraph(DotCallGraph &);
void startDirDepGraph();
- void endDirDepGraph(const DotDirDeps &g);
- void writeGraphicalHierarchy(const DotGfxHierarchyTable &) {}
+ void endDirDepGraph(DotDirDeps &g);
+ void writeGraphicalHierarchy(DotGfxHierarchyTable &) {}
void startTextBlock(bool) {}
void endTextBlock(bool) {}
diff --git a/src/layout.cpp b/src/layout.cpp
index a5df6f4..38a55f4 100644
--- a/src/layout.cpp
+++ b/src/layout.cpp
@@ -1395,7 +1395,7 @@ class LayoutParser : public QXmlDefaultHandler
}
else
{
- err("Unexpected start tag `%s' found in scope='%s'!\n",
+ err("Unexpected start tag '%s' found in scope='%s'!\n",
name.data(),m_scope.data());
}
return TRUE;
@@ -1538,10 +1538,11 @@ void LayoutDocManager::clear(LayoutDocManager::LayoutPart p)
d->docEntries[(int)p].clear();
}
-void LayoutDocManager::parse(QTextStream &t,const char *fileName)
+void LayoutDocManager::parse(const char *fileName)
{
LayoutErrorHandler errorHandler(fileName);
- QXmlInputSource source( t );
+ QXmlInputSource source;
+ source.setData(fileToString(fileName));
QXmlSimpleReader reader;
reader.setContentHandler( &LayoutParser::instance() );
reader.setErrorHandler( &errorHandler );
@@ -1560,7 +1561,7 @@ void writeDefaultLayoutFile(const char *fileName)
return;
}
QTextStream t(&f);
- t << substitute(layout_default,"$doxygenversion",versionString);
+ t << substitute(layout_default,"$doxygenversion",getVersion());
}
//----------------------------------------------------------------------------------
diff --git a/src/layout.h b/src/layout.h
index b25aa4e..b1facf5 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -201,7 +201,7 @@ class LayoutDocManager
LayoutNavEntry *rootNavEntry() const;
/** Parses a user provided layout */
- void parse(QTextStream &t,const char *fileName);
+ void parse(const char *fileName);
void init();
private:
void addEntry(LayoutPart p,LayoutDocEntry*e);
diff --git a/src/mandocvisitor.cpp b/src/mandocvisitor.cpp
index 5c98c6f..997b24e 100644
--- a/src/mandocvisitor.cpp
+++ b/src/mandocvisitor.cpp
@@ -137,9 +137,11 @@ void ManDocVisitor::visit(DocStyleChange *s)
m_firstCol=FALSE;
break;
case DocStyleChange::Strike:
+ case DocStyleChange::Del:
/* not supported */
break;
case DocStyleChange::Underline: //underline is shown as emphasis
+ case DocStyleChange::Ins:
if (s->enable()) m_t << "\\fI"; else m_t << "\\fP";
m_firstCol=FALSE;
break;
@@ -367,8 +369,10 @@ void ManDocVisitor::visit(DocInclude *inc)
void ManDocVisitor::visit(DocIncOperator *op)
{
- SrcLangExt langExt = getLanguageFromFileName(m_langExt);
- //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
+ QCString locLangExt = getFileNameExtension(op->includeFileName());
+ if (locLangExt.isEmpty()) locLangExt = m_langExt;
+ SrcLangExt langExt = getLanguageFromFileName(locLangExt);
+ //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
// op->type(),op->isFirst(),op->isLast(),op->text().data());
if (op->isFirst())
{
@@ -386,14 +390,14 @@ void ManDocVisitor::visit(DocIncOperator *op)
popEnabled();
if (!m_hide)
{
- FileDef *fd;
+ FileDef *fd = 0;
if (!op->includeFileName().isEmpty())
{
QFileInfo cfi( op->includeFileName() );
fd = createFileDef( cfi.dirPath().utf8(), cfi.fileName().utf8() );
}
- Doxygen::parserManager->getParser(m_langExt)
+ Doxygen::parserManager->getParser(locLangExt)
->parseCode(m_ci,op->context(),op->text(),langExt,
op->isExample(),op->exampleFile(),
fd, // fileDef
@@ -569,7 +573,7 @@ void ManDocVisitor::visitPre(DocSimpleSect *s)
// special case 1: user defined title
if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
{
- m_t << ":\\fP" << endl;
+ m_t << "\\fP" << endl;
m_t << ".RS 4" << endl;
}
}
@@ -942,7 +946,7 @@ void ManDocVisitor::visitPre(DocParamSect *s)
default:
ASSERT(0);
}
- m_t << ":\\fP" << endl;
+ m_t << "\\fP" << endl;
m_t << ".RS 4" << endl;
}
@@ -1026,14 +1030,6 @@ void ManDocVisitor::visitPost(DocInternalRef *)
m_t << "\\fP";
}
-void ManDocVisitor::visitPre(DocCopy *)
-{
-}
-
-void ManDocVisitor::visitPost(DocCopy *)
-{
-}
-
void ManDocVisitor::visitPre(DocText *)
{
}
diff --git a/src/mandocvisitor.h b/src/mandocvisitor.h
index 8efc223..fa65424 100644
--- a/src/mandocvisitor.h
+++ b/src/mandocvisitor.h
@@ -128,8 +128,6 @@ class ManDocVisitor : public DocVisitor
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
diff --git a/src/mangen.h b/src/mangen.h
index 959a34c..d912923 100644
--- a/src/mangen.h
+++ b/src/mangen.h
@@ -207,16 +207,16 @@ class ManGenerator : public OutputGenerator
void endDescTableData() {}
void startDotGraph() {}
- void endDotGraph(const DotClassGraph &) {}
+ void endDotGraph(DotClassGraph &) {}
void startInclDepGraph() {}
- void endInclDepGraph(const DotInclDepGraph &) {}
+ void endInclDepGraph(DotInclDepGraph &) {}
void startGroupCollaboration() {}
- void endGroupCollaboration(const DotGroupCollaboration &) {}
+ void endGroupCollaboration(DotGroupCollaboration &) {}
void startCallGraph() {}
- void endCallGraph(const DotCallGraph &) {}
+ void endCallGraph(DotCallGraph &) {}
void startDirDepGraph() {}
- void endDirDepGraph(const DotDirDeps &) {}
- void writeGraphicalHierarchy(const DotGfxHierarchyTable &) {}
+ void endDirDepGraph(DotDirDeps &) {}
+ void writeGraphicalHierarchy(DotGfxHierarchyTable &) {}
void startTextBlock(bool) {}
void endTextBlock(bool) {}
diff --git a/src/markdown.cpp b/src/markdown.cpp
index 15f119b..2cbdcb5 100644
--- a/src/markdown.cpp
+++ b/src/markdown.cpp
@@ -979,7 +979,7 @@ static int processCodeSpan(GrowBuf &out, const char *data, int /*offset*/, int s
nl++;
}
else if (data[end]=='\'' && nb==1 && (end==size-1 || (end<size-1 && !isIdChar(end+1))))
- { // look for quoted strings like `some word', but skip strings like `it's cool`
+ { // look for quoted strings like 'some word', but skip strings like `it's cool`
QCString textFragment;
convertStringFragment(textFragment,data+nb,end-nb);
out.addStr("&lsquo;");
@@ -1900,7 +1900,7 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size)
}
// need at least one space on either side of the cell text in
// order for doxygen to do other formatting
- out.addStr("> " + cellText + " </" + cellTag + ">\n");
+ out.addStr("> " + cellText + "\n</" + cellTag + ">\n");
}
cellTag = "td";
cellClass = "class=\"markdownTableBody";
@@ -1982,7 +1982,7 @@ void writeOneLineHeaderOrRuler(GrowBuf &out,const char *data,int size)
out.addStr(data,size);
if (hasLineBreak(data,size))
{
- out.addStr("<br>");
+ out.addStr("<br>\n");
}
}
}
@@ -2439,7 +2439,10 @@ static QCString extractPageTitle(QCString &docs,QCString &id)
{
docs=docs.mid(end1);
}
- id = extractTitleId(title, 0);
+ else
+ {
+ id = extractTitleId(title, 0);
+ }
//printf("extractPageTitle(title='%s' docs='%s' id='%s')\n",title.data(),docs.data(),id.data());
return title;
}
@@ -2587,6 +2590,7 @@ void MarkdownFileParser::parseInput(const char *fileName,
QCString docs = fileBuf;
QCString id;
QCString title=extractPageTitle(docs,id).stripWhiteSpace();
+ if (QString(id).startsWith("autotoc_md")) id = "";
g_indentLevel=title.isEmpty() ? 0 : -1;
QCString titleFn = QFileInfo(fileName).baseName().utf8();
QCString fn = QFileInfo(fileName).fileName().utf8();
diff --git a/src/memberdef.cpp b/src/memberdef.cpp
index 3442229..9d6ac51 100644
--- a/src/memberdef.cpp
+++ b/src/memberdef.cpp
@@ -33,6 +33,7 @@
#include "defargs.h"
#include "docparser.h"
#include "dot.h"
+#include "dotcallgraph.h"
#include "searchindex.h"
#include "parserintf.h"
#include "objcache.h"
@@ -173,6 +174,7 @@ class MemberDefImpl : public DefinitionImpl, public MemberDef
virtual bool livesInsideEnum() const;
virtual bool isSliceLocal() const;
virtual bool isConstExpr() const;
+ virtual int numberOfFlowKeyWords() const;
virtual bool isFriendToHide() const;
virtual bool isNotFriend() const;
virtual bool isFunctionOrSignalSlot() const;
@@ -219,7 +221,7 @@ class MemberDefImpl : public DefinitionImpl, public MemberDef
virtual QCString getScopeString() const;
virtual ClassDef *getClassDefOfAnonymousType() const;
virtual bool isTypedefValCached() const;
- virtual ClassDef *getCachedTypedefVal() const;
+ virtual const ClassDef *getCachedTypedefVal() const;
virtual QCString getCachedTypedefTemplSpec() const;
virtual QCString getCachedResolvedTypedef() const;
virtual MemberDef *memberDefinition() const;
@@ -294,7 +296,7 @@ class MemberDefImpl : public DefinitionImpl, public MemberDef
virtual void addListReference(Definition *d);
virtual void setDocsForDefinition(bool b);
virtual void setGroupAlias(const MemberDef *md);
- virtual void cacheTypedefVal(ClassDef *val,const QCString &templSpec,const QCString &resolvedType);
+ virtual void cacheTypedefVal(const ClassDef *val,const QCString &templSpec,const QCString &resolvedType);
virtual void invalidateTypedefValCache();
virtual void invalidateCachedArgumentTypes();
virtual void setMemberDefinition(MemberDef *md);
@@ -307,6 +309,7 @@ class MemberDefImpl : public DefinitionImpl, public MemberDef
virtual void setBriefDescription(const char *b,const char *briefFile,int briefLine);
virtual void setInbodyDocumentation(const char *d,const char *inbodyFile,int inbodyLine);
virtual void setHidden(bool b);
+ virtual void incrementFlowKeyWordCount();
virtual void writeDeclaration(OutputList &ol,
const ClassDef *cd,const NamespaceDef *nd,const FileDef *fd,const GroupDef *gd,
bool inGroup, const ClassDef *inheritFrom=0,const char *inheritId=0) const;
@@ -604,6 +607,8 @@ class MemberDefAliasImpl : public DefinitionAliasImpl, public MemberDef
{ return getMdAlias()->isSliceLocal(); }
virtual bool isConstExpr() const
{ return getMdAlias()->isConstExpr(); }
+ virtual int numberOfFlowKeyWords() const
+ { return getMdAlias()->numberOfFlowKeyWords(); }
virtual bool isFriendToHide() const
{ return getMdAlias()->isFriendToHide(); }
virtual bool isNotFriend() const
@@ -692,7 +697,7 @@ class MemberDefAliasImpl : public DefinitionAliasImpl, public MemberDef
{ return getMdAlias()->getClassDefOfAnonymousType(); }
virtual bool isTypedefValCached() const
{ return getMdAlias()->isTypedefValCached(); }
- virtual ClassDef *getCachedTypedefVal() const
+ virtual const ClassDef *getCachedTypedefVal() const
{ return getMdAlias()->getCachedTypedefVal(); }
virtual QCString getCachedTypedefTemplSpec() const
{ return getMdAlias()->getCachedTypedefTemplSpec(); }
@@ -801,7 +806,7 @@ class MemberDefAliasImpl : public DefinitionAliasImpl, public MemberDef
virtual void addListReference(Definition *d) {}
virtual void setDocsForDefinition(bool b) {}
virtual void setGroupAlias(const MemberDef *md) {}
- virtual void cacheTypedefVal(ClassDef *val,const QCString &templSpec,const QCString &resolvedType) {}
+ virtual void cacheTypedefVal(const ClassDef *val,const QCString &templSpec,const QCString &resolvedType) {}
virtual void invalidateTypedefValCache() {}
virtual void invalidateCachedArgumentTypes() {}
virtual void setMemberDefinition(MemberDef *md) {}
@@ -819,6 +824,7 @@ class MemberDefAliasImpl : public DefinitionAliasImpl, public MemberDef
virtual MemberDef *createTemplateInstanceMember(ArgumentList *formalArgs,
ArgumentList *actualArgs) const
{ return getMdAlias()->createTemplateInstanceMember(formalArgs,actualArgs); }
+ virtual void incrementFlowKeyWordCount() {}
virtual void writeDeclaration(OutputList &ol,
const ClassDef *cd,const NamespaceDef *nd,const FileDef *fd,const GroupDef *gd,
@@ -928,7 +934,7 @@ static bool writeDefArgumentList(OutputList &ol,const Definition *scope,const Me
{
const ArgumentList *defArgList=(md->isDocsForDefinition()) ?
md->argumentList() : md->declArgumentList();
- //printf("writeDefArgumentList `%s' isDocsForDefinition()=%d\n",md->name().data(),md->isDocsForDefinition());
+ //printf("writeDefArgumentList '%s' isDocsForDefinition()=%d\n",md->name().data(),md->isDocsForDefinition());
if (defArgList==0 || md->isProperty())
{
return FALSE; // member has no function like argument list
@@ -1042,7 +1048,7 @@ static bool writeDefArgumentList(OutputList &ol,const Definition *scope,const Me
}
if (hasFuncPtrType) // argument type is a function pointer
{
- //printf("a->type=`%s' a->name=`%s'\n",a->type.data(),a->name.data());
+ //printf("a->type='%s' a->name='%s'\n",a->type.data(),a->name.data());
QCString n=a->type.left(vp);
if (hasFuncPtrType) n=a->type.left(wp);
if (md->isObjCMethod()) { n.prepend("("); n.append(")"); }
@@ -1363,7 +1369,7 @@ class MemberDefImpl::IMPL
MemberDef *groupMember;
bool isTypedefValCached;
- ClassDef *cachedTypedefValue;
+ const ClassDef *cachedTypedefValue;
QCString cachedTypedefTemplSpec;
QCString cachedResolvedType;
@@ -1407,6 +1413,7 @@ class MemberDefImpl::IMPL
QCString declFileName;
int declLine;
int declColumn;
+ int numberOfFlowKW;
};
MemberDefImpl::IMPL::IMPL() :
@@ -1422,7 +1429,8 @@ MemberDefImpl::IMPL::IMPL() :
category(0),
categoryRelation(0),
declLine(-1),
- declColumn(-1)
+ declColumn(-1),
+ numberOfFlowKW(0)
{
}
@@ -1559,7 +1567,7 @@ void MemberDefImpl::IMPL::init(Definition *def,
* \param e A string representing the throw clause of the members.
* \param p The protection context of the member, possible values are:
* \c Public, \c Protected, \c Private.
- * \param v The degree of `virtualness' of the member, possible values are:
+ * \param v The degree of 'virtualness' of the member, possible values are:
* \c Normal, \c Virtual, \c Pure.
* \param s A boolean that is true iff the member is static.
* \param r The relationship between the class and the member.
@@ -2102,13 +2110,13 @@ ClassDef *MemberDefImpl::getClassDefOfAnonymousType() const
cname=getNamespaceDef()->name();
}
QCString ltype(m_impl->type);
- // strip `static' keyword from ltype
+ // strip 'static' keyword from ltype
//if (ltype.left(7)=="static ") ltype=ltype.right(ltype.length()-7);
- // strip `friend' keyword from ltype
+ // strip 'friend' keyword from ltype
ltype.stripPrefix("friend ");
static QRegExp r("@[0-9]+");
int l,i=r.match(ltype,0,&l);
- //printf("ltype=`%s' i=%d\n",ltype.data(),i);
+ //printf("ltype='%s' i=%d\n",ltype.data(),i);
// search for the last anonymous scope in the member type
ClassDef *annoClassDef=0;
if (i!=-1) // found anonymous scope in type
@@ -2250,7 +2258,7 @@ QCString MemberDefImpl::getDeclType() const
{
ltype="using";
}
- // strip `friend' keyword from ltype
+ // strip 'friend' keyword from ltype
ltype.stripPrefix("friend ");
if (ltype=="@") // rename type from enum values
{
@@ -2359,7 +2367,7 @@ void MemberDefImpl::writeDeclaration(OutputList &ol,
{
ltype="using";
}
- // strip `friend' keyword from ltype
+ // strip 'friend' keyword from ltype
ltype.stripPrefix("friend ");
static QRegExp r("@[0-9]+");
@@ -2367,7 +2375,7 @@ void MemberDefImpl::writeDeclaration(OutputList &ol,
int l,i=r.match(ltype,0,&l);
if (i!=-1) // member has an anonymous type
{
- //printf("annoClassDef=%p annMemb=%p scopeName=`%s' anonymous=`%s'\n",
+ //printf("annoClassDef=%p annMemb=%p scopeName='%s' anonymous='%s'\n",
// annoClassDef,annMemb,cname.data(),ltype.mid(i,l).data());
if (annoClassDef) // type is an anonymous compound
@@ -2384,7 +2392,7 @@ void MemberDefImpl::writeDeclaration(OutputList &ol,
ol.writeNonBreakableSpace(3);
}
QCString varName=ltype.right(ltype.length()-ir).stripWhiteSpace();
- //printf(">>>>>> ltype=`%s' varName=`%s'\n",ltype.data(),varName.data());
+ //printf(">>>>>> ltype='%s' varName='%s'\n",ltype.data(),varName.data());
ol.docify("}");
if (varName.isEmpty() && (name().isEmpty() || name().at(0)=='@'))
{
@@ -2945,7 +2953,7 @@ void MemberDefImpl::_writeCallerGraph(OutputList &ol) const
{
warn_uncond("Caller graph for '%s' not generated, too many nodes. Consider increasing DOT_GRAPH_MAX_NODES.\n",qPrint(qualifiedName()));
}
- else if (!callerGraph.isTrivial() && !callerGraph.isTooBig())
+ else if (!callerGraph.isTrivial())
{
msg("Generating caller graph for function %s\n",qPrint(qualifiedName()));
ol.disable(OutputGenerator::Man);
@@ -3381,7 +3389,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
bool inFile = container->definitionType()==Definition::TypeFile;
bool hasDocs = isDetailedSectionVisible(inGroup,inFile);
- //printf("MemberDefImpl::writeDocumentation(): name=`%s' hasDocs=`%d' containerType=%d inGroup=%d sectionLinkable=%d\n",
+ //printf("MemberDefImpl::writeDocumentation(): name='%s' hasDocs='%d' containerType=%d inGroup=%d sectionLinkable=%d\n",
// name().data(),hasDocs,container->definitionType(),inGroup,isDetailedSectionLinkable());
//if ( !hasDocs ) return;
@@ -3423,7 +3431,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
QCString ldef = definition();
QCString title = name();
- //printf("member `%s' def=`%s'\n",name().data(),ldef.data());
+ //printf("member '%s' def='%s'\n",name().data(),ldef.data());
if (isEnumerate())
{
if (title.at(0)=='@')
@@ -3497,7 +3505,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
}
if (!found) // anonymous compound
{
- //printf("Anonymous compound `%s'\n",cname.data());
+ //printf("Anonymous compound '%s'\n",cname.data());
ol.startDoxyAnchor(cfname,cname,memAnchor,doxyName,doxyArgs);
ol.startMemberDoc(ciname,name(),memAnchor,name(),memCount,memTotal,showInline);
// search for the last anonymous compound name in the definition
@@ -3748,7 +3756,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml,
// )
)
{
- //printf("md=%s initLines=%d init=`%s'\n",name().data(),initLines,init.data());
+ //printf("md=%s initLines=%d init='%s'\n",name().data(),initLines,init.data());
ol.startBold();
if (m_impl->mtype==MemberType_Define)
ol.parseText(theTranslator->trDefineValue());
@@ -5625,7 +5633,7 @@ bool MemberDefImpl::isTypedefValCached() const
return m_impl->isTypedefValCached;
}
-ClassDef *MemberDefImpl::getCachedTypedefVal() const
+const ClassDef *MemberDefImpl::getCachedTypedefVal() const
{
return m_impl->cachedTypedefValue;
}
@@ -5907,7 +5915,7 @@ QCString MemberDefImpl::enumBaseType() const
}
-void MemberDefImpl::cacheTypedefVal(ClassDef*val, const QCString & templSpec, const QCString &resolvedType)
+void MemberDefImpl::cacheTypedefVal(const ClassDef*val, const QCString & templSpec, const QCString &resolvedType)
{
m_impl->isTypedefValCached=TRUE;
m_impl->cachedTypedefValue=val;
@@ -5969,6 +5977,16 @@ void MemberDefImpl::invalidateCachedArgumentTypes()
invalidateCachedTypesInArgumentList(m_impl->declArgList);
}
+void MemberDefImpl::incrementFlowKeyWordCount()
+{
+ m_impl->numberOfFlowKW++;
+}
+
+int MemberDefImpl::numberOfFlowKeyWords() const
+{
+ return m_impl->numberOfFlowKW;
+}
+
//----------------
QCString MemberDefImpl::displayName(bool) const
@@ -6052,7 +6070,7 @@ void combineDeclarationAndDefinition(MemberDef *mdec,MemberDef *mdef)
)
) /* match found */
{
- //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n",
+ //printf("Found member %s: definition in %s (doc='%s') and declaration in %s (doc='%s')\n",
// mn->memberName(),
// mdef->getFileDef()->name().data(),mdef->documentation().data(),
// mdec->getFileDef()->name().data(),mdec->documentation().data()
diff --git a/src/memberdef.h b/src/memberdef.h
index a742117..c81af80 100644
--- a/src/memberdef.h
+++ b/src/memberdef.h
@@ -182,6 +182,7 @@ class MemberDef : virtual public Definition
virtual bool livesInsideEnum() const = 0;
virtual bool isSliceLocal() const = 0;
virtual bool isConstExpr() const = 0;
+ virtual int numberOfFlowKeyWords() const = 0;
// derived getters
virtual bool isFriendToHide() const = 0;
@@ -248,7 +249,7 @@ class MemberDef : virtual public Definition
// cached typedef functions
virtual bool isTypedefValCached() const = 0;
- virtual ClassDef *getCachedTypedefVal() const = 0;
+ virtual const ClassDef *getCachedTypedefVal() const = 0;
virtual QCString getCachedTypedefTemplSpec() const = 0;
virtual QCString getCachedResolvedTypedef() const = 0;
@@ -280,6 +281,7 @@ class MemberDef : virtual public Definition
// ---- setters -----
//-----------------------------------------------------------------------------------
+
// set functions
virtual void setMemberType(MemberType t) = 0;
virtual void setDefinition(const char *d) = 0;
@@ -299,12 +301,13 @@ class MemberDef : virtual public Definition
virtual void setReadAccessor(const char *r) = 0;
virtual void setWriteAccessor(const char *w) = 0;
virtual void setTemplateSpecialization(bool b) = 0;
-
+
virtual void makeRelated() = 0;
virtual void makeForeign() = 0;
virtual void setInheritsDocsFrom(MemberDef *md) = 0;
virtual void setTagInfo(TagInfo *i) = 0;
virtual void setArgsString(const char *as) = 0;
+ virtual void incrementFlowKeyWordCount() = 0;
// relation to other members
virtual void setReimplements(MemberDef *md) = 0;
@@ -357,7 +360,7 @@ class MemberDef : virtual public Definition
virtual void setDocsForDefinition(bool b) = 0;
virtual void setGroupAlias(const MemberDef *md) = 0;
- virtual void cacheTypedefVal(ClassDef *val,const QCString &templSpec,const QCString &resolvedType) = 0;
+ virtual void cacheTypedefVal(const ClassDef *val,const QCString &templSpec,const QCString &resolvedType) = 0;
virtual void invalidateTypedefValCache() = 0;
virtual void invalidateCachedArgumentTypes() = 0;
diff --git a/src/membergroup.cpp b/src/membergroup.cpp
index 04689b4..a5852e4 100644
--- a/src/membergroup.cpp
+++ b/src/membergroup.cpp
@@ -59,7 +59,7 @@ MemberGroup::MemberGroup(const Definition *parent,
m_docFile = docFile;
m_docLine = docLine;
m_xrefListItems = 0;
- //printf("Member group docs=`%s'\n",doc.data());
+ //printf("Member group docs='%s'\n",doc.data());
}
MemberGroup::~MemberGroup()
diff --git a/src/memberlist.cpp b/src/memberlist.cpp
index 94bb916..1869808 100644
--- a/src/memberlist.cpp
+++ b/src/memberlist.cpp
@@ -183,7 +183,7 @@ void MemberList::countDecMembers()
m_numDecMembers++;
break;
default:
- err("Unknown member type found for member `%s'\n!",md->name().data());
+ err("Unknown member type found for member '%s'\n!",md->name().data());
}
}
}
@@ -433,7 +433,7 @@ void MemberList::writePlainDeclarations(OutputList &ol,
MemberListIterator mli(*this);
for ( ; (md=mli.current()); ++mli )
{
- //printf(">>> Member `%s' type=%d visible=%d\n",
+ //printf(">>> Member '%s' type=%d visible=%d\n",
// md->name().data(),md->memberType(),md->isBriefSectionVisible());
if ((inheritedFrom==0 || !md->isReimplementedBy(inheritedFrom)) &&
md->isBriefSectionVisible())
@@ -612,7 +612,7 @@ void MemberList::writeDeclarations(OutputList &ol,
if (ctx==0 && gd) ctx = gd;
if (ctx==0 && fd) ctx = fd;
- //printf("%p: MemberList::writeDeclaration(title=`%s',subtitle=`%s')=%d inheritedFrom=%p\n",
+ //printf("%p: MemberList::writeDeclaration(title='%s',subtitle='%s')=%d inheritedFrom=%p\n",
// this,title,subtitle,numDecMembers(),inheritedFrom);
int num = numDecMembers();
diff --git a/src/msc.cpp b/src/msc.cpp
index 29f96ac..51e23fa 100644
--- a/src/msc.cpp
+++ b/src/msc.cpp
@@ -24,6 +24,7 @@
#include "index.h"
#include "util.h"
#include "ftextstream.h"
+#include "mscgen_api.h"
#include <qdir.h>
@@ -50,7 +51,7 @@ static bool convertMapFile(FTextStream &t,const char *mapName,const QCString rel
bool isRef = FALSE;
int numBytes = f.readLine(buf,maxLineLen);
buf[numBytes-1]='\0';
- //printf("ReadLine `%s'\n",buf);
+ //printf("ReadLine '%s'\n",buf);
if (qstrncmp(buf,"rect",4)==0)
{
// obtain the url and the coordinates in the order used by graphviz-1.5
@@ -97,50 +98,38 @@ void writeMscGraphFromFile(const char *inFile,const char *outDir,
absOutFile+=portable_pathSeparator();
absOutFile+=outFile;
- // chdir to the output dir, so dot can find the font file.
- QCString oldDir = QDir::currentDirPath().utf8();
- // go to the html output directory (i.e. path)
- QDir::setCurrent(outDir);
- //printf("Going to dir %s\n",QDir::currentDirPath().data());
- QCString mscExe = Config_getString(MSCGEN_PATH)+"mscgen"+portable_commandExtension();
- QCString mscArgs;
- QCString imgName = outFile;
+ mscgen_format_t msc_format;
+ QCString imgName = absOutFile;
switch (format)
{
case MSC_BITMAP:
- mscArgs+="-T png";
+ msc_format = mscgen_format_png;
imgName+=".png";
break;
case MSC_EPS:
- mscArgs+="-T eps";
+ msc_format = mscgen_format_eps;
imgName+=".eps";
break;
case MSC_SVG:
- mscArgs+="-T svg";
+ msc_format = mscgen_format_svg;
imgName+=".svg";
break;
default:
- goto error; // I am not very fond of goto statements, but when in Rome...
+ return;
}
- mscArgs+=" -i \"";
- mscArgs+=inFile;
-
- mscArgs+="\" -o \"";
- mscArgs+=imgName+"\"";
- int exitCode;
-// printf("*** running: %s %s outDir:%s %s\n",mscExe.data(),mscArgs.data(),outDir,outFile);
- portable_sysTimerStart();
- if ((exitCode=portable_system(mscExe,mscArgs,FALSE))!=0)
+ int code;
+ if ((code=mscgen_generate(inFile,imgName,msc_format))!=0)
{
- portable_sysTimerStop();
- goto error;
+ err("Problems generating msc output (error=%s). Look for typos in you msc file %s\n",
+ mscgen_error2str(code),inFile);
+ return;
}
- portable_sysTimerStop();
+
if ( (format==MSC_EPS) && (Config_getBool(USE_PDFLATEX)) )
{
QCString epstopdfArgs(maxCmdLine);
epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"",
- outFile,outFile);
+ absOutFile.data(),absOutFile.data());
portable_sysTimerStart();
if (portable_system("epstopdf",epstopdfArgs)!=0)
{
@@ -151,45 +140,28 @@ void writeMscGraphFromFile(const char *inFile,const char *outDir,
Doxygen::indexList->addImageFile(imgName);
-error:
- QDir::setCurrent(oldDir);
}
-QCString getMscImageMapFromFile(const QCString& inFile, const QCString& outDir,
- const QCString& relPath,const QCString& context)
+static QCString getMscImageMapFromFile(const QCString& inFile, const QCString& outDir,
+ const QCString& relPath,const QCString& context,
+ bool writeSVGMap)
{
QCString outFile = inFile + ".map";
-
- //printf("*** running:getMscImageMapFromFile \n");
- // chdir to the output dir, so dot can find the font file.
- QCString oldDir = QDir::currentDirPath().utf8();
- // go to the html output directory (i.e. path)
- QDir::setCurrent(outDir);
- //printf("Going to dir %s\n",QDir::currentDirPath().data());
-
- QCString mscExe = Config_getString(MSCGEN_PATH)+"mscgen"+portable_commandExtension();
- QCString mscArgs = "-T ismap -i \"";
- mscArgs+=inFile;
- mscArgs+="\" -o \"";
- mscArgs+=outFile + "\"";
-
- int exitCode;
- portable_sysTimerStart();
- if ((exitCode=portable_system(mscExe,mscArgs,FALSE))!=0)
+ int code;
+ if ((code=mscgen_generate(inFile,outFile,
+ writeSVGMap ? mscgen_format_svgmap : mscgen_format_pngmap))!=0)
{
- portable_sysTimerStop();
- QDir::setCurrent(oldDir);
+ err("Problems generating msc output (error=%s). Look for typos in you msc file %s\n",
+ mscgen_error2str(code),inFile.data());
return "";
}
- portable_sysTimerStop();
-
+
QGString result;
FTextStream tmpout(&result);
convertMapFile(tmpout, outFile, relPath, context);
QDir().remove(outFile);
- QDir::setCurrent(oldDir);
return result.data();
}
@@ -217,7 +189,7 @@ void writeMscImageMapFromFile(FTextStream &t,const QCString &inFile,
default:
t << "unknown";
}
- QCString imap = getMscImageMapFromFile(inFile,outDir,relPath,context);
+ QCString imap = getMscImageMapFromFile(inFile,outDir,relPath,context,format==MSC_SVG);
if (!imap.isEmpty())
{
t << "\" alt=\""
diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp
index 1e526ae..38e5c04 100644
--- a/src/namespacedef.cpp
+++ b/src/namespacedef.cpp
@@ -518,7 +518,7 @@ void NamespaceDefImpl::insertMember(MemberDef *md)
break;
default:
err("NamespaceDefImpl::insertMembers(): "
- "member `%s' with class scope `%s' inserted in namespace scope `%s'!\n",
+ "member '%s' with class scope '%s' inserted in namespace scope '%s'!\n",
md->name().data(),
md->getClassDef() ? md->getClassDef()->name().data() : "",
name().data());
diff --git a/src/outputgen.h b/src/outputgen.h
index 8d9db65..322f4b7 100644
--- a/src/outputgen.h
+++ b/src/outputgen.h
@@ -150,7 +150,7 @@ class BaseOutputDocInterface : public CodeOutputInterface
Examples
};
- virtual bool parseText(const QCString &s) { return s.isEmpty(); }
+ virtual void parseText(const QCString &s) {}
/*! Start of a bullet list: e.g. \c \<ul\> in html. startItemListItem() is
* Used for the bullet items.
@@ -428,16 +428,16 @@ class OutputGenerator : public BaseOutputDocInterface
virtual void startClassDiagram() = 0;
virtual void endClassDiagram(const ClassDiagram &,const char *,const char *) = 0;
virtual void startDotGraph() = 0;
- virtual void endDotGraph(const DotClassGraph &g) = 0;
+ virtual void endDotGraph(DotClassGraph &g) = 0;
virtual void startInclDepGraph() = 0;
- virtual void endInclDepGraph(const DotInclDepGraph &g) = 0;
+ virtual void endInclDepGraph(DotInclDepGraph &g) = 0;
virtual void startGroupCollaboration() = 0;
- virtual void endGroupCollaboration(const DotGroupCollaboration &g) = 0;
+ virtual void endGroupCollaboration(DotGroupCollaboration &g) = 0;
virtual void startCallGraph() = 0;
- virtual void endCallGraph(const DotCallGraph &g) = 0;
+ virtual void endCallGraph(DotCallGraph &g) = 0;
virtual void startDirDepGraph() = 0;
- virtual void endDirDepGraph(const DotDirDeps &g) = 0;
- virtual void writeGraphicalHierarchy(const DotGfxHierarchyTable &g) = 0;
+ virtual void endDirDepGraph(DotDirDeps &g) = 0;
+ virtual void writeGraphicalHierarchy(DotGfxHierarchyTable &g) = 0;
virtual void startQuickIndices() = 0;
virtual void endQuickIndices() = 0;
virtual void writeSplitBar(const char *) = 0;
diff --git a/src/outputlist.cpp b/src/outputlist.cpp
index 1d6db55..daf3270 100644
--- a/src/outputlist.cpp
+++ b/src/outputlist.cpp
@@ -128,14 +128,14 @@ void OutputList::popGeneratorState()
}
}
-bool OutputList::generateDoc(const char *fileName,int startLine,
+void OutputList::generateDoc(const char *fileName,int startLine,
const Definition *ctx,const MemberDef * md,
const QCString &docStr,bool indexWords,
bool isExample,const char *exampleName,
bool singleLine,bool linkFromIndex)
{
int count=0;
- if (docStr.isEmpty()) return TRUE;
+ if (docStr.isEmpty()) return;
QListIterator<OutputGenerator> it(m_outputs);
OutputGenerator *og;
@@ -143,20 +143,17 @@ bool OutputList::generateDoc(const char *fileName,int startLine,
{
if (og->isEnabled()) count++;
}
- if (count==0) return TRUE; // no output formats enabled.
+ // we want to validate irrespective of the number of output formats
+ // specified as:
+ // - when only XML format there should be warnings as well (XML has its own write routines)
+ // - no formats there should be warnings as well
DocRoot *root=0;
root = validatingParseDoc(fileName,startLine,
ctx,md,docStr,indexWords,isExample,exampleName,
singleLine,linkFromIndex);
-
- writeDoc(root,ctx,md);
-
- bool isEmpty = root->isEmpty();
-
+ if (count>0) writeDoc(root,ctx,md);
delete root;
-
- return isEmpty;
}
void OutputList::writeDoc(DocRoot *root,const Definition *ctx,const MemberDef *md)
@@ -172,7 +169,7 @@ void OutputList::writeDoc(DocRoot *root,const Definition *ctx,const MemberDef *m
VhdlDocGen::setFlowMember(0);
}
-bool OutputList::parseText(const QCString &textStr)
+void OutputList::parseText(const QCString &textStr)
{
int count=0;
QListIterator<OutputGenerator> it(m_outputs);
@@ -181,20 +178,22 @@ bool OutputList::parseText(const QCString &textStr)
{
if (og->isEnabled()) count++;
}
- if (count==0) return TRUE; // no output formats enabled.
+ // we want to validate irrespective of the number of output formats
+ // specified as:
+ // - when only XML format there should be warnings as well (XML has its own write routines)
+ // - no formats there should be warnings as well
DocText *root = validatingParseText(textStr);
- for (it.toFirst();(og=it.current());++it)
+ if (count>0)
{
- if (og->isEnabled()) og->writeDoc(root,0,0);
+ for (it.toFirst();(og=it.current());++it)
+ {
+ if (og->isEnabled()) og->writeDoc(root,0,0);
+ }
}
- bool isEmpty = root->isEmpty();
-
delete root;
-
- return isEmpty;
}
@@ -316,12 +315,12 @@ void OutputList::forall(void (OutputGenerator::*func)(a1,a2,a3,a4,a5,a6,a7,a8),a
FORALL1(const char *a1,a1)
FORALL1(char a1,a1)
FORALL1(int a1,a1)
-FORALL1(const DotClassGraph &a1,a1)
-FORALL1(const DotInclDepGraph &a1,a1)
-FORALL1(const DotCallGraph &a1,a1)
-FORALL1(const DotDirDeps &a1,a1)
-FORALL1(const DotGfxHierarchyTable &a1,a1)
-FORALL1(const DotGroupCollaboration &a1,a1)
+FORALL1(DotClassGraph &a1,a1)
+FORALL1(DotInclDepGraph &a1,a1)
+FORALL1(DotCallGraph &a1,a1)
+FORALL1(DotDirDeps &a1,a1)
+FORALL1(DotGfxHierarchyTable &a1,a1)
+FORALL1(DotGroupCollaboration &a1,a1)
FORALL1(SectionTypes a1,a1)
#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE)
FORALL1(bool a1,a1)
diff --git a/src/outputlist.h b/src/outputlist.h
index 1371b3a..2a83020 100644
--- a/src/outputlist.h
+++ b/src/outputlist.h
@@ -74,13 +74,12 @@ class OutputList : public OutputDocInterface
// OutputDocInterface implementation
//////////////////////////////////////////////////
- bool generateDoc(const char *fileName,int startLine,
+ void generateDoc(const char *fileName,int startLine,
const Definition *ctx,const MemberDef *md,const QCString &docStr,
bool indexWords,bool isExample,const char *exampleName=0,
bool singleLine=FALSE,bool linkFromIndex=FALSE);
void writeDoc(DocRoot *root,const Definition *ctx,const MemberDef *md);
- bool parseText(const QCString &textStr);
-
+ void parseText(const QCString &textStr);
void startIndexSection(IndexSections is)
{ forall(&OutputGenerator::startIndexSection,is); }
@@ -391,25 +390,25 @@ class OutputList : public OutputDocInterface
{ forall(&OutputGenerator::endDescTableData); }
void startDotGraph()
{ forall(&OutputGenerator::startDotGraph); }
- void endDotGraph(const DotClassGraph &g)
+ void endDotGraph(DotClassGraph &g)
{ forall(&OutputGenerator::endDotGraph,g); }
void startInclDepGraph()
{ forall(&OutputGenerator::startInclDepGraph); }
- void endInclDepGraph(const DotInclDepGraph &g)
+ void endInclDepGraph(DotInclDepGraph &g)
{ forall(&OutputGenerator::endInclDepGraph,g); }
void startCallGraph()
{ forall(&OutputGenerator::startCallGraph); }
- void endCallGraph(const DotCallGraph &g)
+ void endCallGraph(DotCallGraph &g)
{ forall(&OutputGenerator::endCallGraph,g); }
void startDirDepGraph()
{ forall(&OutputGenerator::startDirDepGraph); }
- void endDirDepGraph(const DotDirDeps &g)
+ void endDirDepGraph(DotDirDeps &g)
{ forall(&OutputGenerator::endDirDepGraph,g); }
void startGroupCollaboration()
{ forall(&OutputGenerator::startGroupCollaboration); }
- void endGroupCollaboration(const DotGroupCollaboration &g)
+ void endGroupCollaboration(DotGroupCollaboration &g)
{ forall(&OutputGenerator::endGroupCollaboration,g); }
- void writeGraphicalHierarchy(const DotGfxHierarchyTable &g)
+ void writeGraphicalHierarchy(DotGfxHierarchyTable &g)
{ forall(&OutputGenerator::writeGraphicalHierarchy,g); }
void startTextBlock(bool dense=FALSE)
{ forall(&OutputGenerator::startTextBlock,dense); }
@@ -520,12 +519,12 @@ class OutputList : public OutputDocInterface
FORALLPROTO1(char);
FORALLPROTO1(IndexSections);
FORALLPROTO1(int);
- FORALLPROTO1(const DotClassGraph &);
- FORALLPROTO1(const DotInclDepGraph &);
- FORALLPROTO1(const DotCallGraph &);
- FORALLPROTO1(const DotGroupCollaboration &);
- FORALLPROTO1(const DotDirDeps &);
- FORALLPROTO1(const DotGfxHierarchyTable &);
+ FORALLPROTO1(DotClassGraph &);
+ FORALLPROTO1(DotInclDepGraph &);
+ FORALLPROTO1(DotCallGraph &);
+ FORALLPROTO1(DotGroupCollaboration &);
+ FORALLPROTO1(DotDirDeps &);
+ FORALLPROTO1(DotGfxHierarchyTable &);
FORALLPROTO1(SectionTypes);
#if defined(HAS_BOOL_TYPE) || defined(Q_HAS_BOOL_TYPE)
FORALLPROTO1(bool);
diff --git a/src/perlmodgen.cpp b/src/perlmodgen.cpp
index 3813c56..a288e0e 100644
--- a/src/perlmodgen.cpp
+++ b/src/perlmodgen.cpp
@@ -388,8 +388,6 @@ public:
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
@@ -642,7 +640,9 @@ void PerlModDocVisitor::visit(DocStyleChange *s)
{
case DocStyleChange::Bold: style = "bold"; break;
case DocStyleChange::Strike: style = "strike"; break;
+ case DocStyleChange::Del: style = "del"; break;
case DocStyleChange::Underline: style = "underline"; break;
+ case DocStyleChange::Ins: style = "ins"; break;
case DocStyleChange::Italic: style = "italic"; break;
case DocStyleChange::Code: style = "code"; break;
case DocStyleChange::Subscript: style = "subscript"; break;
@@ -749,7 +749,7 @@ void PerlModDocVisitor::visit(DocInclude *inc)
void PerlModDocVisitor::visit(DocIncOperator *)
{
#if 0
- //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
+ //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
// op->type(),op->isFirst(),op->isLast(),op->text().data());
if (op->isFirst())
{
@@ -1385,14 +1385,6 @@ void PerlModDocVisitor::visitPost(DocInternalRef *)
closeItem();
}
-void PerlModDocVisitor::visitPre(DocCopy *)
-{
-}
-
-void PerlModDocVisitor::visitPost(DocCopy *)
-{
-}
-
void PerlModDocVisitor::visitPre(DocText *)
{
}
@@ -2283,13 +2275,13 @@ bool PerlModGenerator::createOutputDir(QDir &perlModDir)
dir.setPath(QDir::currentDirPath());
if (!dir.mkdir(outputDirectory))
{
- err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
+ err("tag OUTPUT_DIRECTORY: Output directory '%s' does not "
"exist and cannot be created\n",outputDirectory.data());
exit(1);
}
else
{
- msg("Notice: Output directory `%s' does not exist. "
+ msg("Notice: Output directory '%s' does not exist. "
"I have created it for you.\n", outputDirectory.data());
}
dir.cd(outputDirectory);
diff --git a/src/portable.cpp b/src/portable.cpp
index 3dccaed..3d64638 100644
--- a/src/portable.cpp
+++ b/src/portable.cpp
@@ -396,7 +396,7 @@ const char *portable_commandExtension()
bool portable_fileSystemIsCaseSensitive()
{
-#if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__)
+#if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__) || defined(__CYGWIN__)
return FALSE;
#else
return TRUE;
@@ -463,7 +463,18 @@ void portable_correct_path(void)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
const char *p = portable_getenv("PATH");
+ if (!p) return; // no path nothing to correct
QCString result = substitute(p,'/','\\');
if (result!=p) portable_setenv("PATH",result.data());
#endif
}
+
+void portable_unlink(const char *fileName)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ _unlink(fileName);
+#else
+ unlink(fileName);
+#endif
+}
+
diff --git a/src/portable.h b/src/portable.h
index c5578a3..83f90ef 100644
--- a/src/portable.h
+++ b/src/portable.h
@@ -23,6 +23,7 @@ void portable_unsetenv(const char *variable);
portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence);
portable_off_t portable_ftell(FILE *f);
FILE * portable_fopen(const char *fileName,const char *mode);
+void portable_unlink(const char *fileName);
char portable_pathSeparator();
char portable_pathListSeparator();
const char * portable_ghostScriptCommand();
diff --git a/src/pre.l b/src/pre.l
index ca2fe2b..596108f 100644
--- a/src/pre.l
+++ b/src/pre.l
@@ -694,7 +694,7 @@ static QCString stringize(const QCString &s)
}
}
}
- //printf("stringize `%s'->`%s'\n",s.data(),result.data());
+ //printf("stringize '%s'->'%s'\n",s.data(),result.data());
return result;
}
@@ -705,19 +705,19 @@ static QCString stringize(const QCString &s)
*/
static void processConcatOperators(QCString &expr)
{
- //printf("processConcatOperators: in=`%s'\n",expr.data());
+ //printf("processConcatOperators: in='%s'\n",expr.data());
QRegExp r("[ \\t\\n]*##[ \\t\\n]*");
int l,n,i=0;
if (expr.isEmpty()) return;
while ((n=r.match(expr,i,&l))!=-1)
{
- //printf("Match: `%s'\n",expr.data()+i);
+ //printf("Match: '%s'\n",expr.data()+i);
if (n+l+1<(int)expr.length() && expr.at(n+l)=='@' && expr.at(n+l+1)=='-')
{
// remove no-rescan marker after ID
l+=2;
}
- //printf("found `%s'\n",expr.mid(n,l).data());
+ //printf("found '%s'\n",expr.mid(n,l).data());
// remove the ## operator and the surrounding whitespace
expr=expr.left(n)+expr.right(expr.length()-n-l);
int k=n-1;
@@ -730,7 +730,7 @@ static void processConcatOperators(QCString &expr)
}
i=n;
}
- //printf("processConcatOperators: out=`%s'\n",expr.data());
+ //printf("processConcatOperators: out='%s'\n",expr.data());
}
static void yyunput (int c,char *buf_ptr );
@@ -775,7 +775,7 @@ static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int
unputChar(expr,rest,j,' ');
return FALSE;
}
- getNextChar(expr,rest,j); // eat the `(' character
+ getNextChar(expr,rest,j); // eat the '(' character
QDict<QCString> argTable; // list of arguments
argTable.setAutoDelete(TRUE);
@@ -955,13 +955,13 @@ static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int
if (key.length()>1 && (subst=argTable[key]))
{
QCString substArg=*subst;
- //printf("substArg=`%s'\n",substArg.data());
+ //printf("substArg='%s'\n",substArg.data());
// only if no ## operator is before or after the argument
// marker we do macro expansion.
if (!hash) expandExpression(substArg,0,0);
if (inString)
{
- //printf("`%s'=stringize(`%s')\n",stringize(*subst).data(),subst->data());
+ //printf("'%s'=stringize('%s')\n",stringize(*subst).data(),subst->data());
// if the marker is inside a string (because a # was put
// before the macro name) we must escape " and \ characters
@@ -1000,7 +1000,7 @@ static bool replaceFunctionMacro(const QCString &expr,QCString *rest,int pos,int
}
len=j-pos;
result=resExpr;
- //printf("result after substitution `%s' expr=`%s'\n",
+ //printf("result after substitution '%s' expr='%s'\n",
// result.data(),expr.mid(pos,len).data());
return TRUE;
}
@@ -1089,7 +1089,12 @@ static void expandExpression(QCString &expr,QCString *rest,int pos)
if (g_expandedDict->find(macroName)==0) // expand macro
{
Define *def=DefineManager::instance().isDefined(macroName);
- if (definedTest) // macro name was found after defined
+ if (macroName=="defined")
+ {
+ //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
+ definedTest=TRUE;
+ }
+ else if (definedTest) // macro name was found after defined
{
if (def) expMacro = " 1 "; else expMacro = " 0 ";
replaced=TRUE;
@@ -1099,7 +1104,7 @@ static void expandExpression(QCString &expr,QCString *rest,int pos)
else if (def && def->nargs==-1) // simple macro
{
// substitute the definition of the macro
- //printf("macro `%s'->`%s'\n",macroName.data(),def->definition.data());
+ //printf("macro '%s'->'%s'\n",macroName.data(),def->definition.data());
if (g_nospaces)
{
expMacro=def->definition.stripWhiteSpace();
@@ -1111,22 +1116,17 @@ static void expandExpression(QCString &expr,QCString *rest,int pos)
//expMacro=def->definition.stripWhiteSpace();
replaced=TRUE;
len=l;
- //printf("simple macro expansion=`%s'->`%s'\n",macroName.data(),expMacro.data());
+ //printf("simple macro expansion='%s'->'%s'\n",macroName.data(),expMacro.data());
}
else if (def && def->nargs>=0) // function macro
{
replaced=replaceFunctionMacro(expr,rest,p+l,len,def,expMacro);
len+=l;
}
- else if (macroName=="defined")
- {
- //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data());
- definedTest=TRUE;
- }
if (replaced) // expand the macro and rescan the expression
{
- //printf("replacing `%s'->`%s'\n",expr.mid(p,len).data(),expMacro.data());
+ //printf("replacing '%s'->'%s'\n",expr.mid(p,len).data(),expMacro.data());
QCString resultExpr=expMacro;
QCString restExpr=expr.right(expr.length()-len-p);
processConcatOperators(resultExpr);
@@ -1237,7 +1237,7 @@ QCString removeIdsAndMarkers(const char *s)
{
p = processUntilMatchingTerminator(p,result);
}
- else if (c=='d' && !inNum) // identifier starting with a `d'
+ else if (c=='d' && !inNum) // identifier starting with a 'd'
{
if (qstrncmp(p,"defined ",8)==0 || qstrncmp(p,"defined(",8)==0)
// defined keyword
@@ -1388,10 +1388,10 @@ bool computeExpression(const QCString &expr)
{
QCString e=expr;
expandExpression(e,0,0);
- //printf("after expansion `%s'\n",e.data());
+ //printf("after expansion '%s'\n",e.data());
e = removeIdsAndMarkers(e);
if (e.isEmpty()) return FALSE;
- //printf("parsing `%s'\n",e.data());
+ //printf("parsing '%s'\n",e.data());
return parseconstexp(g_yyFileName,g_yyLineNr,e);
}
@@ -1404,7 +1404,7 @@ QCString expandMacro(const QCString &name)
QCString n=name;
expandExpression(n,0,0);
n=removeMarkers(n);
- //printf("expandMacro `%s'->`%s'\n",name.data(),n.data());
+ //printf("expandMacro '%s'->'%s'\n",name.data(),n.data());
return n;
}
@@ -1421,7 +1421,7 @@ Define *newDefine()
def->varArgs = g_defVarArgs;
//printf("newDefine: %s %s file: %s\n",def->name.data(),def->definition.data(),
// def->fileDef ? def->fileDef->name().data() : def->fileName.data());
- //printf("newDefine: `%s'->`%s'\n",def->name.data(),def->definition.data());
+ //printf("newDefine: '%s'->'%s'\n",def->name.data(),def->definition.data());
if (!def->name.isEmpty() && Doxygen::expandAsDefinedDict[def->name])
{
def->isPredefined=TRUE;
@@ -1445,11 +1445,11 @@ void addDefine()
if (!g_defArgsStr.isEmpty())
{
ArgumentList *argList = new ArgumentList;
- //printf("addDefine() g_defName=`%s' g_defArgsStr=`%s'\n",g_defName.data(),g_defArgsStr.data());
+ //printf("addDefine() g_defName='%s' g_defArgsStr='%s'\n",g_defName.data(),g_defArgsStr.data());
stringToArgumentList(g_defArgsStr,argList);
md->setArgumentList(argList);
}
- //printf("Setting initializer for `%s' to `%s'\n",g_defName.data(),g_defText.data());
+ //printf("Setting initializer for '%s' to '%s'\n",g_defName.data(),g_defText.data());
int l=g_defLitText.find('\n');
if (l>0 && g_defLitText.left(l).stripWhiteSpace()=="\\")
{
@@ -1529,7 +1529,7 @@ static void readIncludeFile(const QCString &inc)
QCString oldFileName = g_yyFileName;
FileDef *oldFileDef = g_yyFileDef;
int oldLineNr = g_yyLineNr;
- //printf("Searching for `%s'\n",incFileName.data());
+ //printf("Searching for '%s'\n",incFileName.data());
// absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336)
QCString absIncFileName = incFileName;
@@ -2020,7 +2020,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
if (g_roundCount==0)
{
QCString result=expandMacro(g_defArgsStr);
- //printf("g_defArgsStr=`%s'->`%s'\n",g_defArgsStr.data(),result.data());
+ //printf("g_defArgsStr='%s'->'%s'\n",g_defArgsStr.data(),result.data());
if (g_findDefArgContext==CopyLine)
{
outputArray(result,result.length());
@@ -2094,6 +2094,8 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
<ReadString>"//"|"/*" {
g_defArgsStr+=yytext;
}
+<ReadString>\\/\r?\n { // line continuation
+ }
<ReadString>\\. {
g_defArgsStr+=yytext;
}
@@ -2227,7 +2229,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
<Guard>. { g_guardExpr+=*yytext; }
<Guard>\n {
unput(*yytext);
- //printf("Guard: `%s'\n",
+ //printf("Guard: '%s'\n",
// g_guardExpr.data());
bool guard=computeExpression(g_guardExpr);
setCaseDone(guard);
@@ -2381,7 +2383,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
<EndImport>. {
}
<DefName>{ID}/("\\\n")*"(" { // define with argument
- //printf("Define() `%s'\n",yytext);
+ //printf("Define() '%s'\n",yytext);
delete g_argDict;
g_argDict = new QDict<int>(31);
g_argDict->setAutoDelete(TRUE);
@@ -2395,7 +2397,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
BEGIN(DefineArg);
}
<DefName>{ID}{B}+"1"/[ \r\t\n] { // special case: define with 1 -> can be "guard"
- //printf("Define `%s'\n",yytext);
+ //printf("Define '%s'\n",yytext);
delete g_argDict; g_argDict=0;
g_defArgs = -1;
g_defArgsStr.resize(0);
@@ -2453,7 +2455,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
g_expectGuard=FALSE;
}
<DefName>{ID}/{B}* { // define with content
- //printf("Define `%s'\n",yytext);
+ //printf("Define '%s'\n",yytext);
delete g_argDict; g_argDict=0;
g_defArgs = -1;
g_defArgsStr.resize(0);
@@ -2855,7 +2857,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
}
outputChar('\n');
Define *def=0;
- //printf("Define name=`%s' text=`%s' litTexti=`%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
+ //printf("Define name='%s' text='%s' litTexti='%s'\n",g_defName.data(),g_defText.data(),g_defLitText.data());
if (g_includeStack.isEmpty() || g_curlyCount>0)
{
addDefine();
@@ -3202,7 +3204,7 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
DefineManager::instance().addDefine(g_yyFileName,def);
}
- //printf("#define `%s' `%s' #nargs=%d\n",
+ //printf("#define '%s' '%s' #nargs=%d\n",
// def->name.data(),def->definition.data(),def->nargs);
}
else if ((i_obrace==-1 || i_obrace>i_equals) &&
@@ -3237,7 +3239,7 @@ void preprocessFile(const char *fileName,BufStr &input,BufStr &output)
delete def;
}
- //printf("#define `%s' `%s' #nargs=%d\n",
+ //printf("#define '%s' '%s' #nargs=%d\n",
// def->name.data(),def->definition.data(),def->nargs);
}
}
diff --git a/src/printdocvisitor.h b/src/printdocvisitor.h
index 26bb3e7..6b9bd75 100644
--- a/src/printdocvisitor.h
+++ b/src/printdocvisitor.h
@@ -108,9 +108,15 @@ class PrintDocVisitor : public DocVisitor
case DocStyleChange::Strike:
if (s->enable()) printf("<strike>"); else printf("</strike>");
break;
+ case DocStyleChange::Del:
+ if (s->enable()) printf("<del>"); else printf("</del>");
+ break;
case DocStyleChange::Underline:
if (s->enable()) printf("<underline>"); else printf("</underline>");
break;
+ case DocStyleChange::Ins:
+ if (s->enable()) printf("<ins>"); else printf("</ins>");
+ break;
case DocStyleChange::Italic:
if (s->enable()) printf("<italic>"); else printf("</italic>");
break;
@@ -616,16 +622,24 @@ class PrintDocVisitor : public DocVisitor
//const char *s;
DocNode *param;
printf("<parameters>");
- for (sli.toFirst();(param=sli.current());++sli)
+ if (sli.count() > 0)
{
printf("<param>");
- if (param->kind()==DocNode::Kind_Word)
+ for (sli.toFirst();(param=sli.current());++sli)
{
- visit((DocWord*)param);
- }
- else if (param->kind()==DocNode::Kind_LinkedWord)
- {
- visit((DocLinkedWord*)param);
+ if (param->kind()==DocNode::Kind_Word)
+ {
+ visit((DocWord*)param);
+ }
+ else if (param->kind()==DocNode::Kind_LinkedWord)
+ {
+ visit((DocLinkedWord*)param);
+ }
+ else if (param->kind()==DocNode::Kind_Sep)
+ {
+ printf("</param>");
+ printf("<param>");
+ }
}
printf("</param>");
}
@@ -676,16 +690,6 @@ class PrintDocVisitor : public DocVisitor
indent_post();
printf("</internalref>\n");
}
- void visitPre(DocCopy *c)
- {
- indent_pre();
- printf("<copy link=\"%s\">\n",c->link().data());
- }
- void visitPost(DocCopy *)
- {
- indent_post();
- printf("</copy>\n");
- }
void visitPre(DocText *)
{
indent_pre();
diff --git a/src/pycode.l b/src/pycode.l
index 1a87bca..0f04baa 100644
--- a/src/pycode.l
+++ b/src/pycode.l
@@ -162,7 +162,7 @@ void PyVariableContext::addVariable(const QCString &type,const QCString &name)
QCString lname = name.simplifyWhiteSpace();
Scope *scope = m_scopes.count()==0 ? &m_globalScope : m_scopes.getLast();
- ClassDef *varType;
+ const ClassDef *varType;
if (
(varType=g_codeClassSDict[ltype]) || // look for class definitions inside the code block
(varType=getResolvedClass(g_currentDefinition,g_sourceFileDef,ltype)) // look for global class definitions
@@ -212,7 +212,7 @@ class PyCallContext
Ctx() : name(g_name), type(g_type), cd(0) {}
QCString name;
QCString type;
- ClassDef *cd;
+ const ClassDef *cd;
};
PyCallContext()
@@ -223,7 +223,7 @@ class PyCallContext
virtual ~PyCallContext() {}
- void setClass(ClassDef *cd)
+ void setClass(const ClassDef *cd)
{
Ctx *ctx = m_classList.getLast();
if (ctx)
@@ -259,7 +259,7 @@ class PyCallContext
m_classList.append(new Ctx);
}
- ClassDef *getClass() const
+ const ClassDef *getClass() const
{
Ctx *ctx = m_classList.getLast();
@@ -320,7 +320,7 @@ static void addToSearchIndex(const char *text)
}
-static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
+static const ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
{
int pos=0;
QCString type = s;
@@ -330,7 +330,7 @@ static ClassDef *stripClassName(const char *s,Definition *d=g_currentDefinition)
{
QCString clName=className+templSpec;
- ClassDef *cd=0;
+ const ClassDef *cd=0;
if (!g_classScope.isEmpty())
{
cd=getResolvedClass(d,g_sourceFileDef,g_classScope+"::"+clName);
@@ -376,7 +376,7 @@ static void startCodeLine()
g_searchingForBody = TRUE;
g_realScope = d->name().copy();
g_classScope = d->name().copy();
- //printf("Real scope: `%s'\n",g_realScope.data());
+ //printf("Real scope: '%s'\n",g_realScope.data());
g_bodyCurlyCount = 0;
QCString lineAnchor;
lineAnchor.sprintf("l%05d",g_yyLineNr);
@@ -549,7 +549,7 @@ static bool getLinkInScope(const QCString &c, // scope
const FileDef *fd = 0;
const NamespaceDef *nd = 0;
const GroupDef *gd = 0;
- //printf("Trying `%s'::`%s'\n",c.data(),m.data());
+ //printf("Trying '%s'::'%s'\n",c.data(),m.data());
if (getDefs(c,m,"()",md,cd,fd,nd,gd,FALSE,g_sourceFileDef) &&
md->isLinkable())
{
@@ -571,7 +571,7 @@ static bool getLinkInScope(const QCString &c, // scope
{
addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(md));
}
- //printf("d->getReference()=`%s' d->getOutputBase()=`%s' name=`%s' member name=`%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data());
+ //printf("d->getReference()='%s' d->getOutputBase()='%s' name='%s' member name='%s'\n",d->getReference().data(),d->getOutputFileBase().data(),d->name().data(),md->name().data());
writeMultiLineCodeLink(ol,md, text ? text : memberText);
addToSearchIndex(text ? text : memberText);
@@ -616,8 +616,8 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName,
DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",className.data()));
- ClassDef *cd=0,*lcd=0; /** Class def that we may find */
- MemberDef *md=0; /** Member def that we may find */
+ const ClassDef *cd=0,*lcd=0; /** Class def that we may find */
+ const MemberDef *md=0; /** Member def that we may find */
//bool isLocal=FALSE;
if ((lcd=g_theVarContext.findVariable(className))==0) // not a local variable
@@ -669,7 +669,7 @@ static void generateClassOrGlobalLink(CodeOutputInterface &ol,char *clName,
if (d && d->isLinkable() && md->isLinkable() &&
g_currentMemberDef && g_collectXRefs)
{
- addDocCrossReference(g_currentMemberDef,md);
+ addDocCrossReference(g_currentMemberDef,const_cast<MemberDef*>(md));
}
}
}
@@ -753,7 +753,7 @@ static void generateFunctionLink(CodeOutputInterface &ol,char *funcName)
locScope=locFunc.left(i);
locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace();
}
- //printf("generateFunctionLink(%s) classScope=`%s'\n",locFunc.data(),locScope.data());
+ //printf("generateFunctionLink(%s) classScope='%s'\n",locFunc.data(),locScope.data());
if (!locScope.isEmpty() && (ccd=g_codeClassSDict[locScope]))
{
//printf("using classScope %s\n",g_classScope.data());
@@ -1091,7 +1091,7 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUT
char *s=g_curClassBases.first();
while (s)
{
- ClassDef *baseDefToAdd=g_codeClassSDict[s];
+ const ClassDef *baseDefToAdd=g_codeClassSDict[s];
// Try to find class in global
// scope
@@ -1102,7 +1102,7 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUT
if (baseDefToAdd && baseDefToAdd!=classDefToAdd)
{
- classDefToAdd->insertBaseClass(baseDefToAdd,s,Public,Normal);
+ classDefToAdd->insertBaseClass(const_cast<ClassDef*>(baseDefToAdd),s,Public,Normal);
}
s=g_curClassBases.next();
@@ -1173,6 +1173,10 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUT
}
{FLOWKW} {
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
startFontClass("keywordflow");
codify(yytext);
endFontClass();
@@ -1210,6 +1214,10 @@ TARGET ({IDENTIFIER}|"("{TARGET_LIST}")"|"["{TARGET_LIST}"]"|{ATTRIBUT
}
{FLOWKW} {
+ if (g_currentMemberDef && g_currentMemberDef->isFunction())
+ {
+ g_currentMemberDef->incrementFlowKeyWordCount();
+ }
startFontClass("keywordflow");
codifyLines(yytext);
endFontClass();
diff --git a/src/pyscanner.l b/src/pyscanner.l
index fe94e64..3fe66f2 100644
--- a/src/pyscanner.l
+++ b/src/pyscanner.l
@@ -95,6 +95,7 @@ static int g_stringContext;
static QGString * g_copyString;
static int g_indent = 0;
static int g_curIndent = 0;
+static bool g_importTuple;
static QDict<QCString> g_packageNameCache(257);
@@ -102,6 +103,7 @@ static char g_atomStart;
static char g_atomEnd;
static int g_atomCount;
+
//static bool g_insideConstructor;
static QCString g_moduleScope;
@@ -143,7 +145,7 @@ static void initEntry()
current->stat = gstat;
current->lang = SrcLangExt_Python;
current->setParent(current_root);
- initGroupInfo(current);
+ Doxygen::docGroup.initGroupInfo(current);
gstat = FALSE;
}
@@ -230,6 +232,17 @@ static QCString findPackageScope(const char *fileName)
return findPackageScopeFromPath(fi.dirPath(TRUE).data());
}
+static void addFrom(bool all)
+{
+ QCString item=all ? g_packageName : g_packageName+"."+yytext;
+ current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
+ current->fileName = yyFileName;
+ //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
+ current->section=all ? Entry::USINGDIR_SEC : Entry::USINGDECL_SEC;
+ current_root->addSubEntry(current);
+ current = new Entry ;
+ initEntry();
+}
//-----------------------------------------------------------------------------
static void lineCount()
@@ -702,45 +715,43 @@ STARTDOCSYMS "##"
<FromModItem>{
"*" { // import all
- QCString item=g_packageName;
- current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
- current->fileName = yyFileName;
- //printf("Adding using directive: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
- current->section=Entry::USINGDIR_SEC;
- current_root->addSubEntry(current);
- current = new Entry ;
- initEntry();
+ addFrom(TRUE);
BEGIN(Search);
}
{IDENTIFIER}/{B}","{B} {
- QCString item=g_packageName+"."+yytext;
- current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
- current->fileName = yyFileName;
- //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
- current->section=Entry::USINGDECL_SEC;
- current_root->addSubEntry(current);
- current = new Entry ;
- initEntry();
+ addFrom(FALSE);
}
+ {IDENTIFIER}/{B}")" {
+ addFrom(FALSE);
+ }
{IDENTIFIER} {
- QCString item=g_packageName+"."+yytext;
- current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
- current->fileName = yyFileName;
- //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
- current->section=Entry::USINGDECL_SEC;
- current_root->addSubEntry(current);
- current = new Entry ;
- initEntry();
- BEGIN(Search);
+ addFrom(FALSE);
+ if (!g_importTuple)
+ {
+ BEGIN(Search);
+ }
}
\n {
incLineNr();
- BEGIN(Search);
+ if (!g_importTuple)
+ {
+ BEGIN(Search);
+ }
}
{B} {
}
- "," {
+ "(" {
+ g_importTuple=TRUE;
+ }
+ ")" {
+ g_importTuple=FALSE;
+ BEGIN(Search);
+ }
+ "," {
}
+ "\\"{B}\n { // line continuation
+ incLineNr();
+ }
. {
unput(*yytext);
BEGIN(Search);
@@ -1772,14 +1783,14 @@ static void parseCompounds(Entry *rt)
current = new Entry;
initEntry();
- groupEnterCompound(yyFileName,yyLineNr,ce->name);
+ Doxygen::docGroup.enterCompound(yyFileName,yyLineNr,ce->name);
pyscannerYYlex() ;
g_lexInit=TRUE;
delete current; current=0;
ce->program.resize(0);
- groupLeaveCompound(yyFileName,yyLineNr,ce->name);
+ Doxygen::docGroup.leaveCompound(yyFileName,yyLineNr,ce->name);
}
parseCompounds(ce);
@@ -1839,7 +1850,7 @@ static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
initParser();
current = new Entry;
- groupEnterFile(yyFileName,yyLineNr);
+ Doxygen::docGroup.enterFile(yyFileName,yyLineNr);
current->reset();
initEntry();
@@ -1848,7 +1859,7 @@ static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
pyscannerYYlex();
g_lexInit=TRUE;
- groupLeaveFile(yyFileName,yyLineNr);
+ Doxygen::docGroup.leaveFile(yyFileName,yyLineNr);
current_root->program.resize(0);
delete current; current=0;
diff --git a/src/resourcemgr.cpp b/src/resourcemgr.cpp
index ab7422a..8cb831e 100644
--- a/src/resourcemgr.cpp
+++ b/src/resourcemgr.cpp
@@ -144,7 +144,7 @@ bool ResourceMgr::copyResourceAs(const char *name,const char *targetDir,const ch
}
else
{
- t << substitute(buf,"$doxygenversion",versionString);
+ t << substitute(buf,"$doxygenversion",getVersion());
}
return TRUE;
}
diff --git a/src/rtfdocvisitor.cpp b/src/rtfdocvisitor.cpp
index 55c03a5..43ac362 100644
--- a/src/rtfdocvisitor.cpp
+++ b/src/rtfdocvisitor.cpp
@@ -236,9 +236,11 @@ void RTFDocVisitor::visit(DocStyleChange *s)
if (s->enable()) m_t << "{\\b "; else m_t << "} ";
break;
case DocStyleChange::Strike:
+ case DocStyleChange::Del:
if (s->enable()) m_t << "{\\strike "; else m_t << "} ";
break;
case DocStyleChange::Underline:
+ case DocStyleChange::Ins:
if (s->enable()) m_t << "{\\ul "; else m_t << "} ";
break;
case DocStyleChange::Italic:
@@ -529,10 +531,12 @@ void RTFDocVisitor::visit(DocInclude *inc)
void RTFDocVisitor::visit(DocIncOperator *op)
{
- //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
+ //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
// op->type(),op->isFirst(),op->isLast(),op->text().data());
DBG_RTF("{\\comment RTFDocVisitor::visit(DocIncOperator)}\n");
- SrcLangExt langExt = getLanguageFromFileName(m_langExt);
+ QCString locLangExt = getFileNameExtension(op->includeFileName());
+ if (locLangExt.isEmpty()) locLangExt = m_langExt;
+ SrcLangExt langExt = getLanguageFromFileName(locLangExt);
if (op->isFirst())
{
if (!m_hide)
@@ -549,14 +553,14 @@ void RTFDocVisitor::visit(DocIncOperator *op)
popEnabled();
if (!m_hide)
{
- FileDef *fd;
+ FileDef *fd = 0;
if (!op->includeFileName().isEmpty())
{
QFileInfo cfi( op->includeFileName() );
fd = createFileDef( cfi.dirPath().utf8(), cfi.fileName().utf8() );
}
- Doxygen::parserManager->getParser(m_langExt)
+ Doxygen::parserManager->getParser(locLangExt)
->parseCode(m_ci,op->context(),op->text(),langExt,
op->isExample(),op->exampleFile(),
fd, // fileDef
@@ -782,7 +786,6 @@ void RTFDocVisitor::visitPre(DocSimpleSect *s)
// special case 1: user defined title
if (s->type()!=DocSimpleSect::User && s->type()!=DocSimpleSect::Rcs)
{
- m_t << ":";
m_t << "\\par";
m_t << "}"; // end bold
incIndentLevel();
@@ -1377,7 +1380,6 @@ void RTFDocVisitor::visitPre(DocParamSect *s)
default:
ASSERT(0);
}
- m_t << ":";
m_t << "\\par";
m_t << "}" << endl;
bool useTable = s->type()==DocParamSect::Param ||
@@ -1493,10 +1495,8 @@ void RTFDocVisitor::visitPre(DocParamList *pl)
}
QListIterator<DocNode> li(pl->paramTypes());
DocNode *type;
- bool first=TRUE;
for (li.toFirst();(type=li.current());++li)
{
- if (!first) m_t << " | "; else first=FALSE;
if (type->kind()==DocNode::Kind_Word)
{
visit((DocWord*)type);
@@ -1505,6 +1505,10 @@ void RTFDocVisitor::visitPre(DocParamList *pl)
{
visit((DocLinkedWord*)type);
}
+ else if (type->kind()==DocNode::Kind_Sep)
+ {
+ m_t << " " << ((DocSeparator *)type)->chars() << " ";
+ }
}
if (useTable)
{
@@ -1655,18 +1659,6 @@ void RTFDocVisitor::visitPost(DocInternalRef *)
m_t << " ";
}
-void RTFDocVisitor::visitPre(DocCopy *)
-{
- if (m_hide) return;
- DBG_RTF("{\\comment RTFDocVisitor::visitPre(DocCopy)}\n");
-}
-
-void RTFDocVisitor::visitPost(DocCopy *)
-{
- if (m_hide) return;
- DBG_RTF("{\\comment RTFDocVisitor::visitPost(DocCopy)}\n");
-}
-
void RTFDocVisitor::visitPre(DocText *)
{
if (m_hide) return;
diff --git a/src/rtfdocvisitor.h b/src/rtfdocvisitor.h
index b7cc3ea..82e4453 100644
--- a/src/rtfdocvisitor.h
+++ b/src/rtfdocvisitor.h
@@ -126,8 +126,6 @@ class RTFDocVisitor : public DocVisitor
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp
index bb2075b..229a817 100644
--- a/src/rtfgen.cpp
+++ b/src/rtfgen.cpp
@@ -31,6 +31,10 @@
#include "diagram.h"
#include "language.h"
#include "dot.h"
+#include "dotcallgraph.h"
+#include "dotclassgraph.h"
+#include "dotdirdeps.h"
+#include "dotincldepgraph.h"
#include "version.h"
#include "pagedef.h"
#include "rtfstyle.h"
@@ -44,6 +48,8 @@
#include "filename.h"
#include "namespacedef.h"
+static bool DoxyCodeLineOpen = FALSE;
+
//#define DBG_RTF(x) x;
#define DBG_RTF(x)
@@ -96,7 +102,7 @@ RTFGenerator::~RTFGenerator()
void RTFGenerator::writeStyleSheetFile(QFile &file)
{
FTextStream t(&file);
- t << "# Generated by doxygen " << versionString << "\n\n";
+ t << "# Generated by doxygen " << getVersion() << "\n\n";
t << "# This file describes styles used for generating RTF output.\n";
t << "# All text after a hash (#) is considered a comment and will be ignored.\n";
t << "# Remove a hash to activate a line.\n\n";
@@ -113,7 +119,7 @@ void RTFGenerator::writeStyleSheetFile(QFile &file)
void RTFGenerator::writeExtensionsFile(QFile &file)
{
FTextStream t(&file);
- t << "# Generated by doxygen " << versionString << "\n\n";
+ t << "# Generated by doxygen " << getVersion() << "\n\n";
t << "# This file describes extensions used for generating RTF output.\n";
t << "# All text after a hash (#) is considered a comment and will be ignored.\n";
t << "# Remove a hash to activate a line.\n\n";
@@ -1532,7 +1538,7 @@ void RTFGenerator::startMemberDoc(const char *clname,
t << rtf_Style_Reset << rtf_Style[showInline ? "Heading5" : "Heading4"]->reference;
//styleStack.push(rtf_Style_Heading4);
t << "{" << endl;
- //printf("RTFGenerator::startMemberDoc() `%s'\n",rtf_Style["Heading4"]->reference);
+ //printf("RTFGenerator::startMemberDoc() '%s'\n",rtf_Style["Heading4"]->reference);
startBold();
t << endl;
}
@@ -1541,7 +1547,7 @@ void RTFGenerator::endMemberDoc(bool)
{
DBG_RTF(t << "{\\comment endMemberDoc}" << endl)
//const char *style = styleStack.pop();
- //printf("RTFGenerator::endMemberDoc() `%s'\n",style);
+ //printf("RTFGenerator::endMemberDoc() '%s'\n",style);
//ASSERT(style==rtf_Style["Heading4"]->reference);
endBold();
t << "}" << endl;
@@ -1948,6 +1954,9 @@ void RTFGenerator::endCodeFragment()
//styleStack.pop();
//printf("RTFGenerator::endCodeFrament() top=%s\n",styleStack.top());
//t << rtf_Style_Reset << styleStack.top() << endl;
+ //endCodeLine checks is there is still an open code line, if so closes it.
+ endCodeLine();
+
DBG_RTF(t << "{\\comment (endCodeFragment) }" << endl)
t << "}" << endl;
m_omitParagraph = TRUE;
@@ -2497,7 +2506,7 @@ void RTFGenerator::startDotGraph()
DBG_RTF(t << "{\\comment (startDotGraph)}" << endl)
}
-void RTFGenerator::endDotGraph(const DotClassGraph &g)
+void RTFGenerator::endDotGraph(DotClassGraph &g)
{
newParagraph();
@@ -2521,7 +2530,7 @@ void RTFGenerator::startInclDepGraph()
DBG_RTF(t << "{\\comment (startInclDepGraph)}" << endl)
}
-void RTFGenerator::endInclDepGraph(const DotInclDepGraph &g)
+void RTFGenerator::endInclDepGraph(DotInclDepGraph &g)
{
newParagraph();
@@ -2543,7 +2552,7 @@ void RTFGenerator::startGroupCollaboration()
{
}
-void RTFGenerator::endGroupCollaboration(const DotGroupCollaboration &)
+void RTFGenerator::endGroupCollaboration(DotGroupCollaboration &)
{
}
@@ -2552,7 +2561,7 @@ void RTFGenerator::startCallGraph()
DBG_RTF(t << "{\\comment (startCallGraph)}" << endl)
}
-void RTFGenerator::endCallGraph(const DotCallGraph &g)
+void RTFGenerator::endCallGraph(DotCallGraph &g)
{
newParagraph();
@@ -2575,7 +2584,7 @@ void RTFGenerator::startDirDepGraph()
DBG_RTF(t << "{\\comment (startDirDepGraph)}" << endl)
}
-void RTFGenerator::endDirDepGraph(const DotDirDeps &g)
+void RTFGenerator::endDirDepGraph(DotDirDeps &g)
{
newParagraph();
@@ -3037,6 +3046,22 @@ void RTFGenerator::endInlineMemberDoc()
t << "\\cell }{\\row }" << endl;
}
+void RTFGenerator::writeLineNumber(const char *,const char *,const char *,int l)
+{
+ DoxyCodeLineOpen = TRUE;
+ t << QString("%1").arg(l,5) << " ";
+}
+void RTFGenerator::startCodeLine(bool)
+{
+ DoxyCodeLineOpen = TRUE;
+ col=0;
+}
+void RTFGenerator::endCodeLine()
+{
+ if (DoxyCodeLineOpen) lineBreak();
+ DoxyCodeLineOpen = FALSE;
+}
+
void RTFGenerator::startLabels()
{
}
diff --git a/src/rtfgen.h b/src/rtfgen.h
index 3f05821..b5f06f0 100644
--- a/src/rtfgen.h
+++ b/src/rtfgen.h
@@ -127,9 +127,9 @@ class RTFGenerator : public OutputGenerator
void writeAnchor(const char *fileName,const char *name);
void startCodeFragment();
void endCodeFragment();
- void writeLineNumber(const char *,const char *,const char *,int l) { t << QString("%1").arg(l,5) << " "; }
- void startCodeLine(bool) { col=0; }
- void endCodeLine() { lineBreak(); }
+ void writeLineNumber(const char *,const char *,const char *,int l);
+ void startCodeLine(bool);
+ void endCodeLine();
void startEmphasis() { t << "{\\i "; }
void endEmphasis() { t << "}"; }
void startBold() { t << "{\\b "; }
@@ -202,16 +202,16 @@ class RTFGenerator : public OutputGenerator
void endDescTableData();
void startDotGraph();
- void endDotGraph(const DotClassGraph &);
+ void endDotGraph(DotClassGraph &);
void startInclDepGraph();
- void endInclDepGraph(const DotInclDepGraph &);
+ void endInclDepGraph(DotInclDepGraph &);
void startGroupCollaboration();
- void endGroupCollaboration(const DotGroupCollaboration &g);
+ void endGroupCollaboration(DotGroupCollaboration &g);
void startCallGraph();
- void endCallGraph(const DotCallGraph &);
+ void endCallGraph(DotCallGraph &);
void startDirDepGraph();
- void endDirDepGraph(const DotDirDeps &g);
- void writeGraphicalHierarchy(const DotGfxHierarchyTable &) {}
+ void endDirDepGraph(DotDirDeps &g);
+ void writeGraphicalHierarchy(DotGfxHierarchyTable &) {}
void startMemberGroupHeader(bool);
void endMemberGroupHeader();
diff --git a/src/scanner.l b/src/scanner.l
index f94e4f8..970b1e8 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -78,6 +78,7 @@ static int lastHereDocContext;
static int lastDefineContext;
static int lastAlignAsContext;
static int lastC11AttributeContext;
+static int lastModifierContext;
static Protection protection;
static Protection baseProt;
static int sharpCount = 0 ;
@@ -246,7 +247,7 @@ static void initEntry()
// //printf("Appending group %s\n",autoGroupStack.top()->groupname.data());
// current->groups->append(new Grouping(*autoGroupStack.top()));
//}
- initGroupInfo(current);
+ Doxygen::docGroup.initGroupInfo(current);
isTypedef=FALSE;
}
@@ -613,6 +614,7 @@ PRE [pP][rR][eE]
CODE [cC][oO][dD][eE]
CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
PHPKW ("require"|"require_once"|"include"|"include_once"|"echo")[^a-zA-Z0-9_;]
+PHPUSEKW ("public"|"private"|"protected")
IDLATTR ("["[^\]]*"]"){BN}*
TYPEDEFPREFIX (("typedef"{BN}+)?)((("volatile"|"const"){BN}+)?)
RAWBEGIN (u|U|L|u8)?R\"[^ \t\(\)\\]{0,16}"("
@@ -766,6 +768,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
/** Slice states */
+%x SliceOptional
%x SliceMetadata
%x SliceSequence
%x SliceSequenceName
@@ -865,12 +868,6 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
<FindMembersPHP>. { // Non-PHP code text, ignore
}
-<FindMembers>"?>"|"</script>" { // PHP code end
- if (insidePHP)
- BEGIN( FindMembersPHP );
- else
- REJECT;
- }
<FindMembers>{PHPKW} { if (insidePHP)
BEGIN( NextSemi );
else
@@ -1146,9 +1143,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
<ObjCReturnType>")" {
BEGIN( ObjCMethod );
}
-<ObjCParams>({ID})?":" { // Keyword of parameter
+<ObjCParams>({ID})?{BN}*":" { // Keyword of parameter
QCString keyw = yytext;
- keyw=keyw.left(keyw.length()-1); // strip :
+ keyw=keyw.left(keyw.length()-1).stripWhiteSpace(); // strip :
if (keyw.isEmpty())
{
current->name += " :";
@@ -1390,6 +1387,10 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
current->explicitExternal = TRUE;
lineCount();
}
+<FindMembers>{B}*"const"{BN}+ { current->type += " const ";
+ if (insideCS) current->stat = TRUE;
+ lineCount();
+ }
<FindMembers>{B}*"virtual"{BN}+ { current->type += " virtual ";
current->virt = Virtual;
lineCount();
@@ -2006,11 +2007,16 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
<PHPUseAs>{BN}+"as"{BN}+ {
lineCount();
}
+<PHPUseAs>{PHPUSEKW} {
+ }
<PHPUseAs>{ID} {
//printf("PHP: adding use as relation: %s->%s\n",yytext,aliasName.data());
- Doxygen::namespaceAliasDict.insert(yytext,
- new QCString(removeRedundantWhiteSpace(
- substitute(aliasName,"\\","::"))));
+ if (!aliasName.isEmpty())
+ {
+ Doxygen::namespaceAliasDict.insert(yytext,
+ new QCString(removeRedundantWhiteSpace(
+ substitute(aliasName,"\\","::"))));
+ }
aliasName.resize(0);
}
<PHPUse,PHPUseAs>[,;] {
@@ -2310,6 +2316,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
<CopyHereDocEnd>\n {
*pCopyHereDocGString += yytext;
}
+<CopyHereDocEnd>{ID} {
+ *pCopyHereDocGString += yytext;
+ }
<CopyHereDocEnd>. {
*pCopyHereDocGString += yytext;
}
@@ -2435,6 +2444,19 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
current->type+=yytext;
BEGIN(DeclType);
}
+ else if (insideSlice && qstrcmp(yytext,"optional")==0)
+ {
+ if (current->type.isEmpty())
+ {
+ current->type = "optional";
+ }
+ else
+ {
+ current->type += " optional";
+ }
+ lastModifierContext = YY_START;
+ BEGIN(SliceOptional);
+ }
else
{
if (YY_START==FindMembers)
@@ -2655,7 +2677,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
*/
<Define>{ID} {
- //printf("Define `%s' without args\n",yytext);
+ //printf("Define '%s' without args\n",yytext);
if (insideCpp || insideObjC)
{
current->id = ClangParser::instance()->lookup(yyLineNr,yytext);
@@ -2830,17 +2852,17 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
}
-<FindMembers,FindFields>("//"([!/]?){B}*{CMD}"{")|("/*"([!*]?){B}*{CMD}"{") {
+<FindMembers,FindFields>("//"([!/]){B}*{CMD}"{")|("/*"([!*]){B}*{CMD}"{") {
//handleGroupStartCommand(current->name);
if (previous && previous->section==Entry::GROUPDOC_SEC)
{
// link open command to the group defined in the previous entry
- openGroup(previous,yyFileName,yyLineNr);
+ Doxygen::docGroup.open(previous,yyFileName,yyLineNr);
}
else
{
// link open command to the current entry
- openGroup(current,yyFileName,yyLineNr);
+ Doxygen::docGroup.open(current,yyFileName,yyLineNr);
}
//current = tmp;
initEntry();
@@ -2882,9 +2904,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
}
}
-<FindMembers,FindFields,ReadInitializer>"//"([!/]?){B}*{CMD}"}".*|"/*"([!*]?){B}*{CMD}"}"[^*]*"*/" {
+<FindMembers,FindFields,ReadInitializer>"//"([!/]){B}*{CMD}"}".*|"/*"([!*]){B}*{CMD}"}"[^*]*"*/" {
bool insideEnum = YY_START==FindFields || (YY_START==ReadInitializer && lastInitializerContext==FindFields); // see bug746226
- closeGroup(current,yyFileName,yyLineNr,insideEnum);
+ Doxygen::docGroup.close(current,yyFileName,yyLineNr,insideEnum);
}
<FindMembers>"=" { // in PHP code this could also be due to "<?="
current->bodyLine = yyLineNr;
@@ -2926,7 +2948,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
BEGIN(GCopyCurly);
}
<ReadInitializer>[;,] {
- //printf(">> initializer `%s' <<\n",current->initializer.data());
+ //printf(">> initializer '%s' <<\n",current->initializer.data());
if (*yytext==';' && (current_root->spec&Entry::Enum))
{
current->fileName = yyFileName;
@@ -3589,6 +3611,20 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
BEGIN (lastSquareContext);
}
}
+<SliceOptional>"(" {
+ current->type += "(";
+ roundCount++;
+ }
+<SliceOptional>[0-9]+ {
+ current->type += yytext;
+ }
+<SliceOptional>")" {
+ current->type += ")";
+ if(--roundCount<=0)
+ {
+ BEGIN (lastModifierContext);
+ }
+ }
<IDLAttribute>"]" {
// end of IDL function attribute
if (--squareCount<=0)
@@ -3820,7 +3856,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
<SkipRemainder>[^\n]*
<FindFields>"," {
- //printf("adding `%s' `%s' `%s' to enum `%s' (mGrpId=%d)\n",
+ //printf("adding '%s' '%s' '%s' to enum '%s' (mGrpId=%d)\n",
// current->type.data(), current->name.data(),
// current->args.data(), current_root->name.data(),current->mGrpId);
if (!current->name.isEmpty())
@@ -3966,7 +4002,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
QCString &cn = current->name;
QCString rn = current_root->name.copy();
- //printf("cn=`%s' rn=`%s' isTypedef=%d\n",cn.data(),rn.data(),isTypedef);
+ //printf("cn='%s' rn='%s' isTypedef=%d\n",cn.data(),rn.data(),isTypedef);
if (!cn.isEmpty() && !rn.isEmpty())
{
prependScope();
@@ -3987,7 +4023,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
// was: current->args.simplifyWhiteSpace();
current->type = current->type.simplifyWhiteSpace();
current->name = current->name.stripWhiteSpace();
- //printf("adding `%s' `%s' `%s' brief=%s insideObjC=%d %x\n",current->type.data(),current->name.data(),current->args.data(),current->brief.data(),insideObjC,current->section);
+ //printf("adding '%s' '%s' '%s' brief=%s insideObjC=%d %x\n",current->type.data(),current->name.data(),current->args.data(),current->brief.data(),insideObjC,current->section);
if (insideObjC &&
((current->spec&Entry::Interface) || (current->spec==Entry::Category))
) // method definition follows
@@ -4133,7 +4169,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
{
// see if the compound does not have a name or is inside another
// anonymous compound. If so we insert a
- // special `anonymous' variable.
+ // special 'anonymous' variable.
//Entry *p=current_root;
Entry *p=current;
while (p)
@@ -4141,7 +4177,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
// only look for class scopes, not namespace scopes
if ((p->section & Entry::COMPOUND_MASK) && !p->name.isEmpty())
{
- //printf("Trying scope `%s'\n",p->name.data());
+ //printf("Trying scope '%s'\n",p->name.data());
int i=p->name.findRev("::");
int pi = (i==-1) ? 0 : i+2;
if (p->name.at(pi)=='@')
@@ -4226,7 +4262,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
}
- //printf("Add: type=`%s',name=`%s',args=`%s' brief=%s doc=%s\n",
+ //printf("Add: type='%s',name='%s',args='%s' brief=%s doc=%s\n",
// varEntry->type.data(),varEntry->name.data(),
// varEntry->args.data(),varEntry->brief.data(),varEntry->doc.data());
current_root->addSubEntry(varEntry);
@@ -4328,7 +4364,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
}
<FuncPtr>. {
- //printf("error: FuncPtr `%c' unexpected at line %d of %s\n",*yytext,yyLineNr,yyFileName);
+ //printf("error: FuncPtr '%c' unexpected at line %d of %s\n",*yytext,yyLineNr,yyFileName);
}
<FuncPtrOperator>"("{BN}*")"{BN}*/"(" {
current->name += yytext;
@@ -4582,7 +4618,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
BEGIN( SkipCxxComment );
}
*/
- /* `)' followed by a special comment */
+ /* ')' followed by a special comment */
<ReadFuncArgType>")"{BN}*("/*"[*!]|"//"[/!])"<" {
lineCount();
if (currentArgumentContext==DefineEnd)
@@ -5113,7 +5149,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
if (!current->type.isEmpty() &&
(!isFunction || current->type.left(8)=="typedef "))
{
- //printf("Scanner.l: found in class variable: `%s' `%s' `%s'\n", current->type.data(),current->name.data(),current->args.data());
+ //printf("Scanner.l: found in class variable: '%s' '%s' '%s'\n", current->type.data(),current->name.data(),current->args.data());
if (isTypedef && current->type.left(8)!="typedef ")
{
current->type.prepend("typedef ");
@@ -5122,14 +5158,14 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
else
{
- //printf("Scanner.l: found in class function: `%s' `%s' `%s'\n", current->type.data(),current->name.data(),current->args.data());
+ //printf("Scanner.l: found in class function: '%s' '%s' '%s'\n", current->type.data(),current->name.data(),current->args.data());
current->section = Entry::FUNCTION_SEC ;
current->proto = *yytext==';';
}
}
else // a global function prototype or function variable
{
- //printf("Scanner.l: prototype? type=`%s' name=`%s' args=`%s'\n",current->type.data(),current->name.data(),current->args.data());
+ //printf("Scanner.l: prototype? type='%s' name='%s' args='%s'\n",current->type.data(),current->name.data(),current->args.data());
if (!current->type.isEmpty() &&
(current->type.find(re,0)!=-1 || current->type.left(8)=="typedef "))
{
@@ -5147,7 +5183,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
current->proto = TRUE;
}
}
- //printf("Adding entry `%s'\n",current->name.data());
+ //printf("Adding entry '%s'\n",current->name.data());
if ( insidePHP)
{
if (findAndRemoveWord(current->type,"final"))
@@ -5344,7 +5380,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
lineCount();
//addToBody(yytext);
}
-<SkipCurly,SkipCurlyCpp>"<<<" {
+<SkipCurly,SkipCurlyCpp,ReadInitializer>"<<<" {
if (!insidePHP)
{
REJECT;
@@ -5555,7 +5591,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
current->name=current->name.left(current->name.length()-1).stripWhiteSpace();
//printf("template class declaration for %s!\n",current->name.data());
QCString rn = current_root->name.copy();
- //printf("cn=`%s' rn=`%s' isTypedef=%d\n",cn.data(),rn.data(),isTypedef);
+ //printf("cn='%s' rn='%s' isTypedef=%d\n",cn.data(),rn.data(),isTypedef);
if (!current->name.isEmpty() && !rn.isEmpty())
{
prependScope();
@@ -6771,7 +6807,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
<DocCopyBlock><<EOF>> {
warn(yyFileName,yyLineNr,
- "reached end of file while inside a `%s' block!\n"
+ "reached end of file while inside a '%s' block!\n"
"The command that should end the block seems to be missing!\n",
docBlockName.data());
yyterminate();
@@ -6849,7 +6885,6 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
- /* ------------ Generic rules -------------- */
<SkipCxxComment>.*"\\\n" { // line continuation
@@ -6867,6 +6902,15 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP})
}
<SkipComment>[^\*\n]+
+ /* ------------ Generic rules -------------- */
+
+<*>"?>"|"</script>" { // PHP code end
+ if (insidePHP)
+ BEGIN( FindMembersPHP );
+ else
+ REJECT;
+ }
+
<*>"[[" { // C++11 attribute
if (!insideCpp) REJECT;
if (YY_START == CopyGString || YY_START == CopyGString) REJECT;
@@ -7174,13 +7218,13 @@ static void parseCompounds(Entry *rt)
//memberGroupId = DOX_NOGROUP;
//memberGroupRelates.resize(0);
//memberGroupInside.resize(0);
- groupEnterCompound(yyFileName,yyLineNr,ce->name);
+ Doxygen::docGroup.enterCompound(yyFileName,yyLineNr,ce->name);
scannerYYlex() ;
g_lexInit=TRUE;
//forceEndGroup();
- groupLeaveCompound(yyFileName,yyLineNr,ce->name);
+ Doxygen::docGroup.leaveCompound(yyFileName,yyLineNr,ce->name);
delete current; current=0;
ce->program.resize(0);
@@ -7240,7 +7284,7 @@ static void parseMain(const char *fileName,
current_root = rt ;
initParser();
- groupEnterFile(yyFileName,yyLineNr);
+ Doxygen::docGroup.enterFile(yyFileName,yyLineNr);
current = new Entry;
//printf("current=%p current_root=%p\n",current,current_root);
int sec=guessSection(yyFileName);
@@ -7272,7 +7316,7 @@ static void parseMain(const char *fileName,
}
//forceEndGroup();
- groupLeaveFile(yyFileName,yyLineNr);
+ Doxygen::docGroup.leaveFile(yyFileName,yyLineNr);
//if (depthIf>0)
//{
@@ -7424,7 +7468,7 @@ bool CLanguageScanner::needsPreprocessing(const QCString &extension)
SrcLangExt lang = getLanguageFromFileName(extension);
return (SrcLangExt_Cpp == lang) ||
!( fe==".java" || fe==".as" || fe==".d" || fe==".php" ||
- fe==".php4" || fe==".inc" || fe==".phtml"
+ fe==".php4" || fe==".inc" || fe==".phtml"|| fe==".php5"
);
}
diff --git a/src/searchindex.cpp b/src/searchindex.cpp
index babefe9..b21d587 100644
--- a/src/searchindex.cpp
+++ b/src/searchindex.cpp
@@ -956,6 +956,7 @@ void createJavascriptSearchIndex()
void writeJavascriptSearchIndex()
{
int i;
+ int cnt = 0;
// write index files
QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
@@ -983,7 +984,7 @@ void writeJavascriptSearchIndex()
" \"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl;
t << "<html><head><title></title>" << endl;
t << "<meta http-equiv=\"Content-Type\" content=\"text/xhtml;charset=UTF-8\"/>" << endl;
- t << "<meta name=\"generator\" content=\"Doxygen " << versionString << "\"/>" << endl;
+ t << "<meta name=\"generator\" content=\"Doxygen " << getVersion() << "\"/>" << endl;
t << "<link rel=\"stylesheet\" type=\"text/css\" href=\"search.css\"/>" << endl;
t << "<script type=\"text/javascript\" src=\"" << baseName << ".js\"></script>" << endl;
t << "<script type=\"text/javascript\" src=\"search.js\"></script>" << endl;
@@ -1043,7 +1044,7 @@ void writeJavascriptSearchIndex()
}
firstEntry=FALSE;
- ti << " ['" << dl->id() << "',['" << convertToXML(dl->name()) << "',[";
+ ti << " ['" << dl->id() << "_" << cnt++ << "',['" << convertToXML(dl->name()) << "',[";
if (dl->count()==1) // item with a unique name
{
diff --git a/src/sqlite3gen.cpp b/src/sqlite3gen.cpp
index 9805d7f..012a0c0 100644
--- a/src/sqlite3gen.cpp
+++ b/src/sqlite3gen.cpp
@@ -924,7 +924,7 @@ static int insertPath(QCString name, bool local=TRUE, bool found=TRUE, int type=
static void recordMetadata()
{
- bindTextParameter(meta_insert,":doxygen_version",versionString);
+ bindTextParameter(meta_insert,":doxygen_version",getVersion());
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);
@@ -2009,7 +2009,11 @@ static void generateSqlite3ForClass(const ClassDef *cd)
if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName();
if (!nm.isEmpty())
{
- int header_id=insertPath(ii->fileDef->absFilePath(),!ii->fileDef->isReference());
+ int header_id=-1;
+ if (ii->fileDef)
+ {
+ 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));
diff --git a/src/tagreader.cpp b/src/tagreader.cpp
index da2f3f1..56dbe7d 100644
--- a/src/tagreader.cpp
+++ b/src/tagreader.cpp
@@ -384,7 +384,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unknown compound attribute `%s' found!",kind.data());
+ warn("Unknown compound attribute '%s' found!",kind.data());
m_state = Invalid;
}
if (isObjC=="yes" && m_curClass)
@@ -412,7 +412,7 @@ class TagFileParser : public QXmlDefaultHandler
case InPackage: m_tagFilePackages.append(m_curPackage);
m_curPackage=0; break;
default:
- warn("tag `compound' was not expected!");
+ warn("tag 'compound' was not expected!");
}
}
@@ -458,7 +458,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"); break;
+ default: warn("Unexpected tag 'member' found"); break;
}
}
@@ -476,7 +476,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Found `enumvalue' tag outside of member tag");
+ warn("Found 'enumvalue' tag outside of member tag");
}
}
@@ -504,7 +504,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 `docanchor' found"); break;
+ default: warn("Unexpected tag 'docanchor' found"); break;
}
}
@@ -517,7 +517,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"); break;
+ default: warn("Unexpected tag 'class' found"); break;
}
}
@@ -528,7 +528,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"); break;
+ default: warn("Unexpected tag 'namespace' found"); break;
}
}
@@ -538,7 +538,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"); break;
+ default: warn("Unexpected tag 'file' found"); break;
}
}
@@ -547,7 +547,7 @@ class TagFileParser : public QXmlDefaultHandler
switch(m_state)
{
case InGroup: m_curGroup->fileList.append(m_curString); break;
- default: warn("Unexpected tag `page' found"); break;
+ default: warn("Unexpected tag 'page' found"); break;
}
}
@@ -556,7 +556,7 @@ class TagFileParser : public QXmlDefaultHandler
switch(m_state)
{
case InDir: m_curDir->subdirList.append(m_curString); break;
- default: warn("Unexpected tag `dir' found"); break;
+ default: warn("Unexpected tag 'dir' found"); break;
}
}
@@ -580,7 +580,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `type' found");
+ warn("Unexpected tag 'type' found");
}
}
@@ -596,7 +596,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"); break;
+ default: warn("Unexpected tag 'name' found"); break;
}
}
@@ -630,7 +630,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `base' found");
+ warn("Unexpected tag 'base' found");
}
}
@@ -642,7 +642,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `base' found");
+ warn("Unexpected tag 'base' found");
}
}
@@ -659,7 +659,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `includes' found");
+ warn("Unexpected tag 'includes' found");
}
m_curString="";
}
@@ -682,7 +682,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `templarg' found");
+ warn("Unexpected tag 'templarg' found");
}
}
@@ -697,7 +697,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"); break;
+ default: warn("Unexpected tag 'filename' found"); break;
}
}
@@ -707,7 +707,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"); break;
+ default: warn("Unexpected tag 'path' found"); break;
}
}
@@ -723,7 +723,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `anchor' found");
+ warn("Unexpected tag 'anchor' found");
}
}
@@ -743,7 +743,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `clangid' found");
+ warn("Unexpected tag 'clangid' found");
}
}
@@ -757,7 +757,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `anchorfile' found");
+ warn("Unexpected tag 'anchorfile' found");
}
}
@@ -769,7 +769,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `arglist' found");
+ warn("Unexpected tag 'arglist' found");
}
}
void endTitle()
@@ -778,7 +778,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"); break;
+ default: warn("Unexpected tag 'title' found"); break;
}
}
@@ -790,7 +790,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unexpected tag `subgroup' found");
+ warn("Unexpected tag 'subgroup' found");
}
}
@@ -877,7 +877,7 @@ class TagFileParser : public QXmlDefaultHandler
bool startElement( const QString&, const QString&,
const QString&name, const QXmlAttributes& attrib )
{
- //printf("startElement `%s'\n",name.data());
+ //printf("startElement '%s'\n",name.data());
StartElementHandler *handler = m_startElementHandlers[name.utf8()];
if (handler)
{
@@ -885,14 +885,14 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unknown tag `%s' found!",name.data());
+ warn("Unknown tag '%s' found!",name.data());
}
return TRUE;
}
bool endElement( const QString&, const QString&, const QString& name )
{
- //printf("endElement `%s'\n",name.data());
+ //printf("endElement '%s'\n",name.data());
EndElementHandler *handler = m_endElementHandlers[name.utf8()];
if (handler)
{
@@ -900,7 +900,7 @@ class TagFileParser : public QXmlDefaultHandler
}
else
{
- warn("Unknown tag `%s' found!",name.data());
+ warn("Unknown tag '%s' found!",name.data());
}
return TRUE;
}
@@ -986,8 +986,8 @@ void TagFileParser::dump()
TagClassInfo *cd;
for (;(cd=lci.current());++lci)
{
- msg("class `%s'\n",cd->name.data());
- msg(" filename `%s'\n",cd->filename.data());
+ msg("class '%s'\n",cd->name.data());
+ msg(" filename '%s'\n",cd->filename.data());
if (cd->bases)
{
QListIterator<BaseInfo> bii(*cd->bases);
@@ -1003,10 +1003,10 @@ void TagFileParser::dump()
for (;(md=mci.current());++mci)
{
msg(" member:\n");
- msg(" kind: `%s'\n",md->kind.data());
- msg(" name: `%s'\n",md->name.data());
- msg(" anchor: `%s'\n",md->anchor.data());
- msg(" arglist: `%s'\n",md->arglist.data());
+ msg(" kind: '%s'\n",md->kind.data());
+ msg(" name: '%s'\n",md->name.data());
+ msg(" anchor: '%s'\n",md->anchor.data());
+ msg(" arglist: '%s'\n",md->arglist.data());
}
}
//============== NAMESPACES
@@ -1014,8 +1014,8 @@ void TagFileParser::dump()
TagNamespaceInfo *nd;
for (;(nd=lni.current());++lni)
{
- msg("namespace `%s'\n",nd->name.data());
- msg(" filename `%s'\n",nd->filename.data());
+ msg("namespace '%s'\n",nd->name.data());
+ msg(" filename '%s'\n",nd->filename.data());
QCStringList::Iterator it;
for ( it = nd->classList.begin();
it != nd->classList.end(); ++it )
@@ -1028,10 +1028,10 @@ void TagFileParser::dump()
for (;(md=mci.current());++mci)
{
msg(" member:\n");
- msg(" kind: `%s'\n",md->kind.data());
- msg(" name: `%s'\n",md->name.data());
- msg(" anchor: `%s'\n",md->anchor.data());
- msg(" arglist: `%s'\n",md->arglist.data());
+ msg(" kind: '%s'\n",md->kind.data());
+ msg(" name: '%s'\n",md->name.data());
+ msg(" anchor: '%s'\n",md->anchor.data());
+ msg(" arglist: '%s'\n",md->arglist.data());
}
}
//============== FILES
@@ -1039,8 +1039,8 @@ void TagFileParser::dump()
TagFileInfo *fd;
for (;(fd=lfi.current());++lfi)
{
- msg("file `%s'\n",fd->name.data());
- msg(" filename `%s'\n",fd->filename.data());
+ msg("file '%s'\n",fd->name.data());
+ msg(" filename '%s'\n",fd->filename.data());
QCStringList::Iterator it;
for ( it = fd->namespaceList.begin();
it != fd->namespaceList.end(); ++it )
@@ -1058,10 +1058,10 @@ void TagFileParser::dump()
for (;(md=mci.current());++mci)
{
msg(" member:\n");
- msg(" kind: `%s'\n",md->kind.data());
- msg(" name: `%s'\n",md->name.data());
- msg(" anchor: `%s'\n",md->anchor.data());
- msg(" arglist: `%s'\n",md->arglist.data());
+ msg(" kind: '%s'\n",md->kind.data());
+ msg(" name: '%s'\n",md->name.data());
+ msg(" anchor: '%s'\n",md->anchor.data());
+ msg(" arglist: '%s'\n",md->arglist.data());
}
QListIterator<TagIncludeInfo> mii(fd->includes);
@@ -1077,8 +1077,8 @@ void TagFileParser::dump()
TagGroupInfo *gd;
for (;(gd=lgi.current());++lgi)
{
- msg("group `%s'\n",gd->name.data());
- msg(" filename `%s'\n",gd->filename.data());
+ msg("group '%s'\n",gd->name.data());
+ msg(" filename '%s'\n",gd->filename.data());
QCStringList::Iterator it;
for ( it = gd->namespaceList.begin();
it != gd->namespaceList.end(); ++it )
@@ -1111,10 +1111,10 @@ void TagFileParser::dump()
for (;(md=mci.current());++mci)
{
msg(" member:\n");
- msg(" kind: `%s'\n",md->kind.data());
- msg(" name: `%s'\n",md->name.data());
- msg(" anchor: `%s'\n",md->anchor.data());
- msg(" arglist: `%s'\n",md->arglist.data());
+ msg(" kind: '%s'\n",md->kind.data());
+ msg(" name: '%s'\n",md->name.data());
+ msg(" anchor: '%s'\n",md->anchor.data());
+ msg(" arglist: '%s'\n",md->arglist.data());
}
}
//============== PAGES
@@ -1122,17 +1122,17 @@ void TagFileParser::dump()
TagPageInfo *pd;
for (;(pd=lpi.current());++lpi)
{
- msg("page `%s'\n",pd->name.data());
- msg(" title `%s'\n",pd->title.data());
- msg(" filename `%s'\n",pd->filename.data());
+ msg("page '%s'\n",pd->name.data());
+ msg(" title '%s'\n",pd->title.data());
+ msg(" filename '%s'\n",pd->filename.data());
}
//============== DIRS
QListIterator<TagDirInfo> ldi(m_tagFileDirs);
TagDirInfo *dd;
for (;(dd=ldi.current());++ldi)
{
- msg("dir `%s'\n",dd->name.data());
- msg(" path `%s'\n",dd->path.data());
+ msg("dir '%s'\n",dd->name.data());
+ msg(" path '%s'\n",dd->path.data());
QCStringList::Iterator it;
for ( it = dd->fileList.begin();
it != dd->fileList.end(); ++it )
@@ -1527,7 +1527,7 @@ void TagFileParser::addIncludes()
TagIncludeInfo *ii;
for (;(ii=mii.current());++mii)
{
- //printf("ii->name=`%s'\n",ii->name.data());
+ //printf("ii->name='%s'\n",ii->name.data());
FileName *ifn = Doxygen::inputNameDict->find(ii->name);
ASSERT(ifn!=0);
if (ifn)
diff --git a/src/tclscanner.l b/src/tclscanner.l
index df52201..88bd474 100644
--- a/src/tclscanner.l
+++ b/src/tclscanner.l
@@ -486,7 +486,7 @@ Entry* tcl_entry_new()
// myEntry->stat = FALSE;
myEntry->fileName = tcl.file_name;
myEntry->lang = SrcLangExt_Tcl;
- initGroupInfo(myEntry);
+ Doxygen::docGroup.initGroupInfo(myEntry);
// collect entries
if (!tcl.code)
{
@@ -1049,7 +1049,7 @@ D
tcl.string_commentcodify = "";
tcl.string_commentline = "";
tcl.line_body1=yylineno;
- tcl_command(-1,"");
+ tcl_command(-1,yytext);
}
<COMMAND>{ws}*; {
D
@@ -2274,21 +2274,22 @@ D
}
//! Handle \c namespace statements.
-static void tcl_command_NAMESPACE()
+static bool tcl_command_NAMESPACE()
{
D
QCString myNs, myName, myStr;
//Entry *myEntryNs=NULL;
tcl_scan *myScan = tcl.scan.at(0);
+ tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)),myNs,myName);
+ if (myName.isEmpty()) return false; // not a namespace
tcl_codify_cmd("keyword",0);
tcl_codify_cmd(NULL,1);
tcl_codify_cmd("keyword",2);
tcl_codify_cmd(NULL,3);
tcl_codify_cmd(NULL,4);
tcl_codify_cmd(NULL,5);
- tcl_name(myScan->ns,(*tcl.list_commandwords.at(4)),myNs,myName);
- if (myNs.length())
+ if (!myNs.isEmpty())
{
myName = myNs+"::"+myName;
}
@@ -2310,6 +2311,7 @@ D
tcl.word_is=' ';
}
myScan = tcl_scan_start(tcl.word_is,myStr, myName, NULL, NULL);
+ return true;
}
//! Handle \c itcl::class statements.
@@ -2636,11 +2638,16 @@ tcl_inf("->\n");
if ((*tcl.list_commandwords.at(2))=="eval")
{
if (tcl.list_commandwords.count() < 7) {myLine=__LINE__;goto command_warn;}
- tcl_command_NAMESPACE();
+ if (tcl_command_NAMESPACE())
+ {
+ goto command_end;
+ }
+ }
+ else
+ {
+ tcl_command_OTHER();
goto command_end;
}
- tcl_command_OTHER();
- goto command_end;
}
if (myStr=="itcl::class")
{
@@ -2950,7 +2957,7 @@ tcl_inf("%s\n",fileName);
printlex(yy_flex_debug, TRUE, __FILE__, fileName);
msg("Parsing %s...\n",fileName);
- groupEnterFile(fileName,yylineno);
+ Doxygen::docGroup.enterFile(fileName,yylineno);
tcl_init();
tcl.code = NULL;
@@ -2958,7 +2965,7 @@ tcl_inf("%s\n",fileName);
tcl.this_parser = this;
tcl.entry_main = root; /* toplevel entry */
tcl_parse("","");
- groupLeaveFile(tcl.file_name,yylineno);
+ Doxygen::docGroup.leaveFile(tcl.file_name,yylineno);
root->program.resize(0);
myFile.close();
printlex(yy_flex_debug, FALSE, __FILE__, fileName);
diff --git a/src/template.cpp b/src/template.cpp
index b1435ce..228da4d 100644
--- a/src/template.cpp
+++ b/src/template.cpp
@@ -2832,7 +2832,7 @@ template<class T> class TemplateNodeCreator : public TemplateNode
rootDir.setPath(QDir::currentDirPath());
if (!rootDir.mkdir(outputDir))
{
- err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
+ err("tag OUTPUT_DIRECTORY: Output directory '%s' does not "
"exist and cannot be created\n",outputDir.data());
return;
}
diff --git a/src/textdocvisitor.h b/src/textdocvisitor.h
index bbc70e8..c4ba3d7 100644
--- a/src/textdocvisitor.h
+++ b/src/textdocvisitor.h
@@ -125,8 +125,6 @@ class TextDocVisitor : public DocVisitor
void visitPost(DocXRefItem *) {}
void visitPre(DocInternalRef *) {}
void visitPost(DocInternalRef *) {}
- void visitPre(DocCopy *) {}
- void visitPost(DocCopy *) {}
void visitPre(DocText *) {}
void visitPost(DocText *) {}
void visitPre(DocHtmlBlockQuote *) {}
diff --git a/src/util.cpp b/src/util.cpp
index d458877..5808815 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -184,7 +184,7 @@ QCString removeAnonymousScopes(const QCString &s)
p=i+l;
}
result+=s.right(sl-p);
- //printf("removeAnonymousScopes(`%s')=`%s'\n",s.data(),result.data());
+ //printf("removeAnonymousScopes('%s')='%s'\n",s.data(),result.data());
return result;
}
@@ -210,7 +210,7 @@ QCString replaceAnonymousScopes(const QCString &s,const char *replacement)
p=i+l;
}
result+=s.right(sl-p);
- //printf("replaceAnonymousScopes(`%s')=`%s'\n",s.data(),result.data());
+ //printf("replaceAnonymousScopes('%s')='%s'\n",s.data(),result.data());
return result;
}
@@ -241,7 +241,7 @@ QCString stripAnonymousNamespaceScope(const QCString &s)
p=i+l;
}
done:
- //printf("stripAnonymousNamespaceScope(`%s')=`%s'\n",s.data(),newScope.data());
+ //printf("stripAnonymousNamespaceScope('%s')='%s'\n",s.data(),newScope.data());
return newScope;
}
@@ -383,7 +383,7 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
{
// split-off scope part
QCString resScopeName = qualifiedName.left(scopeIndex);
- //printf("resScopeName=`%s'\n",resScopeName.data());
+ //printf("resScopeName='%s'\n",resScopeName.data());
// look-up scope in context
int is,ps=0;
@@ -394,7 +394,7 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
QCString tmp = resolveTypeDef(mContext,qualScopePart);
if (!tmp.isEmpty()) qualScopePart=tmp;
resScope = resScope->findInnerCompound(qualScopePart);
- //printf("qualScopePart=`%s' resScope=%p\n",qualScopePart.data(),resScope);
+ //printf("qualScopePart='%s' resScope=%p\n",qualScopePart.data(),resScope);
if (resScope==0) break;
ps=is+l;
}
@@ -444,7 +444,7 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
// step 3: get the member's type
if (md)
{
- //printf(">>resolveTypeDef: Found typedef name `%s' in scope `%s' value=`%s' args='%s'\n",
+ //printf(">>resolveTypeDef: Found typedef name '%s' in scope '%s' value='%s' args='%s'\n",
// qualifiedName.data(),context->name().data(),md->typeString(),md->argsString()
// );
result=md->typeString();
@@ -461,7 +461,7 @@ QCString resolveTypeDef(const Definition *context,const QCString &qualifiedName,
}
else
{
- //printf(">>resolveTypeDef: Typedef `%s' not found in scope `%s'!\n",
+ //printf(">>resolveTypeDef: Typedef '%s' not found in scope '%s'!\n",
// qualifiedName.data(),context ? context->name().data() : "<global>");
}
return result;
@@ -518,10 +518,10 @@ static QDict<MemberDef> g_resolvedTypedefs;
static QDict<Definition> g_visitedNamespaces;
// forward declaration
-static ClassDef *getResolvedClassRec(const Definition *scope,
+static const ClassDef *getResolvedClassRec(const Definition *scope,
const FileDef *fileScope,
const char *n,
- MemberDef **pTypeDef,
+ const MemberDef **pTypeDef,
QCString *pTemplSpec,
QCString *pResolvedType
);
@@ -535,10 +535,12 @@ int isAccessibleFromWithExpScope(const Definition *scope,const FileDef *fileScop
*
* Example: typedef int T; will return 0, since "int" is not a class.
*/
-ClassDef *newResolveTypedef(const FileDef *fileScope,MemberDef *md,
- MemberDef **pMemType,QCString *pTemplSpec,
- QCString *pResolvedType,
- ArgumentList *actTemplParams)
+const ClassDef *newResolveTypedef(const FileDef *fileScope,
+ const MemberDef *md,
+ const MemberDef **pMemType,
+ QCString *pTemplSpec,
+ QCString *pResolvedType,
+ ArgumentList *actTemplParams)
{
//printf("newResolveTypedef(md=%p,cachedVal=%p)\n",md,md->getCachedTypedefVal());
bool isCached = md->isTypedefValCached(); // value already cached
@@ -581,8 +583,8 @@ ClassDef *newResolveTypedef(const FileDef *fileScope,MemberDef *md,
int sp=0;
tl=type.length(); // length may have been changed
while (sp<tl && type.at(sp)==' ') sp++;
- MemberDef *memTypeDef = 0;
- ClassDef *result = getResolvedClassRec(md->getOuterScope(),
+ const MemberDef *memTypeDef = 0;
+ const ClassDef *result = getResolvedClassRec(md->getOuterScope(),
fileScope,type,&memTypeDef,0,pResolvedType);
// if type is a typedef then return what it resolves to.
if (memTypeDef && memTypeDef->isTypedef())
@@ -652,7 +654,7 @@ done:
//printf("setting cached typedef %p in result %p\n",md,result);
//printf("==> %s (%s,%d)\n",result->name().data(),result->getDefFileName().data(),result->getDefLine());
//printf("*pResolvedType=%s\n",pResolvedType?pResolvedType->data():"<none>");
- md->cacheTypedefVal(result,
+ const_cast<MemberDef*>(md)->cacheTypedefVal(result,
pTemplSpec ? *pTemplSpec : QCString(),
pResolvedType ? *pResolvedType : QCString()
);
@@ -667,7 +669,7 @@ done:
* value of the typedef or \a name if no typedef was found.
*/
static QCString substTypedef(const Definition *scope,const FileDef *fileScope,const QCString &name,
- MemberDef **pTypeDef=0)
+ const MemberDef **pTypeDef=0)
{
QCString result=name;
if (name.isEmpty()) return result;
@@ -763,12 +765,12 @@ static const Definition *followPath(const Definition *start,const FileDef *fileS
while ((is=getScopeFragment(path,ps,&l))!=-1)
{
// try to resolve the part if it is a typedef
- MemberDef *typeDef=0;
+ const MemberDef *typeDef=0;
QCString qualScopePart = substTypedef(current,fileScope,path.mid(is,l),&typeDef);
//printf(" qualScopePart=%s\n",qualScopePart.data());
if (typeDef)
{
- ClassDef *type = newResolveTypedef(fileScope,typeDef);
+ const ClassDef *type = newResolveTypedef(fileScope,typeDef);
if (type)
{
//printf("Found type %s\n",type->name().data());
@@ -1218,8 +1220,8 @@ static void getResolvedSymbol(const Definition *scope,
const QCString &explicitScopePart,
ArgumentList *actTemplParams,
int &minDistance,
- ClassDef *&bestMatch,
- MemberDef *&bestTypedef,
+ const ClassDef *&bestMatch,
+ const MemberDef *&bestTypedef,
QCString &bestTemplSpec,
QCString &bestResolvedType
)
@@ -1306,8 +1308,8 @@ static void getResolvedSymbol(const Definition *scope,
QCString spec;
QCString type;
minDistance=distance;
- MemberDef *enumType = 0;
- ClassDef *cd = newResolveTypedef(fileScope,md,&enumType,&spec,&type,actTemplParams);
+ const MemberDef *enumType = 0;
+ const ClassDef *cd = newResolveTypedef(fileScope,md,&enumType,&spec,&type,actTemplParams);
if (cd) // type resolves to a class
{
//printf(" bestTypeDef=%p spec=%s type=%s\n",md,spec.data(),type.data());
@@ -1377,10 +1379,10 @@ static void getResolvedSymbol(const Definition *scope,
* match against the input name. Can recursively call itself when
* resolving typedefs.
*/
-static ClassDef *getResolvedClassRec(const Definition *scope,
+static const ClassDef *getResolvedClassRec(const Definition *scope,
const FileDef *fileScope,
const char *n,
- MemberDef **pTypeDef,
+ const MemberDef **pTypeDef,
QCString *pTemplSpec,
QCString *pResolvedType
)
@@ -1499,8 +1501,8 @@ static ClassDef *getResolvedClassRec(const Definition *scope,
Doxygen::lookupCache->insert(key,new LookupInfo);
}
- ClassDef *bestMatch=0;
- MemberDef *bestTypedef=0;
+ const ClassDef *bestMatch=0;
+ const MemberDef *bestTypedef=0;
QCString bestTemplSpec;
QCString bestResolvedType;
int minDistance=10000; // init at "infinite"
@@ -1566,10 +1568,10 @@ static ClassDef *getResolvedClassRec(const Definition *scope,
* Loops through scope and each of its parent scopes looking for a
* match against the input name.
*/
-ClassDef *getResolvedClass(const Definition *scope,
+const ClassDef *getResolvedClass(const Definition *scope,
const FileDef *fileScope,
const char *n,
- MemberDef **pTypeDef,
+ const MemberDef **pTypeDef,
QCString *pTemplSpec,
bool mayBeUnlinkable,
bool mayBeHidden,
@@ -1593,7 +1595,7 @@ ClassDef *getResolvedClass(const Definition *scope,
// n,
// mayBeUnlinkable
// );
- ClassDef *result;
+ const ClassDef *result;
if (optimizeOutputVhdl)
{
result = getClass(n);
@@ -1675,6 +1677,7 @@ struct CharAroundSpace
charMap['='].after=FALSE;
charMap[' '].after=FALSE;
+ charMap['['].after=FALSE;
charMap[']'].after=FALSE;
charMap['\t'].after=FALSE;
charMap['\n'].after=FALSE;
@@ -2015,7 +2018,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
const char *text, bool autoBreak,bool external,
bool keepSpaces,int indentLevel)
{
- //printf("linkify=`%s'\n",text);
+ //printf("linkify='%s'\n",text);
static QRegExp regExp("[a-z_A-Z\\x80-\\xFF][~!a-z_A-Z0-9$\\\\.:\\x80-\\xFF]*");
static QRegExp regExpSplit("(?!:),");
QCString txtStr=text;
@@ -2031,12 +2034,17 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
int floatingIndex=0;
if (strLen==0) return;
// read a word from the text string
- while ((newIndex=regExp.match(txtStr,index,&matchLen))!=-1 &&
- (newIndex==0 || !(txtStr.at(newIndex-1)>='0' && txtStr.at(newIndex-1)<='9')) // avoid matching part of hex numbers
- )
+ while ((newIndex=regExp.match(txtStr,index,&matchLen))!=-1)
{
- // add non-word part to the result
floatingIndex+=newIndex-skipIndex+matchLen;
+ if (newIndex>0 && txtStr.at(newIndex-1)=='0') // ignore hex numbers (match x00 in 0x00)
+ {
+ out.writeString(txtStr.mid(skipIndex,newIndex+matchLen-skipIndex),keepSpaces);
+ skipIndex=index=newIndex+matchLen;
+ continue;
+ }
+
+ // add non-word part to the result
bool insideString=FALSE;
int i;
for (i=index;i<newIndex;i++)
@@ -2087,7 +2095,7 @@ void linkifyText(const TextGeneratorIntf &out, const Definition *scope,
const GroupDef *gd=0;
//printf("** Match word '%s'\n",matchWord.data());
- MemberDef *typeDef=0;
+ const MemberDef *typeDef=0;
cd=getResolvedClass(scope,fileScope,matchWord,&typeDef);
if (typeDef) // First look at typedef then class, see bug 584184.
{
@@ -2559,7 +2567,7 @@ QCString fileToString(const char *name,bool filter,bool isSourceCode)
QFileInfo fi(name);
if (!fi.exists() || !fi.isFile())
{
- err("file `%s' not found\n",name);
+ err("file '%s' not found\n",name);
return "";
}
BufStr buf(fi.size());
@@ -2577,7 +2585,7 @@ QCString fileToString(const char *name,bool filter,bool isSourceCode)
}
if (!fileOpened)
{
- err("cannot open file `%s' for reading\n",name);
+ err("cannot open file '%s' for reading\n",name);
}
return "";
}
@@ -2634,7 +2642,7 @@ QCString yearToString()
//----------------------------------------------------------------------
// recursive function that returns the number of branches in the
-// inheritance tree that the base class `bcd' is below the class `cd'
+// inheritance tree that the base class 'bcd' is below the class 'cd'
int minClassDistance(const ClassDef *cd,const ClassDef *bcd,int level)
{
@@ -2705,7 +2713,7 @@ exit:
// printf("(");
// for (;(a=ali.current());++ali)
// {
-// printf("t=`%s' n=`%s' v=`%s' ",a->type.data(),!a->name.isEmpty()>0?a->name.data():"",!a->defval.isEmpty()>0?a->defval.data():"");
+// printf("t='%s' n='%s' v='%s' ",a->type.data(),!a->name.isEmpty()>0?a->name.data():"",!a->defval.isEmpty()>0?a->defval.data():"");
// }
// printf(")");
//}
@@ -2851,7 +2859,7 @@ static QCString trimScope(const QCString &name,const QCString &s)
{
QCString tmp;
QCString scope=name.left(scopeOffset)+"::";
- //printf("Trying with scope=`%s'\n",scope.data());
+ //printf("Trying with scope='%s'\n",scope.data());
int i,p=0,l;
while ((i=findScopePattern(scope,result,p,&l))!=-1) // for each occurrence
@@ -2871,7 +2879,7 @@ static QCString trimScope(const QCString &name,const QCString &s)
void trimBaseClassScope(BaseClassList *bcl,QCString &s,int level=0)
{
- //printf("trimBaseClassScope level=%d `%s'\n",level,s.data());
+ //printf("trimBaseClassScope level=%d '%s'\n",level,s.data());
BaseClassListIterator bcli(*bcl);
BaseClassDef *bcd;
for (;(bcd=bcli.current());++bcli)
@@ -2885,7 +2893,7 @@ void trimBaseClassScope(BaseClassList *bcl,QCString &s,int level=0)
s.length()-spos-cd->name().length()-2
);
}
- //printf("base class `%s'\n",cd->name().data());
+ //printf("base class '%s'\n",cd->name().data());
if (cd->baseClasses())
trimBaseClassScope(cd->baseClasses(),s,level+1);
}
@@ -3042,7 +3050,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA,
NamespaceSDict *usingNamespaces,
SDict<Definition> *usingClasses)
{
- //printf("match argument start `%s|%s' <-> `%s|%s' using nsp=%p class=%p\n",
+ //printf("match argument start '%s|%s' <-> '%s|%s' using nsp=%p class=%p\n",
// srcA->type.data(),srcA->name.data(),
// dstA->type.data(),dstA->name.data(),
// usingNamespaces,
@@ -3104,7 +3112,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA,
//srcAType=stripTemplateSpecifiersFromScope(srcAType,FALSE);
//dstAType=stripTemplateSpecifiersFromScope(dstAType,FALSE);
- //printf("srcA=`%s|%s' dstA=`%s|%s'\n",srcAType.data(),srcAName.data(),
+ //printf("srcA='%s|%s' dstA='%s|%s'\n",srcAType.data(),srcAName.data(),
// dstAType.data(),dstAName.data());
if (srcA->array!=dstA->array) // nomatch for char[] against char
@@ -3129,7 +3137,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA,
{
srcAType=trimScope(className,srcAType);
dstAType=trimScope(className,dstAType);
- //printf("trimScope: `%s' <=> `%s'\n",srcAType.data(),dstAType.data());
+ //printf("trimScope: '%s' <=> '%s'\n",srcAType.data(),dstAType.data());
ClassDef *cd;
if (!namespaceName.isEmpty())
cd=getClass(namespaceName+"::"+className);
@@ -3140,7 +3148,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA,
trimBaseClassScope(cd->baseClasses(),srcAType);
trimBaseClassScope(cd->baseClasses(),dstAType);
}
- //printf("trimBaseClassScope: `%s' <=> `%s'\n",srcAType.data(),dstAType.data());
+ //printf("trimBaseClassScope: '%s' <=> '%s'\n",srcAType.data(),dstAType.data());
}
if (!namespaceName.isEmpty())
{
@@ -3233,7 +3241,7 @@ static bool matchArgument(const Argument *srcA,const Argument *dstA,
while (dstPos<dstATypeLen && isId(dstAType.at(dstPos))) dstPos++;
// if nothing more follows for both types then we assume we have
- // found a match. Note that now `signed int' and `signed' match, but
+ // found a match. Note that now 'signed int' and 'signed' match, but
// seeing that int is not a name can only be done by looking at the
// semantics.
@@ -3495,8 +3503,8 @@ static QCString getCanonicalTypeForIdentifier(
//printf("getCanonicalTypeForIdentifier(%s,[%s->%s]) start\n",
// word.data(),tSpec?tSpec->data():"<none>",templSpec.data());
- ClassDef *cd = 0;
- MemberDef *mType = 0;
+ const ClassDef *cd = 0;
+ const MemberDef *mType = 0;
QCString ts;
QCString resolvedType;
@@ -3708,7 +3716,7 @@ static bool matchArgument2(
const Definition *dstScope,const FileDef *dstFileScope,Argument *dstA
)
{
- //printf(">> match argument: %s::`%s|%s' (%s) <-> %s::`%s|%s' (%s)\n",
+ //printf(">> match argument: %s::'%s|%s' (%s) <-> %s::'%s|%s' (%s)\n",
// srcScope ? srcScope->name().data() : "",
// srcA->type.data(),srcA->name.data(),srcA->canType.data(),
// dstScope ? dstScope->name().data() : "",
@@ -3857,7 +3865,7 @@ bool matchArguments2(const Definition *srcScope,const FileDef *srcFileScope,cons
// pre: the types of the arguments in the list should match.
void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwrite)
{
- //printf("mergeArguments `%s', `%s'\n",
+ //printf("mergeArguments '%s', '%s'\n",
// argListToString(srcAl).data(),argListToString(dstAl).data());
if (srcAl==0 || dstAl==0 || srcAl->count()!=dstAl->count())
@@ -3871,12 +3879,12 @@ void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwr
{
if (srcA->defval.isEmpty() && !dstA->defval.isEmpty())
{
- //printf("Defval changing `%s'->`%s'\n",srcA->defval.data(),dstA->defval.data());
+ //printf("Defval changing '%s'->'%s'\n",srcA->defval.data(),dstA->defval.data());
srcA->defval=dstA->defval.copy();
}
else if (!srcA->defval.isEmpty() && dstA->defval.isEmpty())
{
- //printf("Defval changing `%s'->`%s'\n",dstA->defval.data(),srcA->defval.data());
+ //printf("Defval changing '%s'->'%s'\n",dstA->defval.data(),srcA->defval.data());
dstA->defval=srcA->defval.copy();
}
@@ -3898,15 +3906,15 @@ void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwr
//printf("1. merging %s:%s <-> %s:%s\n",srcA->type.data(),srcA->name.data(),dstA->type.data(),dstA->name.data());
if (srcA->name.isEmpty() && !dstA->name.isEmpty())
{
- //printf("type: `%s':=`%s'\n",srcA->type.data(),dstA->type.data());
- //printf("name: `%s':=`%s'\n",srcA->name.data(),dstA->name.data());
+ //printf("type: '%s':='%s'\n",srcA->type.data(),dstA->type.data());
+ //printf("name: '%s':='%s'\n",srcA->name.data(),dstA->name.data());
srcA->type = dstA->type.copy();
srcA->name = dstA->name.copy();
}
else if (!srcA->name.isEmpty() && dstA->name.isEmpty())
{
- //printf("type: `%s':=`%s'\n",dstA->type.data(),srcA->type.data());
- //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
+ //printf("type: '%s':='%s'\n",dstA->type.data(),srcA->type.data());
+ //printf("name: '%s':='%s'\n",dstA->name.data(),srcA->name.data());
dstA->type = srcA->type.copy();
dstA->name = dstA->name.copy();
}
@@ -3960,15 +3968,15 @@ void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwr
j2=dstA->type.length()-i2-2;
if (i1!=-1 && i2==-1 && srcA->type.right(j1)==dstA->type)
{
- //printf("type: `%s':=`%s'\n",dstA->type.data(),srcA->type.data());
- //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
+ //printf("type: '%s':='%s'\n",dstA->type.data(),srcA->type.data());
+ //printf("name: '%s':='%s'\n",dstA->name.data(),srcA->name.data());
dstA->type = srcA->type.left(i1+2)+dstA->type;
dstA->name = dstA->name.copy();
}
else if (i1==-1 && i2!=-1 && dstA->type.right(j2)==srcA->type)
{
- //printf("type: `%s':=`%s'\n",srcA->type.data(),dstA->type.data());
- //printf("name: `%s':=`%s'\n",dstA->name.data(),srcA->name.data());
+ //printf("type: '%s':='%s'\n",srcA->type.data(),dstA->type.data());
+ //printf("name: '%s':='%s'\n",dstA->name.data(),srcA->name.data());
srcA->type = dstA->type.left(i2+2)+srcA->type;
srcA->name = dstA->name.copy();
}
@@ -3980,7 +3988,7 @@ void mergeArguments(ArgumentList *srcAl,ArgumentList *dstAl,bool forceNameOverwr
{
dstA->docs = srcA->docs.copy();
}
- //printf("Merge argument `%s|%s' `%s|%s'\n",
+ //printf("Merge argument '%s|%s' '%s|%s'\n",
// srcA->type.data(),srcA->name.data(),
// dstA->type.data(),dstA->name.data());
}
@@ -3994,7 +4002,7 @@ static void findMembersWithSpecificName(MemberName *mn,
const char *forceTagFile,
QList<MemberDef> &members)
{
- //printf(" Function with global scope name `%s' args=`%s'\n",
+ //printf(" Function with global scope name '%s' args='%s'\n",
// mn->memberName(),args);
MemberNameIterator mli(*mn);
const MemberDef *md = 0;
@@ -4002,7 +4010,7 @@ static void findMembersWithSpecificName(MemberName *mn,
{
const FileDef *fd=md->getFileDef();
const GroupDef *gd=md->getGroupDef();
- //printf(" md->name()=`%s' md->args=`%s' fd=%p gd=%p current=%p ref=%s\n",
+ //printf(" md->name()='%s' md->args='%s' fd=%p gd=%p current=%p ref=%s\n",
// md->name().data(),args,fd,gd,currentFile,md->getReference().data());
if (
((gd && gd->isLinkable()) || (fd && fd->isLinkable()) || md->isReference()) &&
@@ -4034,11 +4042,11 @@ static void findMembersWithSpecificName(MemberName *mn,
}
/*!
- * Searches for a member definition given its name `memberName' as a string.
+ * Searches for a member definition given its name 'memberName' as a string.
* memberName may also include a (partial) scope to indicate the scope
* in which the member is located.
*
- * The parameter `scName' is a string representing the name of the scope in
+ * The parameter 'scName' is a string representing the name of the scope in
* which the link was found.
*
* In case of a function args contains a string representation of the
@@ -4047,12 +4055,12 @@ static void findMembersWithSpecificName(MemberName *mn,
*
* The function returns TRUE if the member is known and documented or
* FALSE if it is not.
- * If TRUE is returned parameter `md' contains a pointer to the member
- * definition. Furthermore exactly one of the parameter `cd', `nd', or `fd'
+ * If TRUE is returned parameter 'md' contains a pointer to the member
+ * definition. Furthermore exactly one of the parameter 'cd', 'nd', or 'fd'
* will be non-zero:
- * - if `cd' is non zero, the member was found in a class pointed to by cd.
- * - if `nd' is non zero, the member was found in a namespace pointed to by nd.
- * - if `fd' is non zero, the member was found in the global namespace of
+ * - if 'cd' is non zero, the member was found in a class pointed to by cd.
+ * - if 'nd' is non zero, the member was found in a namespace pointed to by nd.
+ * - if 'fd' is non zero, the member was found in the global namespace of
* file fd.
*/
bool getDefs(const QCString &scName,
@@ -4107,7 +4115,7 @@ bool getDefs(const QCString &scName,
// handle special the case where both scope name and member scope are equal
if (mScope==scopeName) scopeName.resize(0);
- //printf("mScope=`%s' mName=`%s'\n",mScope.data(),mName.data());
+ //printf("mScope='%s' mName='%s'\n",mScope.data(),mName.data());
MemberName *mn = Doxygen::memberNameSDict->find(mName);
//printf("mName=%s mn=%p\n",mName.data(),mn);
@@ -4129,8 +4137,8 @@ bool getDefs(const QCString &scName,
className=mScope;
}
- MemberDef *tmd=0;
- ClassDef *fcd=getResolvedClass(Doxygen::globalScope,0,className,&tmd);
+ const MemberDef *tmd=0;
+ const ClassDef *fcd=getResolvedClass(Doxygen::globalScope,0,className,&tmd);
if (fcd==0 && className.find('<')!=-1) // try without template specifiers as well
{
QCString nameWithoutTemplates = stripTemplateSpecifiersFromScope(className,FALSE);
@@ -4308,7 +4316,7 @@ bool getDefs(const QCString &scName,
// maybe an namespace, file or group member ?
- //printf("Testing for global symbol scopeName=`%s' mScope=`%s' :: mName=`%s'\n",
+ //printf("Testing for global symbol scopeName='%s' mScope='%s' :: mName='%s'\n",
// scopeName.data(),mScope.data(),mName.data());
if ((mn=Doxygen::functionNameSDict->find(mName))) // name is known
{
@@ -4332,7 +4340,7 @@ bool getDefs(const QCString &scName,
fnd->isLinkable()
)
{
- //printf("Symbol inside existing namespace `%s' count=%d\n",
+ //printf("Symbol inside existing namespace '%s' count=%d\n",
// namespaceName.data(),mn->count());
bool found=FALSE;
MemberNameIterator mmli(*mn);
@@ -4473,8 +4481,8 @@ bool getDefs(const QCString &scName,
MemberNameIterator mni(*mn);
for (mni.toLast();(md=mni.current());--mni)
{
- //printf("Found member `%s'\n",md->name().data());
- //printf("member is linkable md->name()=`%s'\n",md->name().data());
+ //printf("Found member '%s'\n",md->name().data());
+ //printf("member is linkable md->name()='%s'\n",md->name().data());
fd=md->getFileDef();
gd=md->getGroupDef();
const MemberDef *tmd = md->getEnumScope();
@@ -4547,7 +4555,7 @@ static bool getScopeDefs(const char *docScope,const char *scope,
cd=0;nd=0;
QCString scopeName=scope;
- //printf("getScopeDefs: docScope=`%s' scope=`%s'\n",docScope,scope);
+ //printf("getScopeDefs: docScope='%s' scope='%s'\n",docScope,scope);
if (scopeName.isEmpty()) return FALSE;
bool explicitGlobalScope=FALSE;
@@ -4556,6 +4564,10 @@ static bool getScopeDefs(const char *docScope,const char *scope,
scopeName=scopeName.right(scopeName.length()-2);
explicitGlobalScope=TRUE;
}
+ if (scopeName.isEmpty())
+ {
+ return FALSE;
+ }
QCString docScopeName=docScope;
int scopeOffset=explicitGlobalScope ? 0 : docScopeName.length();
@@ -4808,10 +4820,10 @@ QCString linkToText(SrcLangExt lang,const char *link,bool isFileName)
#if 0
/*
* generate a reference to a class, namespace or member.
- * `scName' is the name of the scope that contains the documentation
+ * 'scName' is the name of the scope that contains the documentation
* string that is returned.
- * `name' is the name that we want to link to.
- * `name' may have five formats:
+ * 'name' is the name that we want to link to.
+ * 'name' may have the following formats:
* 1) "ScopeName"
* 2) "memberName()" one of the (overloaded) function or define
* with name memberName.
@@ -4983,8 +4995,8 @@ bool resolveLink(/* in */ const char *scName,
//----------------------------------------------------------------------
// General function that generates the HTML code for a reference to some
-// file, class or member from text `lr' within the context of class `clName'.
-// This link has the text 'lt' (if not 0), otherwise `lr' is used as a
+// file, class or member from text 'lr' within the context of class 'clName'.
+// This link has the text 'lt' (if not 0), otherwise 'lr' is used as a
// basis for the link's text.
// returns TRUE if a link could be generated.
@@ -5129,7 +5141,7 @@ FileDef *findFileDef(const FileNameDict *fnDict,const char *n,bool &ambig)
if (fn->count()==1)
{
FileDef *fd = fn->getFirst();
-#if defined(_WIN32) || defined(__MACOSX__) // Windows or MacOSX
+#if defined(_WIN32) || defined(__MACOSX__) || defined(__CYGWIN__) // Windows or MacOSX
bool isSamePath = fd->getPath().right(path.length()).lower()==path.lower();
#else // Unix
bool isSamePath = fd->getPath().right(path.length())==path;
@@ -5329,7 +5341,7 @@ QCString substituteKeywords(const QCString &s,const char *title,
result = substitute(result,"$datetime",dateToString(TRUE));
result = substitute(result,"$date",dateToString(FALSE));
result = substitute(result,"$year",yearToString());
- result = substitute(result,"$doxygenversion",versionString);
+ result = substitute(result,"$doxygenversion",getVersion());
result = substitute(result,"$projectname",projName);
result = substitute(result,"$projectnumber",projNum);
result = substitute(result,"$projectbrief",projBrief);
@@ -5475,10 +5487,12 @@ QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscor
case '(': growBuf.addStr("_07"); break;
case ')': growBuf.addStr("_08"); break;
case '+': growBuf.addStr("_09"); break;
- case '=': growBuf.addStr("_0A"); break;
- case '$': growBuf.addStr("_0B"); break;
- case '\\': growBuf.addStr("_0C"); break;
- case '@': growBuf.addStr("_0D"); break;
+ case '=': growBuf.addStr("_0a"); break;
+ case '$': growBuf.addStr("_0b"); break;
+ case '\\': growBuf.addStr("_0c"); break;
+ case '@': growBuf.addStr("_0d"); break;
+ case ']': growBuf.addStr("_0e"); break;
+ case '[': growBuf.addStr("_0f"); break;
default:
if (c<0)
{
@@ -5550,6 +5564,76 @@ QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscor
return growBuf.get();
}
+QCString unescapeCharsInString(const char *s)
+{
+ static bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES);
+ QCString result;
+ const char *p = s;
+ if (p)
+ {
+ char c;
+ while ((c=*p++))
+ {
+ if (c=='_') // 2 or 3 character escape
+ {
+ switch (*p)
+ {
+ case '_': result+=c; p++; break; // __ -> '_'
+ case '1': result+=':'; p++; break; // _1 -> ':'
+ case '2': result+='/'; p++; break; // _2 -> '/'
+ case '3': result+='<'; p++; break; // _3 -> '<'
+ case '4': result+='>'; p++; break; // _4 -> '>'
+ case '5': result+='*'; p++; break; // _5 -> '*'
+ case '6': result+='&'; p++; break; // _6 -> '&'
+ case '7': result+='|'; p++; break; // _7 -> '|'
+ case '8': result+='.'; p++; break; // _8 -> '.'
+ case '9': result+='!'; p++; break; // _9 -> '!'
+ case '0': // 3 character escape
+ switch (*(p+1))
+ {
+ case '0': result+=','; p+=2; break; // _00 -> ','
+ case '1': result+=' '; p+=2; break; // _01 -> ' '
+ case '2': result+='{'; p+=2; break; // _02 -> '{'
+ case '3': result+='}'; p+=2; break; // _03 -> '}'
+ case '4': result+='?'; p+=2; break; // _04 -> '?'
+ case '5': result+='^'; p+=2; break; // _05 -> '^'
+ case '6': result+='%'; p+=2; break; // _06 -> '%'
+ case '7': result+='('; p+=2; break; // _07 -> '('
+ case '8': result+=')'; p+=2; break; // _08 -> ')'
+ case '9': result+='+'; p+=2; break; // _09 -> '+'
+ case 'a': result+='='; p+=2; break; // _0a -> '='
+ case 'b': result+='$'; p+=2; break; // _0b -> '$'
+ case 'c': result+='\\'; p+=2; break;// _0c -> '\'
+ case 'd': result+='@'; p+=2; break; // _0d -> '@'
+ case 'e': result+=']'; p+=2; break; // _0e -> ']'
+ case 'f': result+='['; p+=2; break; // _0f -> '['
+ default: // unknown escape, just pass underscore character as-is
+ result+=c;
+ break;
+ }
+ break;
+ default:
+ if (!caseSenseNames && c>='a' && c<='z') // lower to upper case escape, _a -> 'A'
+ {
+ result+=toupper(*p);
+ p++;
+ }
+ else // unknown escape, pass underscore character as-is
+ {
+ result+=c;
+ }
+ break;
+ }
+ }
+ else // normal character; pass as is
+ {
+ result+=c;
+ }
+ }
+ }
+ return result;
+}
+
/*! This function determines the file name on disk of an item
* given its name, which could be a class name with template
* arguments, so special characters need to be escaped.
@@ -5719,7 +5803,7 @@ done:
className=namespaceName.copy();
namespaceName.resize(0);
}
- //printf("extractNamespace `%s' => `%s|%s'\n",scopeName.data(),
+ //printf("extractNamespace '%s' => '%s|%s'\n",scopeName.data(),
// className.data(),namespaceName.data());
if (/*className.right(2)=="-g" ||*/ className.right(2)=="-p")
{
@@ -5740,7 +5824,7 @@ QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &te
((cd=getClass(scope.left(si)))==0 || cd->templateArguments()==0)
)
{
- //printf("Tried `%s'\n",(scope.left(si)+templ).data());
+ //printf("Tried '%s'\n",(scope.left(si)+templ).data());
pi=si+2;
}
if (si==-1) // not nested => append template specifier
@@ -5752,7 +5836,7 @@ QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &te
result=scope.left(si) + templ + scope.right(scope.length()-si);
}
}
- //printf("insertTemplateSpecifierInScope(`%s',`%s')=%s\n",
+ //printf("insertTemplateSpecifierInScope('%s','%s')=%s\n",
// scope.data(),templ.data(),result.data());
return result;
}
@@ -6358,7 +6442,7 @@ QCString normalizeNonTemplateArgumentsInString(
if (!found)
{
// try to resolve the type
- ClassDef *cd = getResolvedClass(context,0,n);
+ const ClassDef *cd = getResolvedClass(context,0,n);
if (cd)
{
result+=cd->name();
@@ -6672,7 +6756,7 @@ 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);
+ //printf("Adding page docs '%s' pi=%p name=%s\n",doc.data(),pd,name);
// append (x)refitems to the page.
pd->setRefItems(sli);
}
@@ -6696,7 +6780,7 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
pd->setFileName(tagInfo->fileName);
}
- //printf("Appending page `%s'\n",baseName.data());
+ //printf("Appending page '%s'\n",baseName.data());
Doxygen::pageSDict->append(baseName,pd);
if (gd) gd->addPage(pd);
@@ -6731,7 +6815,7 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle,
{
si=new SectionInfo(
file,-1,pd->name(),pd->title(),SectionInfo::Page,0,pd->getReference());
- //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
+ //printf("si->label='%s' si->definition=%s si->fileName='%s'\n",
// si->label.data(),si->definition?si->definition->name().data():"<none>",
// si->fileName.data());
//printf(" SectionInfo: sec=%p sec->fileName=%s\n",si,si->fileName.data());
@@ -7079,6 +7163,7 @@ QCString latexFilterURL(const char *s)
switch (c)
{
case '#': t << "\\#"; break;
+ case '%': t << "\\%"; break;
default:
t << c;
break;
@@ -7414,24 +7499,28 @@ void addCodeOnlyMappings()
SrcLangExt getLanguageFromFileName(const QCString& fileName)
{
- int i = fileName.findRev('.');
- if (i!=-1) // name has an extension
- {
- QCString extStr=fileName.right(fileName.length()-i).lower();
- if (!extStr.isEmpty()) // non-empty extension
+ QFileInfo fi(fileName);
+ QCString extName = fi.extension().lower().data();
+ if (extName.isEmpty()) extName=".no_extension";
+ if (extName.at(0)!='.') extName.prepend(".");
+ int *pVal=g_extLookup.find(extName.data());
+ if (pVal) // listed extension
{
- int *pVal=g_extLookup.find(extStr);
- if (pVal) // listed extension
- {
- //printf("getLanguageFromFileName(%s)=%x\n",extStr.data(),*pVal);
- return (SrcLangExt)*pVal;
- }
+ //printf("getLanguageFromFileName(%s)=%x\n",fi.extension().data(),*pVal);
+ return (SrcLangExt)*pVal;
}
- }
//printf("getLanguageFromFileName(%s) not found!\n",fileName.data());
return SrcLangExt_Cpp; // not listed => assume C-ish language.
}
+QCString getFileNameExtension(QCString fn)
+{
+ if (fn.isEmpty()) return "";
+ int lastDot = fn.findRev('.');
+ if (lastDot!=-1) return fn.mid(lastDot);
+ return "";
+}
+
//--------------------------------------------------------------------------
MemberDef *getMemberFromSymbol(const Definition *scope,const FileDef *fileScope,
@@ -8129,8 +8218,8 @@ QCString filterTitle(const QCString &title)
}
//----------------------------------------------------------------------------
-// returns TRUE if the name of the file represented by `fi' matches
-// one of the file patterns in the `patList' list.
+// returns TRUE if the name of the file represented by 'fi' matches
+// one of the file patterns in the 'patList' list.
bool patternMatch(const QFileInfo &fi,const QStrList *patList)
{
@@ -8138,7 +8227,7 @@ bool patternMatch(const QFileInfo &fi,const QStrList *patList)
bool found = FALSE;
// For Windows/Mac, always do the case insensitive match
-#if defined(_WIN32) || defined(__MACOSX__)
+#if defined(_WIN32) || defined(__MACOSX__) || defined(__CYGWIN__)
caseSenseNames = FALSE;
#endif
@@ -8164,7 +8253,7 @@ bool patternMatch(const QFileInfo &fi,const QStrList *patList)
re.match(fp)!=-1 ||
re.match(afp)!=-1;
if (found) break;
- //printf("Matching `%s' against pattern `%s' found=%d\n",
+ //printf("Matching '%s' against pattern '%s' found=%d\n",
// fi->fileName().data(),pattern.data(),found);
}
}
diff --git a/src/util.h b/src/util.h
index 9873350..8ff7e4d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -207,10 +207,10 @@ QCString resolveDefines(const char *n);
ClassDef *getClass(const char *key);
-ClassDef *getResolvedClass(const Definition *scope,
+const ClassDef *getResolvedClass(const Definition *scope,
const FileDef *fileScope,
const char *key,
- MemberDef **pTypeDef=0,
+ const MemberDef **pTypeDef=0,
QCString *pTemplSpec=0,
bool mayBeUnlinkable=FALSE,
bool mayBeHidden=FALSE,
@@ -341,6 +341,7 @@ PageDef *addRelatedPage(const char *name,
);
QCString escapeCharsInString(const char *name,bool allowDots,bool allowUnderscore=FALSE);
+QCString unescapeCharsInString(const char *s);
void addGroupListToTitle(OutputList &ol,const Definition *d);
@@ -390,6 +391,7 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine);
bool updateLanguageMapping(const QCString &extension,const QCString &parser);
SrcLangExt getLanguageFromFileName(const QCString& fileName);
+QCString getFileNameExtension(QCString fn);
void initDefaultExtensionMapping();
void addCodeOnlyMappings();
@@ -397,10 +399,12 @@ MemberDef *getMemberFromSymbol(const Definition *scope,const FileDef *fileScope,
const char *n);
bool checkIfTypedef(const Definition *scope,const FileDef *fileScope,const char *n);
-ClassDef *newResolveTypedef(const FileDef *fileScope,MemberDef *md,
- MemberDef **pMemType=0,QCString *pTemplSpec=0,
- QCString *pResolvedType=0,
- ArgumentList *actTemplParams=0);
+const ClassDef *newResolveTypedef(const FileDef *fileScope,
+ const MemberDef *md,
+ const MemberDef **pMemType=0,
+ QCString *pTemplSpec=0,
+ QCString *pResolvedType=0,
+ ArgumentList *actTemplParams=0);
QCString parseCommentAsText(const Definition *scope,const MemberDef *member,const QCString &doc,const QCString &fileName,int lineNr);
diff --git a/src/version.h b/src/version.h
deleted file mode 100644
index 16bf9df..0000000
--- a/src/version.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************************************
- *
- *
- *
- * Copyright (C) 1997-2015 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 VERSION_H
-#define VERSION_H
-
-extern char versionString[];
-
-#endif
diff --git a/src/vhdlcode.l b/src/vhdlcode.l
index 7c6cfa4..5f668c6 100644
--- a/src/vhdlcode.l
+++ b/src/vhdlcode.l
@@ -347,7 +347,7 @@ static void writeWord(const char *word,const char* curr_class=0,bool classLink=F
}// writeWord
-/*! write a code fragment `text' that may span multiple lines, inserting
+/*! write a code fragment 'text' that may span multiple lines, inserting
* line numbers for each line.
*/
static void codifyLines(const char *text,const char *cl=0,bool classlink=FALSE,bool comment=FALSE)
diff --git a/src/vhdldocgen.cpp b/src/vhdldocgen.cpp
index bba249a..38a80ef 100644
--- a/src/vhdldocgen.cpp
+++ b/src/vhdldocgen.cpp
@@ -168,7 +168,7 @@ static void createSVG()
QCString vlargs="-Tsvg \""+ov+"\" "+dir ;
- if (portable_system("dot",vlargs)!=0)
+ if (portable_system(Config_getString(DOT_PATH) + "dot",vlargs)!=0)
{
err("could not create dot file");
}
@@ -3845,7 +3845,7 @@ void FlowChart::createSVG()
QCString vlargs="-Tsvg \""+ov+"\" "+dir ;
- if (portable_system("dot",vlargs)!=0)
+ if (portable_system(Config_getString(DOT_PATH) + "dot",vlargs)!=0)
{
err("could not create dot file");
}
diff --git a/src/vhdljjparser.cpp b/src/vhdljjparser.cpp
index 4a312bd..aeed048 100644
--- a/src/vhdljjparser.cpp
+++ b/src/vhdljjparser.cpp
@@ -146,7 +146,7 @@ void VHDLLanguageScanner::parseInput(const char *fileName,const char *fileBuf,En
oldEntry = 0;
VhdlParser::current=new Entry();
VhdlParser::initEntry(VhdlParser::current);
- groupEnterFile(fileName,yyLineNr);
+ Doxygen::docGroup.enterFile(fileName,yyLineNr);
vhdlFileName = fileName;
lineParse=new int[200]; // Dimitri: dangerous constant: should be bigger than largest token id in VhdlParserConstants.h
VhdlParserIF::parseVhdlfile(fileBuf,inLine);
@@ -193,7 +193,7 @@ void VhdlParser::initEntry(Entry *e)
e->fileName = yyFileName;
e->lang = SrcLangExt_VHDL;
isVhdlDocPending();
- initGroupInfo(e);
+ Doxygen::docGroup.initGroupInfo(e);
}
void VhdlParser::newEntry()
diff --git a/src/xmldocvisitor.cpp b/src/xmldocvisitor.cpp
index 1005719..a0afa9d 100644
--- a/src/xmldocvisitor.cpp
+++ b/src/xmldocvisitor.cpp
@@ -190,9 +190,15 @@ void XmlDocVisitor::visit(DocStyleChange *s)
case DocStyleChange::Strike:
if (s->enable()) m_t << "<strike>"; else m_t << "</strike>";
break;
+ case DocStyleChange::Del:
+ if (s->enable()) m_t << "<del>"; else m_t << "</del>";
+ break;
case DocStyleChange::Underline:
if (s->enable()) m_t << "<underline>"; else m_t << "</underline>";
break;
+ case DocStyleChange::Ins:
+ if (s->enable()) m_t << "<ins>"; else m_t << "</ins>";
+ break;
case DocStyleChange::Italic:
if (s->enable()) m_t << "<emphasis>"; else m_t << "</emphasis>";
break;
@@ -404,7 +410,7 @@ void XmlDocVisitor::visit(DocInclude *inc)
void XmlDocVisitor::visit(DocIncOperator *op)
{
- //printf("DocIncOperator: type=%d first=%d, last=%d text=`%s'\n",
+ //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n",
// op->type(),op->isFirst(),op->isLast(),op->text().data());
if (op->isFirst())
{
@@ -415,20 +421,22 @@ void XmlDocVisitor::visit(DocIncOperator *op)
pushEnabled();
m_hide = TRUE;
}
- SrcLangExt langExt = getLanguageFromFileName(m_langExt);
+ QCString locLangExt = getFileNameExtension(op->includeFileName());
+ if (locLangExt.isEmpty()) locLangExt = m_langExt;
+ SrcLangExt langExt = getLanguageFromFileName(locLangExt);
if (op->type()!=DocIncOperator::Skip)
{
popEnabled();
if (!m_hide)
{
- FileDef *fd;
+ FileDef *fd = 0;
if (!op->includeFileName().isEmpty())
{
QFileInfo cfi( op->includeFileName() );
fd = createFileDef( cfi.dirPath().utf8(), cfi.fileName().utf8() );
}
- Doxygen::parserManager->getParser(m_langExt)
+ Doxygen::parserManager->getParser(locLangExt)
->parseCode(m_ci,op->context(),
op->text(),langExt,op->isExample(),
op->exampleFile(),
@@ -990,9 +998,9 @@ void XmlDocVisitor::visitPre(DocParamList *pl)
{
QListIterator<DocNode> li(pl->paramTypes());
DocNode *type;
+ m_t << "<parametertype>";
for (li.toFirst();(type=li.current());++li)
{
- m_t << "<parametertype>";
if (type->kind()==DocNode::Kind_Word)
{
visit((DocWord*)type);
@@ -1001,8 +1009,13 @@ void XmlDocVisitor::visitPre(DocParamList *pl)
{
visit((DocLinkedWord*)type);
}
- m_t << "</parametertype>" << endl;
+ else if (type->kind()==DocNode::Kind_Sep)
+ {
+ m_t << "</parametertype>" << endl;
+ m_t << "<parametertype>";
+ }
}
+ m_t << "</parametertype>" << endl;
}
m_t << "<parametername";
if (pl->direction()!=DocParamSect::Unspecified)
@@ -1078,18 +1091,6 @@ void XmlDocVisitor::visitPost(DocInternalRef *)
m_t << " ";
}
-void XmlDocVisitor::visitPre(DocCopy *c)
-{
- if (m_hide) return;
- m_t << "<copydoc link=\"" << convertToXML(c->link()) << "\">";
-}
-
-void XmlDocVisitor::visitPost(DocCopy *)
-{
- if (m_hide) return;
- m_t << "</copydoc>" << endl;
-}
-
void XmlDocVisitor::visitPre(DocText *)
{
}
diff --git a/src/xmldocvisitor.h b/src/xmldocvisitor.h
index c2c6537..6fa1392 100644
--- a/src/xmldocvisitor.h
+++ b/src/xmldocvisitor.h
@@ -130,8 +130,6 @@ class XmlDocVisitor : public DocVisitor
void visitPost(DocXRefItem *);
void visitPre(DocInternalRef *);
void visitPost(DocInternalRef *);
- void visitPre(DocCopy *);
- void visitPost(DocCopy *);
void visitPre(DocText *);
void visitPost(DocText *);
void visitPre(DocHtmlBlockQuote *);
diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp
index fe324be..d05adf0 100644
--- a/src/xmlgen.cpp
+++ b/src/xmlgen.cpp
@@ -29,6 +29,8 @@
#include "defargs.h"
#include "outputgen.h"
#include "dot.h"
+#include "dotclassgraph.h"
+#include "dotincldepgraph.h"
#include "pagedef.h"
#include "filename.h"
#include "version.h"
@@ -152,7 +154,7 @@ static void writeXMLHeader(FTextStream &t)
t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
t << "<doxygen xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
t << "xsi:noNamespaceSchemaLocation=\"compound.xsd\" ";
- t << "version=\"" << versionString << "\">" << endl;
+ t << "version=\"" << getVersion() << "\">" << endl;
}
static void writeCombineScript()
@@ -566,7 +568,7 @@ static void generateXMLForMember(const MemberDef *md,FTextStream &ti,FTextStream
{
t << memberOutputFileBase(md);
}
- t << "_1" // encoded `:' character (see util.cpp:convertNameToFile)
+ t << "_1" // encoded ':' character (see util.cpp:convertNameToFile)
<< md->anchor();
t << "\" prot=\"";
switch(md->protection())
@@ -1407,14 +1409,14 @@ static void generateXMLForClass(const ClassDef *cd,FTextStream &ti)
t << " <detaileddescription>" << endl;
writeXMLDocBlock(t,cd->docFile(),cd->docLine(),cd,0,cd->documentation());
t << " </detaileddescription>" << endl;
- DotClassGraph inheritanceGraph(cd,DotNode::Inheritance);
+ DotClassGraph inheritanceGraph(cd,Inheritance);
if (!inheritanceGraph.isTrivial())
{
t << " <inheritancegraph>" << endl;
inheritanceGraph.writeXML(t);
t << " </inheritancegraph>" << endl;
}
- DotClassGraph collaborationGraph(cd,DotNode::Collaboration);
+ DotClassGraph collaborationGraph(cd,Collaboration);
if (!collaborationGraph.isTrivial())
{
t << " <collaborationgraph>" << endl;
@@ -1979,7 +1981,7 @@ void generateXML()
t << "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" << endl;;
t << "<doxygenindex xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
t << "xsi:noNamespaceSchemaLocation=\"index.xsd\" ";
- t << "version=\"" << versionString << "\">" << endl;
+ t << "version=\"" << getVersion() << "\">" << endl;
{
ClassSDict::Iterator cli(*Doxygen::classSDict);
diff --git a/templates/latex/doxygen.sty b/templates/latex/doxygen.sty
index bd5fdba..bf19901 100644
--- a/templates/latex/doxygen.sty
+++ b/templates/latex/doxygen.sty
@@ -3,14 +3,14 @@
% Packages used by this style file
\RequirePackage{alltt}
-\RequirePackage{array}
+%%\RequirePackage{array} %% moved to refman.tex due to workaround for LaTex 2019 version and unmaintained tabu package
\RequirePackage{calc}
\RequirePackage{float}
-\RequirePackage{ifthen}
+%%\RequirePackage{ifthen} %% moved to refman.tex due to workaround for LaTex 2019 version and unmaintained tabu package
\RequirePackage{verbatim}
\RequirePackage[table]{xcolor}
-\RequirePackage{longtable}
-\RequirePackage{tabu}
+\RequirePackage{longtable_doxygen}
+\RequirePackage{tabu_doxygen}
\RequirePackage{fancyvrb}
\RequirePackage{tabularx}
\RequirePackage{multirow}
@@ -306,16 +306,9 @@
% Used by @par and @paragraph
\newenvironment{DoxyParagraph}[1]{%
- \begin{list}{}{%
- \settowidth{\labelwidth}{40pt}%
- \setlength{\leftmargin}{\labelwidth+\labelsep}%
- \setlength{\parsep}{0pt}%
- \setlength{\itemsep}{-4pt}%
- \renewcommand{\makelabel}{\entrylabel}%
- }%
- \item[#1]%
+ \begin{DoxyDesc}{#1}%
}{%
- \end{list}%
+ \end{DoxyDesc}%
}
% Used by parameter lists
@@ -546,22 +539,28 @@
\newcommand{\Hypertarget}[1]{\Hy@raisedlink{\hypertarget{#1}{}}}
% possibility to have sections etc. be within the margins
+% unfortunately had to copy part of book.cls and add \raggedright
\makeatletter
-\newcommand{\doxysection}{\@ifstar{\doxysection@star}{\doxysection@nostar}}
-\newcommand{\doxysection@star}[1]{\begingroup\sloppy\raggedright\section*{#1}\endgroup}
-\newcommand{\doxysection@nostar}[1]{\begingroup\sloppy\raggedright\section{#1}\endgroup}
-\newcommand{\doxysubsection}{\@ifstar{\doxysubsection@star}{\doxysubsection@nostar}}
-\newcommand{\doxysubsection@star}[1]{\begingroup\sloppy\raggedright\subsection*{#1}\endgroup}
-\newcommand{\doxysubsection@nostar}[1]{\begingroup\sloppy\raggedright\subsection{#1}\endgroup}
-\newcommand{\doxysubsubsection}{\@ifstar{\doxysubsubsection@star}{\doxysubsubsection@nostar}}
-\newcommand{\doxysubsubsection@star}[1]{\begingroup\sloppy\raggedright\subsubsection*{#1}\endgroup}
-\newcommand{\doxysubsubsection@nostar}[1]{\begingroup\sloppy\raggedright\subsubsection{#1}\endgroup}
-\newcommand{\doxyparagraph}{\@ifstar{\doxyparagraph@star}{\doxyparagraph@nostar}}
-\newcommand{\doxyparagraph@star}[1]{\begingroup\sloppy\raggedright\paragraph*{#1}\endgroup}
-\newcommand{\doxyparagraph@nostar}[1]{\begingroup\sloppy\raggedright\paragraph{#1}\endgroup}
-\newcommand{\doxysubparagraph}{\@ifstar{\doxysubparagraph@star}{\doxysubparagraph@nostar}}
-\newcommand{\doxysubparagraph@star}[1]{\begingroup\sloppy\raggedright\subparagraph*{#1}\endgroup}
-\newcommand{\doxysubparagraph@nostar}[1]{\begingroup\sloppy\raggedright\subparagraph{#1}\endgroup}
+\newcommand\doxysection{\@startsection {section}{1}{\z@}%
+ {-3.5ex \@plus -1ex \@minus -.2ex}%
+ {2.3ex \@plus.2ex}%
+ {\raggedright\normalfont\Large\bfseries}}
+\newcommand\doxysubsection{\@startsection{subsection}{2}{\z@}%
+ {-3.25ex\@plus -1ex \@minus -.2ex}%
+ {1.5ex \@plus .2ex}%
+ {\raggedright\normalfont\large\bfseries}}
+\newcommand\doxysubsubsection{\@startsection{subsubsection}{3}{\z@}%
+ {-3.25ex\@plus -1ex \@minus -.2ex}%
+ {1.5ex \@plus .2ex}%
+ {\raggedright\normalfont\normalsize\bfseries}}
+\newcommand\doxyparagraph{\@startsection{paragraph}{4}{\z@}%
+ {3.25ex \@plus1ex \@minus.2ex}%
+ {-1em}%
+ {\raggedright\normalfont\normalsize\bfseries}}
+\newcommand\doxysubparagraph{\@startsection{subparagraph}{5}{\parindent}%
+ {3.25ex \@plus1ex \@minus .2ex}%
+ {-1em}%
+ {\raggedright\normalfont\normalsize\bfseries}}
\makeatother
% Define caption that is also suitable in a table
\makeatletter
diff --git a/templates/latex/longtable_doxygen.sty b/templates/latex/longtable_doxygen.sty
new file mode 100755
index 0000000..a0eb314
--- /dev/null
+++ b/templates/latex/longtable_doxygen.sty
@@ -0,0 +1,448 @@
+%%
+%% This is file `longtable.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% longtable.dtx (with options: `package')
+%%
+%% This is a generated file.
+%%
+%% The source is maintained by the LaTeX Project team and bug
+%% reports for it can be opened at http://latex-project.org/bugs.html
+%% (but please observe conditions on bug reports sent to that address!)
+%%
+%% Copyright 1993-2016
+%% The LaTeX3 Project and any individual authors listed elsewhere
+%% in this file.
+%%
+%% This file was generated from file(s) of the Standard LaTeX `Tools Bundle'.
+%% --------------------------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2005/12/01 or later.
+%%
+%% This file may only be distributed together with a copy of the LaTeX
+%% `Tools Bundle'. You may however distribute the LaTeX `Tools Bundle'
+%% without such generated files.
+%%
+%% The list of all files belonging to the LaTeX `Tools Bundle' is
+%% given in the file `manifest.txt'.
+%%
+%% File: longtable.dtx Copyright (C) 1990-2001 David Carlisle
+\NeedsTeXFormat{LaTeX2e}[1995/06/01]
+\ProvidesPackage{longtable_doxygen}
+ [2014/10/28 v4.11 Multi-page Table package (DPC) - frozen version for doxygen]
+\def\LT@err{\PackageError{longtable}}
+\def\LT@warn{\PackageWarning{longtable}}
+\def\LT@final@warn{%
+ \AtEndDocument{%
+ \LT@warn{Table \@width s have changed. Rerun LaTeX.\@gobbletwo}}%
+ \global\let\LT@final@warn\relax}
+\DeclareOption{errorshow}{%
+ \def\LT@warn{\PackageInfo{longtable}}}
+\DeclareOption{pausing}{%
+ \def\LT@warn#1{%
+ \LT@err{#1}{This is not really an error}}}
+\DeclareOption{set}{}
+\DeclareOption{final}{}
+\ProcessOptions
+\newskip\LTleft \LTleft=\fill
+\newskip\LTright \LTright=\fill
+\newskip\LTpre \LTpre=\bigskipamount
+\newskip\LTpost \LTpost=\bigskipamount
+\newcount\LTchunksize \LTchunksize=20
+\let\c@LTchunksize\LTchunksize
+\newdimen\LTcapwidth \LTcapwidth=4in
+\newbox\LT@head
+\newbox\LT@firsthead
+\newbox\LT@foot
+\newbox\LT@lastfoot
+\newcount\LT@cols
+\newcount\LT@rows
+\newcounter{LT@tables}
+\newcounter{LT@chunks}[LT@tables]
+\ifx\c@table\undefined
+ \newcounter{table}
+ \def\fnum@table{\tablename~\thetable}
+\fi
+\ifx\tablename\undefined
+ \def\tablename{Table}
+\fi
+\newtoks\LT@p@ftn
+\mathchardef\LT@end@pen=30000
+\def\longtable{%
+ \par
+ \ifx\multicols\@undefined
+ \else
+ \ifnum\col@number>\@ne
+ \@twocolumntrue
+ \fi
+ \fi
+ \if@twocolumn
+ \LT@err{longtable not in 1-column mode}\@ehc
+ \fi
+ \begingroup
+ \@ifnextchar[\LT@array{\LT@array[x]}}
+\def\LT@array[#1]#2{%
+ \refstepcounter{table}\stepcounter{LT@tables}%
+ \if l#1%
+ \LTleft\z@ \LTright\fill
+ \else\if r#1%
+ \LTleft\fill \LTright\z@
+ \else\if c#1%
+ \LTleft\fill \LTright\fill
+ \fi\fi\fi
+ \let\LT@mcol\multicolumn
+ \let\LT@@tabarray\@tabarray
+ \let\LT@@hl\hline
+ \def\@tabarray{%
+ \let\hline\LT@@hl
+ \LT@@tabarray}%
+ \let\\\LT@tabularcr\let\tabularnewline\\%
+ \def\newpage{\noalign{\break}}%
+ \def\pagebreak{\noalign{\ifnum`}=0\fi\@testopt{\LT@no@pgbk-}4}%
+ \def\nopagebreak{\noalign{\ifnum`}=0\fi\@testopt\LT@no@pgbk4}%
+ \let\hline\LT@hline \let\kill\LT@kill\let\caption\LT@caption
+ \@tempdima\ht\strutbox
+ \let\@endpbox\LT@endpbox
+ \ifx\extrarowheight\@undefined
+ \let\@acol\@tabacol
+ \let\@classz\@tabclassz \let\@classiv\@tabclassiv
+ \def\@startpbox{\vtop\LT@startpbox}%
+ \let\@@startpbox\@startpbox
+ \let\@@endpbox\@endpbox
+ \let\LT@LL@FM@cr\@tabularcr
+ \else
+ \advance\@tempdima\extrarowheight
+ \col@sep\tabcolsep
+ \let\@startpbox\LT@startpbox\let\LT@LL@FM@cr\@arraycr
+ \fi
+ \setbox\@arstrutbox\hbox{\vrule
+ \@height \arraystretch \@tempdima
+ \@depth \arraystretch \dp \strutbox
+ \@width \z@}%
+ \let\@sharp##\let\protect\relax
+ \begingroup
+ \@mkpream{#2}%
+ \xdef\LT@bchunk{%
+ \global\advance\c@LT@chunks\@ne
+ \global\LT@rows\z@\setbox\z@\vbox\bgroup
+ \LT@setprevdepth
+ \tabskip\LTleft \noexpand\halign to\hsize\bgroup
+ \tabskip\z@ \@arstrut \@preamble \tabskip\LTright \cr}%
+ \endgroup
+ \expandafter\LT@nofcols\LT@bchunk&\LT@nofcols
+ \LT@make@row
+ \m@th\let\par\@empty
+ \everycr{}\lineskip\z@\baselineskip\z@
+ \LT@bchunk}
+\def\LT@no@pgbk#1[#2]{\penalty #1\@getpen{#2}\ifnum`{=0\fi}}
+\def\LT@start{%
+ \let\LT@start\endgraf
+ \endgraf\penalty\z@\vskip\LTpre
+ \dimen@\pagetotal
+ \advance\dimen@ \ht\ifvoid\LT@firsthead\LT@head\else\LT@firsthead\fi
+ \advance\dimen@ \dp\ifvoid\LT@firsthead\LT@head\else\LT@firsthead\fi
+ \advance\dimen@ \ht\LT@foot
+ \dimen@ii\vfuzz
+ \vfuzz\maxdimen
+ \setbox\tw@\copy\z@
+ \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox
+ \setbox\tw@\vbox{\unvbox\tw@}%
+ \vfuzz\dimen@ii
+ \advance\dimen@ \ht
+ \ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi
+ \advance\dimen@\dp
+ \ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi
+ \advance\dimen@ -\pagegoal
+ \ifdim \dimen@>\z@\vfil\break\fi
+ \global\@colroom\@colht
+ \ifvoid\LT@foot\else
+ \advance\vsize-\ht\LT@foot
+ \global\advance\@colroom-\ht\LT@foot
+ \dimen@\pagegoal\advance\dimen@-\ht\LT@foot\pagegoal\dimen@
+ \maxdepth\z@
+ \fi
+ \ifvoid\LT@firsthead\copy\LT@head\else\box\LT@firsthead\fi\nobreak
+ \output{\LT@output}}
+\def\endlongtable{%
+ \crcr
+ \noalign{%
+ \let\LT@entry\LT@entry@chop
+ \xdef\LT@save@row{\LT@save@row}}%
+ \LT@echunk
+ \LT@start
+ \unvbox\z@
+ \LT@get@widths
+ \if@filesw
+ {\let\LT@entry\LT@entry@write\immediate\write\@auxout{%
+ \gdef\expandafter\noexpand
+ \csname LT@\romannumeral\c@LT@tables\endcsname
+ {\LT@save@row}}}%
+ \fi
+ \ifx\LT@save@row\LT@@save@row
+ \else
+ \LT@warn{Column \@width s have changed\MessageBreak
+ in table \thetable}%
+ \LT@final@warn
+ \fi
+ \endgraf\penalty -\LT@end@pen
+ \endgroup
+ \global\@mparbottom\z@
+ \pagegoal\vsize
+ \endgraf\penalty\z@\addvspace\LTpost
+ \ifvoid\footins\else\insert\footins{}\fi}
+\def\LT@nofcols#1&{%
+ \futurelet\@let@token\LT@n@fcols}
+\def\LT@n@fcols{%
+ \advance\LT@cols\@ne
+ \ifx\@let@token\LT@nofcols
+ \expandafter\@gobble
+ \else
+ \expandafter\LT@nofcols
+ \fi}
+\def\LT@tabularcr{%
+ \relax\iffalse{\fi\ifnum0=`}\fi
+ \@ifstar
+ {\def\crcr{\LT@crcr\noalign{\nobreak}}\let\cr\crcr
+ \LT@t@bularcr}%
+ {\LT@t@bularcr}}
+\let\LT@crcr\crcr
+\let\LT@setprevdepth\relax
+\def\LT@t@bularcr{%
+ \global\advance\LT@rows\@ne
+ \ifnum\LT@rows=\LTchunksize
+ \gdef\LT@setprevdepth{%
+ \prevdepth\z@\global
+ \global\let\LT@setprevdepth\relax}%
+ \expandafter\LT@xtabularcr
+ \else
+ \ifnum0=`{}\fi
+ \expandafter\LT@LL@FM@cr
+ \fi}
+\def\LT@xtabularcr{%
+ \@ifnextchar[\LT@argtabularcr\LT@ntabularcr}
+\def\LT@ntabularcr{%
+ \ifnum0=`{}\fi
+ \LT@echunk
+ \LT@start
+ \unvbox\z@
+ \LT@get@widths
+ \LT@bchunk}
+\def\LT@argtabularcr[#1]{%
+ \ifnum0=`{}\fi
+ \ifdim #1>\z@
+ \unskip\@xargarraycr{#1}%
+ \else
+ \@yargarraycr{#1}%
+ \fi
+ \LT@echunk
+ \LT@start
+ \unvbox\z@
+ \LT@get@widths
+ \LT@bchunk}
+\def\LT@echunk{%
+ \crcr\LT@save@row\cr\egroup
+ \global\setbox\@ne\lastbox
+ \unskip
+ \egroup}
+\def\LT@entry#1#2{%
+ \ifhmode\@firstofone{&}\fi\omit
+ \ifnum#1=\c@LT@chunks
+ \else
+ \kern#2\relax
+ \fi}
+\def\LT@entry@chop#1#2{%
+ \noexpand\LT@entry
+ {\ifnum#1>\c@LT@chunks
+ 1}{0pt%
+ \else
+ #1}{#2%
+ \fi}}
+\def\LT@entry@write{%
+ \noexpand\LT@entry^^J%
+ \@spaces}
+\def\LT@kill{%
+ \LT@echunk
+ \LT@get@widths
+ \expandafter\LT@rebox\LT@bchunk}
+\def\LT@rebox#1\bgroup{%
+ #1\bgroup
+ \unvbox\z@
+ \unskip
+ \setbox\z@\lastbox}
+\def\LT@blank@row{%
+ \xdef\LT@save@row{\expandafter\LT@build@blank
+ \romannumeral\number\LT@cols 001 }}
+\def\LT@build@blank#1{%
+ \if#1m%
+ \noexpand\LT@entry{1}{0pt}%
+ \expandafter\LT@build@blank
+ \fi}
+\def\LT@make@row{%
+ \global\expandafter\let\expandafter\LT@save@row
+ \csname LT@\romannumeral\c@LT@tables\endcsname
+ \ifx\LT@save@row\relax
+ \LT@blank@row
+ \else
+ {\let\LT@entry\or
+ \if!%
+ \ifcase\expandafter\expandafter\expandafter\LT@cols
+ \expandafter\@gobble\LT@save@row
+ \or
+ \else
+ \relax
+ \fi
+ !%
+ \else
+ \aftergroup\LT@blank@row
+ \fi}%
+ \fi}
+\let\setlongtables\relax
+\def\LT@get@widths{%
+ \setbox\tw@\hbox{%
+ \unhbox\@ne
+ \let\LT@old@row\LT@save@row
+ \global\let\LT@save@row\@empty
+ \count@\LT@cols
+ \loop
+ \unskip
+ \setbox\tw@\lastbox
+ \ifhbox\tw@
+ \LT@def@row
+ \advance\count@\m@ne
+ \repeat}%
+ \ifx\LT@@save@row\@undefined
+ \let\LT@@save@row\LT@save@row
+ \fi}
+\def\LT@def@row{%
+ \let\LT@entry\or
+ \edef\@tempa{%
+ \ifcase\expandafter\count@\LT@old@row
+ \else
+ {1}{0pt}%
+ \fi}%
+ \let\LT@entry\relax
+ \xdef\LT@save@row{%
+ \LT@entry
+ \expandafter\LT@max@sel\@tempa
+ \LT@save@row}}
+\def\LT@max@sel#1#2{%
+ {\ifdim#2=\wd\tw@
+ #1%
+ \else
+ \number\c@LT@chunks
+ \fi}%
+ {\the\wd\tw@}}
+\def\LT@hline{%
+ \noalign{\ifnum0=`}\fi
+ \penalty\@M
+ \futurelet\@let@token\LT@@hline}
+\def\LT@@hline{%
+ \ifx\@let@token\hline
+ \global\let\@gtempa\@gobble
+ \gdef\LT@sep{\penalty-\@medpenalty\vskip\doublerulesep}%
+ \else
+ \global\let\@gtempa\@empty
+ \gdef\LT@sep{\penalty-\@lowpenalty\vskip-\arrayrulewidth}%
+ \fi
+ \ifnum0=`{\fi}%
+ \multispan\LT@cols
+ \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
+ \noalign{\LT@sep}%
+ \multispan\LT@cols
+ \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
+ \noalign{\penalty\@M}%
+ \@gtempa}
+\def\LT@caption{%
+ \noalign\bgroup
+ \@ifnextchar[{\egroup\LT@c@ption\@firstofone}\LT@capti@n}
+\def\LT@c@ption#1[#2]#3{%
+ \LT@makecaption#1\fnum@table{#3}%
+ \def\@tempa{#2}%
+ \ifx\@tempa\@empty\else
+ {\let\\\space
+ \addcontentsline{lot}{table}{\protect\numberline{\thetable}{#2}}}%
+ \fi}
+\def\LT@capti@n{%
+ \@ifstar
+ {\egroup\LT@c@ption\@gobble[]}%
+ {\egroup\@xdblarg{\LT@c@ption\@firstofone}}}
+\def\LT@makecaption#1#2#3{%
+ \LT@mcol\LT@cols c{\hbox to\z@{\hss\parbox[t]\LTcapwidth{%
+ \sbox\@tempboxa{#1{#2: }#3}%
+ \ifdim\wd\@tempboxa>\hsize
+ #1{#2: }#3%
+ \else
+ \hbox to\hsize{\hfil\box\@tempboxa\hfil}%
+ \fi
+ \endgraf\vskip\baselineskip}%
+ \hss}}}
+\def\LT@output{%
+ \ifnum\outputpenalty <-\@Mi
+ \ifnum\outputpenalty > -\LT@end@pen
+ \LT@err{floats and marginpars not allowed in a longtable}\@ehc
+ \else
+ \setbox\z@\vbox{\unvbox\@cclv}%
+ \ifdim \ht\LT@lastfoot>\ht\LT@foot
+ \dimen@\pagegoal
+ \advance\dimen@-\ht\LT@lastfoot
+ \ifdim\dimen@<\ht\z@
+ \setbox\@cclv\vbox{\unvbox\z@\copy\LT@foot\vss}%
+ \@makecol
+ \@outputpage
+ \setbox\z@\vbox{\box\LT@head}%
+ \fi
+ \fi
+ \global\@colroom\@colht
+ \global\vsize\@colht
+ \vbox
+ {\unvbox\z@\box\ifvoid\LT@lastfoot\LT@foot\else\LT@lastfoot\fi}%
+ \fi
+ \else
+ \setbox\@cclv\vbox{\unvbox\@cclv\copy\LT@foot\vss}%
+ \@makecol
+ \@outputpage
+ \global\vsize\@colroom
+ \copy\LT@head\nobreak
+ \fi}
+\def\LT@end@hd@ft#1{%
+ \LT@echunk
+ \ifx\LT@start\endgraf
+ \LT@err
+ {Longtable head or foot not at start of table}%
+ {Increase LTchunksize}%
+ \fi
+ \setbox#1\box\z@
+ \LT@get@widths
+ \LT@bchunk}
+\def\endfirsthead{\LT@end@hd@ft\LT@firsthead}
+\def\endhead{\LT@end@hd@ft\LT@head}
+\def\endfoot{\LT@end@hd@ft\LT@foot}
+\def\endlastfoot{\LT@end@hd@ft\LT@lastfoot}
+\def\LT@startpbox#1{%
+ \bgroup
+ \let\@footnotetext\LT@p@ftntext
+ \setlength\hsize{#1}%
+ \@arrayparboxrestore
+ \vrule \@height \ht\@arstrutbox \@width \z@}
+\def\LT@endpbox{%
+ \@finalstrut\@arstrutbox
+ \egroup
+ \the\LT@p@ftn
+ \global\LT@p@ftn{}%
+ \hfil}
+\def\LT@p@ftntext#1{%
+ \edef\@tempa{\the\LT@p@ftn\noexpand\footnotetext[\the\c@footnote]}%
+ \global\LT@p@ftn\expandafter{\@tempa{#1}}}%
+
+\@namedef{ver@longtable.sty}{2014/10/28 v4.11 Multi-page Table package (DPC) - frozen version for doxygen}
+\endinput
+%%
+%% End of file `longtable.sty'.
diff --git a/templates/latex/tabu_doxygen.sty b/templates/latex/tabu_doxygen.sty
new file mode 100755
index 0000000..f760aca
--- /dev/null
+++ b/templates/latex/tabu_doxygen.sty
@@ -0,0 +1,2557 @@
+%%
+%% This is file `tabu.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% tabu.dtx (with options: `package')
+%%
+%% This is a generated file.
+%% Copyright (FC) 2010-2011 - lppl
+%%
+%% tabu : 2011/02/26 v2.8 - tabu : Flexible LaTeX tabulars
+%%
+%% **********************************************************************************************
+%% \begin{tabu} { preamble } => default target: \linewidth or \linegoal
+%% \begin{tabu} to <dimen>{ preamble } => target specified
+%% \begin{tabu} spread <dimen>{ preamble } => target relative to the ``natural width''
+%%
+%% tabu works in text and in math modes.
+%%
+%% X columns: automatic width ajustment + horizontal and vertical alignment
+%% \begin{tabu} { X[4c] X[1c] X[-2ml] }
+%%
+%% Horizontal lines and / or leaders:
+%% \hline\hline => double horizontal line
+%% \firsthline\hline => for nested tabulars
+%% \lasthline\hline => for nested tabulars
+%% \tabucline[line spec]{column-column} => ``funny'' lines (dash/leader)
+%% Automatic lines / leaders :
+%% \everyrow{\hline\hline}
+%%
+%% Vertical lines and / or leaders:
+%% \begin{tabu} { |[3pt red] X[4c] X[1c] X[-2ml] |[3pt blue] }
+%% \begin{tabu} { |[3pt red] X[4c] X[1c] X[-2ml] |[3pt on 2pt off 4pt blue] }
+%%
+%% Fixed vertical spacing adjustment:
+%% \extrarowheight=<dimen> \extrarowdepth=<dimen>
+%% or: \extrarowsep=<dimen> => may be prefixed by \global
+%%
+%% Dynamic vertical spacing adjustment:
+%% \abovetabulinesep=<dimen> \belowtabulinesep=<dimen>
+%% or: \tabulinesep=<dimen> => may be prefixed by \global
+%%
+%% delarray.sty shortcuts: in math and text modes
+%% \begin{tabu} .... \({ preamble }\)
+%%
+%% Algorithms reports:
+%% \tracingtabu=1 \tracingtabu=2
+%%
+%% **********************************************************************************************
+%%
+%% This work may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3 of this license or (at your option) any later
+%% version. The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%%
+%% This work consists of the main source file tabu.dtx
+%% and the derived files
+%% tabu.sty, tabu.pdf, tabu.ins
+%%
+%% tabu : Flexible LaTeX tabulars
+%% lppl copyright 2010-2011 by FC <florent.chervet@free.fr>
+%%
+
+\NeedsTeXFormat{LaTeX2e}[2005/12/01]
+\ProvidesPackage{tabu_doxygen}[2011/02/26 v2.8 - flexible LaTeX tabulars (FC), frozen version for doxygen]
+\RequirePackage{array}[2008/09/09]
+\RequirePackage{varwidth}[2009/03/30]
+\AtEndOfPackage{\tabu@AtEnd \let\tabu@AtEnd \@undefined}
+\let\tabu@AtEnd\@empty
+\def\TMP@EnsureCode#1={%
+ \edef\tabu@AtEnd{\tabu@AtEnd
+ \catcode#1 \the\catcode#1}%
+ \catcode#1=%
+}% \TMP@EnsureCode
+\TMP@EnsureCode 33 = 12 % !
+\TMP@EnsureCode 58 = 12 % : (for siunitx)
+\TMP@EnsureCode124 = 12 % |
+\TMP@EnsureCode 36 = 3 % $ = math shift
+\TMP@EnsureCode 38 = 4 % & = tab alignmment character
+\TMP@EnsureCode 32 = 10 % space
+\TMP@EnsureCode 94 = 7 % ^
+\TMP@EnsureCode 95 = 8 % _
+%% Constants --------------------------------------------------------
+\newcount \c@taburow \def\thetaburow {\number\c@taburow}
+\newcount \tabu@nbcols
+\newcount \tabu@cnt
+\newcount \tabu@Xcol
+\let\tabu@start \@tempcnta
+\let\tabu@stop \@tempcntb
+\newcount \tabu@alloc \tabu@alloc=\m@ne
+\newcount \tabu@nested
+\def\tabu@alloc@{\global\advance\tabu@alloc \@ne \tabu@nested\tabu@alloc}
+\newdimen \tabu@target
+\newdimen \tabu@spreadtarget
+\newdimen \tabu@naturalX
+\newdimen \tabucolX
+\let\tabu@DELTA \@tempdimc
+\let\tabu@thick \@tempdima
+\let\tabu@on \@tempdimb
+\let\tabu@off \@tempdimc
+\newdimen \tabu@Xsum
+\newdimen \extrarowdepth
+\newdimen \abovetabulinesep
+\newdimen \belowtabulinesep
+\newdimen \tabustrutrule \tabustrutrule \z@
+\newtoks \tabu@thebody
+\newtoks \tabu@footnotes
+\newsavebox \tabu@box
+\newsavebox \tabu@arstrutbox
+\newsavebox \tabu@hleads
+\newsavebox \tabu@vleads
+\newif \iftabu@colortbl
+\newif \iftabu@siunitx
+\newif \iftabu@measuring
+\newif \iftabu@spread
+\newif \iftabu@negcoef
+\newif \iftabu@everyrow
+\def\tabu@everyrowtrue {\global\let\iftabu@everyrow \iftrue}
+\def\tabu@everyrowfalse{\global\let\iftabu@everyrow \iffalse}
+\newif \iftabu@long
+\newif \iftabuscantokens
+\def\tabu@rescan {\tabu@verbatim \scantokens }
+%% Utilities (for internal usage) -----------------------------------
+\def\tabu@gobblespace #1 {#1}
+\def\tabu@gobbletoken #1#2{#1}
+\def\tabu@gobbleX{\futurelet\@let@token \tabu@gobblex}
+\def\tabu@gobblex{\if ^^J\noexpand\@let@token \expandafter\@gobble
+ \else\ifx \@sptoken\@let@token
+ \expandafter\tabu@gobblespace\expandafter\tabu@gobbleX
+ \fi\fi
+}% \tabu@gobblex
+\def\tabu@X{^^J}
+{\obeyspaces
+\global\let\tabu@spxiii= % saves an active space (for \ifx)
+\gdef\tabu@@spxiii{ }}
+\def\tabu@ifenvir {% only for \multicolumn
+ \expandafter\tabu@if@nvir\csname\@currenvir\endcsname
+}% \tabu@ifenvir
+\def\tabu@if@nvir #1{\csname @\ifx\tabu#1first\else
+ \ifx\longtabu#1first\else
+ second\fi\fi oftwo\endcsname
+}% \tabu@ifenvir
+\def\tabu@modulo #1#2{\numexpr\ifnum\numexpr#1=\z@ 0\else #1-(#1-(#2-1)/2)/(#2)*(#2)\fi}
+{\catcode`\&=3
+\gdef\tabu@strtrim #1{% #1 = control sequence to trim
+ \ifodd 1\ifx #1\@empty \else \ifx #1\space \else 0\fi \fi
+ \let\tabu@c@l@r \@empty \let#1\@empty
+ \else \expandafter \tabu@trimspaces #1&#1\@nnil
+ \fi
+}% \tabu@strtrim
+\gdef\tabu@trimspaces #1&#2\@nnil{\let\tabu@c@l@r=#2\tabu@firstspace .#1& &#2}%
+\gdef\tabu@firstspace #1#2#3 &{\tabu@lastspace #2#3&}
+\gdef\tabu@lastspace #1&#2&#3{\def #3{#1}%
+ \ifx #3\tabu@c@l@r \def\tabu@c@l@r{\protect\color{#1}}\expandafter\remove@to@nnil \fi
+ \tabu@trimspaces #1&#3\@nnil}
+}% \catcode
+\def\tabu@sanitizearg #1#2{{%
+ \csname \ifcsname if@safe@actives\endcsname % <babel>
+ @safe@activestrue\else
+ relax\fi \endcsname
+ \edef#2{#1}\tabu@strtrim#2\@onelevel@sanitize#2%
+ \expandafter}\expandafter\def\expandafter#2\expandafter{#2}%
+}% \tabu@sanitizearg
+\def\tabu@textbar #1{\begingroup \endlinechar\m@ne \scantokens{\def\:{|}}%
+ \expandafter\endgroup \expandafter#1\:% !!! semi simple group !!!
+}% \tabu@textbar
+\def\tabu@everyrow@bgroup{\iftabu@everyrow \begingroup \else \noalign{\ifnum0=`}\fi \fi}
+\def\tabu@everyrow@egroup{%
+ \iftabu@everyrow \expandafter \endgroup \the\toks@
+ \else \ifnum0=`{\fi}%
+ \fi
+}% \tabu@everyrow@egroup
+\def\tabu@arstrut {\global\setbox\@arstrutbox \hbox{\vrule
+ height \arraystretch \dimexpr\ht\strutbox+\extrarowheight
+ depth \arraystretch \dimexpr\dp\strutbox+\extrarowdepth
+ width \z@}%
+}% \tabu@arstrut
+\def\tabu@rearstrut {%
+ \@tempdima \arraystretch\dimexpr\ht\strutbox+\extrarowheight \relax
+ \@tempdimb \arraystretch\dimexpr\dp\strutbox+\extrarowdepth \relax
+ \ifodd 1\ifdim \ht\@arstrutbox=\@tempdima
+ \ifdim \dp\@arstrutbox=\@tempdimb 0 \fi\fi
+ \tabu@mkarstrut
+ \fi
+}% \tabu@rearstrut
+\def\tabu@@DBG #1{\ifdim\tabustrutrule>\z@ \color{#1}\fi}
+\def\tabu@DBG@arstrut {\global\setbox\@arstrutbox
+ \hbox to\z@{\hbox to\z@{\hss
+ {\tabu@DBG{cyan}\vrule
+ height \arraystretch \dimexpr\ht\strutbox+\extrarowheight
+ depth \z@
+ width \tabustrutrule}\kern-\tabustrutrule
+ {\tabu@DBG{pink}\vrule
+ height \z@
+ depth \arraystretch \dimexpr\dp\strutbox+\extrarowdepth
+ width \tabustrutrule}}}%
+}% \tabu@DBG@arstrut
+\def\tabu@save@decl{\toks\count@ \expandafter{\the\toks\expandafter\count@
+ \@nextchar}}%
+\def\tabu@savedecl{\ifcat$\d@llarend\else
+ \let\save@decl \tabu@save@decl \fi % no inversion of tokens in text mode
+}% \tabu@savedecl
+\def\tabu@finalstrut #1{\unskip\ifhmode\nobreak\fi\vrule height\z@ depth\z@ width\z@}
+\newcommand*\tabuDisableCommands {\g@addto@macro\tabu@trialh@@k }
+\let\tabu@trialh@@k \@empty
+\def\tabu@nowrite #1#{{\afterassignment}\toks@}
+\let\tabu@write\write
+\let\tabu@immediate\immediate
+\def\tabu@WRITE{\begingroup
+ \def\immediate\write{\aftergroup\endgroup
+ \tabu@immediate\tabu@write}%
+}% \tabu@WRITE
+\expandafter\def\expandafter\tabu@GenericError\expandafter{%
+ \expandafter\tabu@WRITE\GenericError}
+\def\tabu@warn{\tabu@WRITE\PackageWarning{tabu}}
+\def\tabu@noxfootnote [#1]{\@gobble}
+\def\tabu@nocolor #1#{\@gobble}
+\newcommand*\tabu@norowcolor[2][]{}
+\def\tabu@maybesiunitx #1{\def\tabu@temp{#1}%
+ \futurelet\@let@token \tabu@m@ybesiunitx}
+\def\tabu@m@ybesiunitx #1{\def\tabu@m@ybesiunitx {%
+ \ifx #1\@let@token \let\tabu@cellleft \@empty \let\tabu@cellright \@empty \fi
+ \tabu@temp}% \tabu@m@ybesiunitx
+}\expandafter\tabu@m@ybesiunitx \csname siunitx_table_collect_begin:Nn\endcsname
+\def\tabu@celllalign@def #1{\def\tabu@celllalign{\tabu@maybesiunitx{#1}}}%
+%% Fixed vertical spacing adjustment: \extrarowsep ------------------
+\newcommand*\extrarowsep{\edef\tabu@C@extra{\the\numexpr\tabu@C@extra+1}%
+ \iftabu@everyrow \aftergroup\tabu@Gextra
+ \else \aftergroup\tabu@n@Gextra
+ \fi
+ \@ifnextchar={\tabu@gobbletoken\tabu@extra} \tabu@extra
+}% \extrarowsep
+\def\tabu@extra {\@ifnextchar_%
+ {\tabu@gobbletoken{\tabu@setextra\extrarowheight \extrarowdepth}}
+ {\ifx ^\@let@token \def\tabu@temp{%
+ \tabu@gobbletoken{\tabu@setextra\extrarowdepth \extrarowheight}}%
+ \else \let\tabu@temp \@empty
+ \afterassignment \tabu@setextrasep \extrarowdepth
+ \fi \tabu@temp}%
+}% \tabu@extra
+\def\tabu@setextra #1#2{\def\tabu@temp{\tabu@extr@#1#2}\afterassignment\tabu@temp#2}
+\def\tabu@extr@ #1#2{\@ifnextchar^%
+ {\tabu@gobbletoken{\tabu@setextra\extrarowdepth \extrarowheight}}
+ {\ifx _\@let@token \def\tabu@temp{%
+ \tabu@gobbletoken{\tabu@setextra\extrarowheight \extrarowdepth}}%
+ \else \let\tabu@temp \@empty
+ \tabu@Gsave \tabu@G@extra \tabu@C@extra \extrarowheight \extrarowdepth
+ \fi \tabu@temp}%
+}% \tabu@extr@
+\def\tabu@setextrasep {\extrarowheight=\extrarowdepth
+ \tabu@Gsave \tabu@G@extra \tabu@C@extra \extrarowheight \extrarowdepth
+}% \tabu@setextrasep
+\def\tabu@Gextra{\ifx \tabu@G@extra\@empty \else {\tabu@Rextra}\fi}
+\def\tabu@n@Gextra{\ifx \tabu@G@extra\@empty \else \noalign{\tabu@Rextra}\fi}
+\def\tabu@Rextra{\tabu@Grestore \tabu@G@extra \tabu@C@extra}
+\let\tabu@C@extra \z@
+\let\tabu@G@extra \@empty
+%% Dynamic vertical spacing adjustment: \tabulinesep ----------------
+\newcommand*\tabulinesep{\edef\tabu@C@linesep{\the\numexpr\tabu@C@linesep+1}%
+ \iftabu@everyrow \aftergroup\tabu@Glinesep
+ \else \aftergroup\tabu@n@Glinesep
+ \fi
+ \@ifnextchar={\tabu@gobbletoken\tabu@linesep} \tabu@linesep
+}% \tabulinesep
+\def\tabu@linesep {\@ifnextchar_%
+ {\tabu@gobbletoken{\tabu@setsep\abovetabulinesep \belowtabulinesep}}
+ {\ifx ^\@let@token \def\tabu@temp{%
+ \tabu@gobbletoken{\tabu@setsep\belowtabulinesep \abovetabulinesep}}%
+ \else \let\tabu@temp \@empty
+ \afterassignment \tabu@setlinesep \abovetabulinesep
+ \fi \tabu@temp}%
+}% \tabu@linesep
+\def\tabu@setsep #1#2{\def\tabu@temp{\tabu@sets@p#1#2}\afterassignment\tabu@temp#2}
+\def\tabu@sets@p #1#2{\@ifnextchar^%
+ {\tabu@gobbletoken{\tabu@setsep\belowtabulinesep \abovetabulinesep}}
+ {\ifx _\@let@token \def\tabu@temp{%
+ \tabu@gobbletoken{\tabu@setsep\abovetabulinesep \belowtabulinesep}}%
+ \else \let\tabu@temp \@empty
+ \tabu@Gsave \tabu@G@linesep \tabu@C@linesep \abovetabulinesep \belowtabulinesep
+ \fi \tabu@temp}%
+}% \tabu@sets@p
+\def\tabu@setlinesep {\belowtabulinesep=\abovetabulinesep
+ \tabu@Gsave \tabu@G@linesep \tabu@C@linesep \abovetabulinesep \belowtabulinesep
+}% \tabu@setlinesep
+\def\tabu@Glinesep{\ifx \tabu@G@linesep\@empty \else {\tabu@Rlinesep}\fi}
+\def\tabu@n@Glinesep{\ifx \tabu@G@linesep\@empty \else \noalign{\tabu@Rlinesep}\fi}
+\def\tabu@Rlinesep{\tabu@Grestore \tabu@G@linesep \tabu@C@linesep}
+\let\tabu@C@linesep \z@
+\let\tabu@G@linesep \@empty
+%% \global\extrarowsep and \global\tabulinesep -------------------
+\def\tabu@Gsave #1#2#3#4{\xdef#1{#1%
+ \toks#2{\toks\the\currentgrouplevel{\global#3\the#3\global#4\the#4}}}%
+}% \tabu@Gsave
+\def\tabu@Grestore#1#2{%
+ \toks#2{}#1\toks\currentgrouplevel\expandafter{\expandafter}\the\toks#2\relax
+ \ifcat$\the\toks\currentgrouplevel$\else
+ \global\let#1\@empty \global\let#2\z@
+ \the\toks\currentgrouplevel
+ \fi
+}% \tabu@Grestore
+%% Setting code for every row ---------------------------------------
+\newcommand*\everyrow{\tabu@everyrow@bgroup
+ \tabu@start \z@ \tabu@stop \z@ \tabu@evrstartstop
+}% \everyrow
+\def\tabu@evrstartstop {\@ifnextchar^%
+ {\afterassignment \tabu@evrstartstop \tabu@stop=}%
+ {\ifx ^\@let@token
+ \afterassignment\tabu@evrstartstop \tabu@start=%
+ \else \afterassignment\tabu@everyr@w \toks@
+ \fi}%
+}% \tabu@evrstartstop
+\def\tabu@everyr@w {%
+ \xdef\tabu@everyrow{%
+ \noexpand\tabu@everyrowfalse
+ \let\noalign \relax
+ \noexpand\tabu@rowfontreset
+ \iftabu@colortbl \noexpand\tabu@rc@ \fi % \taburowcolors
+ \let\noexpand\tabu@docline \noexpand\tabu@docline@evr
+ \the\toks@
+ \noexpand\tabu@evrh@@k
+ \noexpand\tabu@rearstrut
+ \global\advance\c@taburow \@ne}%
+ \iftabu@everyrow \toks@\expandafter
+ {\expandafter\def\expandafter\tabu@evr@L\expandafter{\the\toks@}\ignorespaces}%
+ \else \xdef\tabu@evr@G{\the\toks@}%
+ \fi
+ \tabu@everyrow@egroup
+}% \tabu@everyr@w
+\def\tabu@evr {\def\tabu@evrh@@k} % for internal use only
+\tabu@evr{}
+%% line style and leaders -------------------------------------------
+\newcommand*\newtabulinestyle [1]{%
+ {\@for \@tempa :=#1\do{\expandafter\tabu@newlinestyle \@tempa==\@nil}}%
+}% \newtabulinestyle
+\def\tabu@newlinestyle #1=#2=#3\@nil{\tabu@getline {#2}%
+ \tabu@sanitizearg {#1}\@tempa
+ \ifodd 1\ifx \@tempa\@empty \ifdefined\tabu@linestyle@ 0 \fi\fi
+ \global\expandafter\let
+ \csname tabu@linestyle@\@tempa \endcsname =\tabu@thestyle \fi
+}% \tabu@newlinestyle
+\newcommand*\tabulinestyle [1]{\tabu@everyrow@bgroup \tabu@getline{#1}%
+ \iftabu@everyrow
+ \toks@\expandafter{\expandafter \def \expandafter
+ \tabu@ls@L\expandafter{\tabu@thestyle}\ignorespaces}%
+ \gdef\tabu@ls@{\tabu@ls@L}%
+ \else
+ \global\let\tabu@ls@G \tabu@thestyle
+ \gdef\tabu@ls@{\tabu@ls@G}%
+ \fi
+ \tabu@everyrow@egroup
+}% \tabulinestyle
+\newcommand*\taburulecolor{\tabu@everyrow@bgroup \tabu@textbar \tabu@rulecolor}
+\def\tabu@rulecolor #1{\toks@{}%
+ \def\tabu@temp #1##1#1{\tabu@ruledrsc{##1}}\@ifnextchar #1%
+ \tabu@temp
+ \tabu@rulearc
+}% \tabu@rulecolor
+\def\tabu@ruledrsc #1{\edef\tabu@temp{#1}\tabu@strtrim\tabu@temp
+ \ifx \tabu@temp\@empty \def\tabu@temp{\tabu@rule@drsc@ {}{}}%
+ \else \edef\tabu@temp{\noexpand\tabu@rule@drsc@ {}{\tabu@temp}}%
+ \fi
+ \tabu@temp
+}% \tabu@ruledrsc@
+\def\tabu@ruledrsc@ #1#{\tabu@rule@drsc@ {#1}}
+\def\tabu@rule@drsc@ #1#2{%
+ \iftabu@everyrow
+ \ifx \\#1#2\\\toks@{\let\CT@drsc@ \relax}%
+ \else \toks@{\def\CT@drsc@{\color #1{#2}}}%
+ \fi
+ \else
+ \ifx \\#1#2\\\global\let\CT@drsc@ \relax
+ \else \gdef\CT@drsc@{\color #1{#2}}%
+ \fi
+ \fi
+ \tabu@rulearc
+}% \tabu@rule@drsc@
+\def\tabu@rulearc #1#{\tabu@rule@arc@ {#1}}
+\def\tabu@rule@arc@ #1#2{%
+ \iftabu@everyrow
+ \ifx \\#1#2\\\toks@\expandafter{\the\toks@ \def\CT@arc@{}}%
+ \else \toks@\expandafter{\the\toks@ \def\CT@arc@{\color #1{#2}}}%
+ \fi
+ \toks@\expandafter{\the\toks@
+ \let\tabu@arc@L \CT@arc@
+ \let\tabu@drsc@L \CT@drsc@
+ \ignorespaces}%
+ \else
+ \ifx \\#1#2\\\gdef\CT@arc@{}%
+ \else \gdef\CT@arc@{\color #1{#2}}%
+ \fi
+ \global\let\tabu@arc@G \CT@arc@
+ \global\let\tabu@drsc@G \CT@drsc@
+ \fi
+ \tabu@everyrow@egroup
+}% \tabu@rule@arc@
+\def\taburowcolors {\tabu@everyrow@bgroup \@testopt \tabu@rowcolors 1}
+\def\tabu@rowcolors [#1]#2#{\tabu@rowc@lors{#1}{#2}}
+\def\tabu@rowc@lors #1#2#3{%
+ \toks@{}\@defaultunits \count@ =\number0#2\relax \@nnil
+ \@defaultunits \tabu@start =\number0#1\relax \@nnil
+ \ifnum \count@<\tw@ \count@=\tw@ \fi
+ \advance\tabu@start \m@ne
+ \ifnum \tabu@start<\z@ \tabu@start \z@ \fi
+ \tabu@rowcolorseries #3\in@..\in@ \@nnil
+}% \tabu@rowcolors
+\def\tabu@rowcolorseries #1..#2\in@ #3\@nnil {%
+ \ifx \in@#1\relax
+ \iftabu@everyrow \toks@{\def\tabu@rc@{}\let\tabu@rc@L \tabu@rc@}%
+ \else \gdef\tabu@rc@{}\global\let\tabu@rc@G \tabu@rc@
+ \fi
+ \else
+ \ifx \\#2\\\tabu@rowcolorserieserror \fi
+ \tabu@sanitizearg{#1}\tabu@temp
+ \tabu@sanitizearg{#2}\@tempa
+ \advance\count@ \m@ne
+ \iftabu@everyrow
+ \def\tabu@rc@ ##1##2##3##4{\def\tabu@rc@{%
+ \ifnum ##2=\c@taburow
+ \definecolorseries{tabu@rcseries@\the\tabu@nested}{rgb}{last}{##3}{##4}\fi
+ \ifnum \c@taburow<##2 \else
+ \ifnum \tabu@modulo {\c@taburow-##2}{##1+1}=\z@
+ \resetcolorseries[{##1}]{tabu@rcseries@\the\tabu@nested}\fi
+ \xglobal\colorlet{tabu@rc@\the\tabu@nested}{tabu@rcseries@\the\tabu@nested!!+}%
+ \rowcolor{tabu@rc@\the\tabu@nested}\fi}%
+ }\edef\x{\noexpand\tabu@rc@ {\the\count@}
+ {\the\tabu@start}
+ {\tabu@temp}
+ {\@tempa}%
+ }\x
+ \toks@\expandafter{\expandafter\def\expandafter\tabu@rc@\expandafter{\tabu@rc@}}%
+ \toks@\expandafter{\the\toks@ \let\tabu@rc@L \tabu@rc@ \ignorespaces}%
+ \else % inside \noalign
+ \definecolorseries{tabu@rcseries@\the\tabu@nested}{rgb}{last}{\tabu@temp}{\@tempa}%
+ \expandafter\resetcolorseries\expandafter[\the\count@]{tabu@rcseries@\the\tabu@nested}%
+ \xglobal\colorlet{tabu@rc@\the\tabu@nested}{tabu@rcseries@\the\tabu@nested!!+}%
+ \let\noalign \relax \rowcolor{tabu@rc@\the\tabu@nested}%
+ \def\tabu@rc@ ##1##2{\gdef\tabu@rc@{%
+ \ifnum \tabu@modulo {\c@taburow-##2}{##1+1}=\@ne
+ \resetcolorseries[{##1}]{tabu@rcseries@\the\tabu@nested}\fi
+ \xglobal\colorlet{tabu@rc@\the\tabu@nested}{tabu@rcseries@\the\tabu@nested!!+}%
+ \rowcolor{tabu@rc@\the\tabu@nested}}%
+ }\edef\x{\noexpand\tabu@rc@{\the\count@}{\the\c@taburow}}\x
+ \global\let\tabu@rc@G \tabu@rc@
+ \fi
+ \fi
+ \tabu@everyrow@egroup
+}% \tabu@rowcolorseries
+\tabuDisableCommands {\let\tabu@rc@ \@empty }
+\def\tabu@rowcolorserieserror {\PackageError{tabu}
+ {Invalid syntax for \string\taburowcolors
+ \MessageBreak Please look at the documentation!}\@ehd
+}% \tabu@rowcolorserieserror
+\newcommand*\tabureset {%
+ \tabulinesep=\z@ \extrarowsep=\z@ \extratabsurround=\z@
+ \tabulinestyle{}\everyrow{}\taburulecolor||{}\taburowcolors{}%
+}% \tabureset
+%% Parsing the line styles ------------------------------------------
+\def\tabu@getline #1{\begingroup
+ \csname \ifcsname if@safe@actives\endcsname % <babel>
+ @safe@activestrue\else
+ relax\fi \endcsname
+ \edef\tabu@temp{#1}\tabu@sanitizearg{#1}\@tempa
+ \let\tabu@thestyle \relax
+ \ifcsname tabu@linestyle@\@tempa \endcsname
+ \edef\tabu@thestyle{\endgroup
+ \def\tabu@thestyle{\expandafter\noexpand
+ \csname tabu@linestyle@\@tempa\endcsname}%
+ }\tabu@thestyle
+ \else \expandafter\tabu@definestyle \tabu@temp \@nil
+ \fi
+}% \tabu@getline
+\def\tabu@definestyle #1#2\@nil {\endlinechar \m@ne \makeatletter
+ \tabu@thick \maxdimen \tabu@on \maxdimen \tabu@off \maxdimen
+ \let\tabu@c@lon \@undefined \let\tabu@c@loff \@undefined
+ \ifodd 1\ifcat .#1\else\ifcat\relax #1\else 0\fi\fi % catcode 12 or non expandable cs
+ \def\tabu@temp{\tabu@getparam{thick}}%
+ \else \def\tabu@temp{\tabu@getparam{thick}\maxdimen}%
+ \fi
+ {%
+ \let\tabu@ \relax
+ \def\:{\obeyspaces \tabu@oXIII \tabu@commaXIII \edef\:}% (space active \: happy ;-))
+ \scantokens{\:{\tabu@temp #1#2 \tabu@\tabu@}}%
+ \expandafter}\expandafter
+ \def\expandafter\:\expandafter{\:}% line spec rewritten now ;-)
+ \def\;{\def\:}%
+ \scantokens\expandafter{\expandafter\;\expandafter{\:}}% space is now inactive (catcode 10)
+ \let\tabu@ \tabu@getcolor \:% all arguments are ready now ;-)
+ \ifdefined\tabu@c@lon \else \let\tabu@c@lon\@empty \fi
+ \ifx \tabu@c@lon\@empty \def\tabu@c@lon{\CT@arc@}\fi
+ \ifdefined\tabu@c@loff \else \let\tabu@c@loff \@empty \fi
+ \ifdim \tabu@on=\maxdimen \ifdim \tabu@off<\maxdimen
+ \tabu@on \tabulineon \fi\fi
+ \ifdim \tabu@off=\maxdimen \ifdim \tabu@on<\maxdimen
+ \tabu@off \tabulineoff \fi\fi
+ \ifodd 1\ifdim \tabu@off=\maxdimen \ifdim \tabu@on=\maxdimen 0 \fi\fi
+ \in@true % <leaders>
+ \else \in@false % <rule>
+ \fi
+ \ifdim\tabu@thick=\maxdimen \def\tabu@thick{\arrayrulewidth}%
+ \else \edef\tabu@thick{\the\tabu@thick}%
+ \fi
+ \edef \tabu@thestyle ##1##2{\endgroup
+ \def\tabu@thestyle{%
+ \ifin@ \noexpand\tabu@leadersstyle {\tabu@thick}
+ {\the\tabu@on}{##1}
+ {\the\tabu@off}{##2}%
+ \else \noexpand\tabu@rulesstyle
+ {##1\vrule width \tabu@thick}%
+ {##1\leaders \hrule height \tabu@thick \hfil}%
+ \fi}%
+ }\expandafter \expandafter
+ \expandafter \tabu@thestyle \expandafter
+ \expandafter \expandafter
+ {\expandafter\tabu@c@lon\expandafter}\expandafter{\tabu@c@loff}%
+}% \tabu@definestyle
+{\catcode`\O=\active \lccode`\O=`\o \catcode`\,=\active
+ \lowercase{\gdef\tabu@oXIII {\catcode`\o=\active \let O=\tabu@oxiii}}
+ \gdef\tabu@commaXIII {\catcode`\,=\active \let ,=\space}
+}% \catcode
+\def\tabu@oxiii #1{%
+ \ifcase \ifx n#1\z@ \else
+ \ifx f#1\@ne\else
+ \tw@ \fi\fi
+ \expandafter\tabu@onxiii
+ \or \expandafter\tabu@ofxiii
+ \else o%
+ \fi#1}%
+\def\tabu@onxiii #1#2{%
+ \ifcase \ifx !#2\tw@ \else
+ \ifcat.\noexpand#2\z@ \else
+ \ifx \tabu@spxiii#2\@ne\else
+ \tw@ \fi\fi\fi
+ \tabu@getparam{on}#2\expandafter\@gobble
+ \or \expandafter\tabu@onxiii % (space is active)
+ \else o\expandafter\@firstofone
+ \fi{#1#2}}%
+\def\tabu@ofxiii #1#2{%
+ \ifx #2f\expandafter\tabu@offxiii
+ \else o\expandafter\@firstofone
+ \fi{#1#2}}
+\def\tabu@offxiii #1#2{%
+ \ifcase \ifx !#2\tw@ \else
+ \ifcat.\noexpand#2\z@ \else
+ \ifx\tabu@spxiii#2\@ne \else
+ \tw@ \fi\fi\fi
+ \tabu@getparam{off}#2\expandafter\@gobble
+ \or \expandafter\tabu@offxiii % (space is active)
+ \else o\expandafter\@firstofone
+ \fi{#1#2}}
+\def\tabu@getparam #1{\tabu@ \csname tabu@#1\endcsname=}
+\def\tabu@getcolor #1{% \tabu@ <- \tabu@getcolor after \edef
+ \ifx \tabu@#1\else % no more spec
+ \let\tabu@theparam=#1\afterassignment \tabu@getc@l@r #1\fi
+}% \tabu@getcolor
+\def\tabu@getc@l@r #1\tabu@ {%
+ \def\tabu@temp{#1}\tabu@strtrim \tabu@temp
+ \ifx \tabu@temp\@empty
+ \else%\ifcsname \string\color@\tabu@temp \endcsname % if the color exists
+ \ifx \tabu@theparam \tabu@off \let\tabu@c@loff \tabu@c@l@r
+ \else \let\tabu@c@lon \tabu@c@l@r
+ \fi
+ %\else \tabu@warncolour{\tabu@temp}%
+ \fi%\fi
+ \tabu@ % next spec
+}% \tabu@getc@l@r
+\def\tabu@warncolour #1{\PackageWarning{tabu}
+ {Color #1 is not defined. Default color used}%
+}% \tabu@warncolour
+\def\tabu@leadersstyle #1#2#3#4#5{\def\tabu@leaders{{#1}{#2}{#3}{#4}{#5}}%
+ \ifx \tabu@leaders\tabu@leaders@G \else
+ \tabu@LEADERS{#1}{#2}{#3}{#4}{#5}\fi
+}% \tabu@leadersstyle
+\def\tabu@rulesstyle #1#2{\let\tabu@leaders \@undefined
+ \gdef\tabu@thevrule{#1}\gdef\tabu@thehrule{#2}%
+}% \tabu@rulesstyle
+%% The leaders boxes ------------------------------------------------
+\def\tabu@LEADERS #1#2#3#4#5{%% width, dash, dash color, gap, gap color
+ {\let\color \tabu@color % => during trials -> \color = \tabu@nocolor
+ {% % but the leaders boxes should have colors !
+ \def\@therule{\vrule}\def\@thick{height}\def\@length{width}%
+ \def\@box{\hbox}\def\@unbox{\unhbox}\def\@elt{\wd}%
+ \def\@skip{\hskip}\def\@ss{\hss}\def\tabu@leads{\tabu@hleads}%
+ \tabu@l@@d@rs {#1}{#2}{#3}{#4}{#5}%
+ \global\let\tabu@thehleaders \tabu@theleaders
+ }%
+ {%
+ \def\@therule{\hrule}\def\@thick{width}\def\@length{height}%
+ \def\@box{\vbox}\def\@unbox{\unvbox}\def\@elt{\ht}%
+ \def\@skip{\vskip}\def\@ss{\vss}\def\tabu@leads{\tabu@vleads}%
+ \tabu@l@@d@rs {#1}{#2}{#3}{#4}{#5}%
+ \global\let\tabu@thevleaders \tabu@theleaders
+ }%
+ \gdef\tabu@leaders@G{{#1}{#2}{#3}{#4}{#5}}%
+ }%
+}% \tabu@LEADERS
+\def\tabu@therule #1#2{\@therule \@thick#1\@length\dimexpr#2/2 \@depth\z@}
+\def\tabu@l@@d@rs #1#2#3#4#5{%% width, dash, dash color, gap, gap color
+ \global\setbox \tabu@leads=\@box{%
+ {#3\tabu@therule{#1}{#2}}%
+ \ifx\\#5\\\@skip#4\else{#5\tabu@therule{#1}{#4*2}}\fi
+ {#3\tabu@therule{#1}{#2}}}%
+ \global\setbox\tabu@leads=\@box to\@elt\tabu@leads{\@ss
+ {#3\tabu@therule{#1}{#2}}\@unbox\tabu@leads}%
+ \edef\tabu@theleaders ##1{\def\noexpand\tabu@theleaders {%
+ {##1\tabu@therule{#1}{#2}}%
+ \xleaders \copy\tabu@leads \@ss
+ \tabu@therule{0pt}{-#2}{##1\tabu@therule{#1}{#2}}}%
+ }\tabu@theleaders{#3}%
+}% \tabu@l@@d@rs
+%% \tabu \endtabu \tabu* \longtabu \endlongtabu \longtabu* ----------
+\newcommand*\tabu {\tabu@longfalse
+ \ifmmode \def\tabu@ {\array}\def\endtabu {\endarray}%
+ \else \def\tabu@ {\tabu@tabular}\def\endtabu {\endtabular}\fi
+ \expandafter\let\csname tabu*\endcsname \tabu
+ \expandafter\def\csname endtabu*\endcsname{\endtabu}%
+ \tabu@spreadfalse \tabu@negcoeffalse \tabu@settarget
+}% {tabu}
+\let\tabu@tabular \tabular % <For LyX: some users redefine \tabular...>
+\expandafter\def\csname tabu*\endcsname{\tabuscantokenstrue \tabu}
+\newcommand*\longtabu {\tabu@longtrue
+ \ifmmode\PackageError{tabu}{longtabu not allowed in math mode}\fi
+ \def\tabu@{\longtable}\def\endlongtabu{\endlongtable}%
+ \LTchunksize=\@M
+ \expandafter\let\csname tabu*\endcsname \tabu
+ \expandafter\def\csname endlongtabu*\endcsname{\endlongtabu}%
+ \let\LT@startpbox \tabu@LT@startpbox % \everypar{ array struts }
+ \tabu@spreadfalse \tabu@negcoeffalse \tabu@settarget
+}% {longtabu}
+\expandafter\def\csname longtabu*\endcsname{\tabuscantokenstrue \longtabu}
+\def\tabu@nolongtabu{\PackageError{tabu}
+ {longtabu requires the longtable package}\@ehd}
+%% Read the target and then : \tabular or \@array ------------------
+\def\tabu@settarget {\futurelet\@let@token \tabu@sett@rget }
+\def\tabu@sett@rget {\tabu@target \z@
+ \ifcase \ifx \bgroup\@let@token \z@ \else
+ \ifx \@sptoken\@let@token \@ne \else
+ \if t\@let@token \tw@ \else
+ \if s\@let@token \thr@@\else
+ \z@\fi\fi\fi\fi
+ \expandafter\tabu@begin
+ \or \expandafter\tabu@gobblespace\expandafter\tabu@settarget
+ \or \expandafter\tabu@to
+ \or \expandafter\tabu@spread
+ \fi
+}% \tabu@sett@rget
+\def\tabu@to to{\def\tabu@halignto{to}\tabu@gettarget}
+\def\tabu@spread spread{\tabu@spreadtrue\def\tabu@halignto{spread}\tabu@gettarget}
+\def\tabu@gettarget {\afterassignment\tabu@linegoaltarget \tabu@target }
+\def\tabu@linegoaltarget {\futurelet\tabu@temp \tabu@linegoalt@rget }
+\def\tabu@linegoalt@rget {%
+ \ifx \tabu@temp\LNGL@setlinegoal
+ \LNGL@setlinegoal \expandafter \@firstoftwo \fi % @gobbles \LNGL@setlinegoal
+ \tabu@begin
+}% \tabu@linegoalt@rget
+\def\tabu@begin #1#{%
+ \iftabu@measuring \expandafter\tabu@nestedmeasure \fi
+ \ifdim \tabu@target=\z@ \let\tabu@halignto \@empty
+ \else \edef\tabu@halignto{\tabu@halignto\the\tabu@target}%
+ \fi
+ \@testopt \tabu@tabu@ \tabu@aligndefault #1\@nil
+}% \tabu@begin
+\long\def\tabu@tabu@ [#1]#2\@nil #3{\tabu@setup
+ \def\tabu@align {#1}\def\tabu@savedpream{\NC@find #3}%
+ \tabu@ [\tabu@align ]#2{#3\tabu@rewritefirst }%
+}% \tabu@tabu@
+\def\tabu@nestedmeasure {%
+ \ifodd 1\iftabu@spread \else \ifdim\tabu@target=\z@ \else 0 \fi\fi\relax
+ \tabu@spreadtrue
+ \else \begingroup \iffalse{\fi \ifnum0=`}\fi
+ \toks@{}\def\tabu@stack{b}%
+ \expandafter\tabu@collectbody\expandafter\tabu@quickrule
+ \expandafter\endgroup
+ \fi
+}% \tabu@nestedmeasure
+\def\tabu@quickrule {\indent\vrule height\z@ depth\z@ width\tabu@target}
+%% \tabu@setup \tabu@init \tabu@indent
+\def\tabu@setup{\tabu@alloc@
+ \ifcase \tabu@nested
+ \ifmmode \else \iftabu@spread\else \ifdim\tabu@target=\z@
+ \let\tabu@afterendpar \par
+ \fi\fi\fi
+ \def\tabu@aligndefault{c}\tabu@init \tabu@indent
+ \else % <nested tabu>
+ \def\tabu@aligndefault{t}\let\tabudefaulttarget \linewidth
+ \fi
+ \let\tabu@thetarget \tabudefaulttarget \let\tabu@restored \@undefined
+ \edef\tabu@NC@list{\the\NC@list}\NC@list{\NC@do \tabu@rewritefirst}%
+ \everycr{}\let\@startpbox \tabu@startpbox % for nested tabu inside longtabu...
+ \let\@endpbox \tabu@endpbox % idem " " " " " "
+ \let\@tabarray \tabu@tabarray % idem " " " " " "
+ \tabu@setcleanup \tabu@setreset
+}% \tabu@setup
+\def\tabu@init{\tabu@starttimer \tabu@measuringfalse
+ \edef\tabu@hfuzz {\the\dimexpr\hfuzz+1sp}\global\tabu@footnotes{}%
+ \let\firsthline \tabu@firsthline \let\lasthline \tabu@lasthline
+ \let\firstline \tabu@firstline \let\lastline \tabu@lastline
+ \let\hline \tabu@hline \let\@xhline \tabu@xhline
+ \let\color \tabu@color \let\@arstrutbox \tabu@arstrutbox
+ \iftabu@colortbl\else\let\LT@@hline \tabu@LT@@hline \fi
+ \tabu@trivlist %<restore \\=\@normalcr inside lists>
+ \let\@footnotetext \tabu@footnotetext \let\@xfootnotetext \tabu@xfootnotetext
+ \let\@xfootnote \tabu@xfootnote \let\centering \tabu@centering
+ \let\raggedright \tabu@raggedright \let\raggedleft \tabu@raggedleft
+ \let\tabudecimal \tabu@tabudecimal \let\Centering \tabu@Centering
+ \let\RaggedRight \tabu@RaggedRight \let\RaggedLeft \tabu@RaggedLeft
+ \let\justifying \tabu@justifying \let\rowfont \tabu@rowfont
+ \let\fbox \tabu@fbox \let\color@b@x \tabu@color@b@x
+ \let\tabu@@everycr \everycr \let\tabu@@everypar \everypar
+ \let\tabu@prepnext@tokORI \prepnext@tok\let\prepnext@tok \tabu@prepnext@tok
+ \let\tabu@multicolumnORI\multicolumn \let\multicolumn \tabu@multicolumn
+ \let\tabu@startpbox \@startpbox % for nested tabu inside longtabu pfff !!!
+ \let\tabu@endpbox \@endpbox % idem " " " " " " "
+ \let\tabu@tabarray \@tabarray % idem " " " " " " "
+ \tabu@adl@fix \let\endarray \tabu@endarray % <fix> colortbl & arydshln (delarray)
+ \iftabu@colortbl\CT@everycr\expandafter{\expandafter\iftabu@everyrow \the\CT@everycr \fi}\fi
+}% \tabu@init
+\def\tabu@indent{% correction for indentation
+ \ifdim \parindent>\z@\ifx \linewidth\tabudefaulttarget
+ \everypar\expandafter{%
+ \the\everypar\everypar\expandafter{\the\everypar}%
+ \setbox\z@=\lastbox
+ \ifdim\wd\z@>\z@ \edef\tabu@thetarget
+ {\the\dimexpr -\wd\z@+\tabudefaulttarget}\fi
+ \box\z@}%
+ \fi\fi
+}% \tabu@indent
+\def\tabu@setcleanup {% saves last global assignments
+ \ifodd 1\ifmmode \else \iftabu@long \else 0\fi\fi\relax
+ \def\tabu@aftergroupcleanup{%
+ \def\tabu@aftergroupcleanup{\aftergroup\tabu@cleanup}}%
+ \else
+ \def\tabu@aftergroupcleanup{%
+ \aftergroup\aftergroup\aftergroup\tabu@cleanup
+ \let\tabu@aftergroupcleanup \relax}%
+ \fi
+ \let\tabu@arc@Gsave \tabu@arc@G
+ \let\tabu@arc@G \tabu@arc@L % <init>
+ \let\tabu@drsc@Gsave \tabu@drsc@G
+ \let\tabu@drsc@G \tabu@drsc@L % <init>
+ \let\tabu@ls@Gsave \tabu@ls@G
+ \let\tabu@ls@G \tabu@ls@L % <init>
+ \let\tabu@rc@Gsave \tabu@rc@G
+ \let\tabu@rc@G \tabu@rc@L % <init>
+ \let\tabu@evr@Gsave \tabu@evr@G
+ \let\tabu@evr@G \tabu@evr@L % <init>
+ \let\tabu@celllalign@save \tabu@celllalign
+ \let\tabu@cellralign@save \tabu@cellralign
+ \let\tabu@cellleft@save \tabu@cellleft
+ \let\tabu@cellright@save \tabu@cellright
+ \let\tabu@@celllalign@save \tabu@@celllalign
+ \let\tabu@@cellralign@save \tabu@@cellralign
+ \let\tabu@@cellleft@save \tabu@@cellleft
+ \let\tabu@@cellright@save \tabu@@cellright
+ \let\tabu@rowfontreset@save \tabu@rowfontreset
+ \let\tabu@@rowfontreset@save\tabu@@rowfontreset
+ \let\tabu@rowfontreset \@empty
+ \edef\tabu@alloc@save {\the\tabu@alloc}% restore at \tabu@reset
+ \edef\c@taburow@save {\the\c@taburow}%
+ \edef\tabu@naturalX@save {\the\tabu@naturalX}%
+ \let\tabu@naturalXmin@save \tabu@naturalXmin
+ \let\tabu@naturalXmax@save \tabu@naturalXmax
+ \let\tabu@mkarstrut@save \tabu@mkarstrut
+ \edef\tabu@clarstrut{%
+ \extrarowheight \the\dimexpr \ht\@arstrutbox-\ht\strutbox \relax
+ \extrarowdepth \the\dimexpr \dp\@arstrutbox-\dp\strutbox \relax
+ \let\noexpand\@arraystretch \@ne \noexpand\tabu@rearstrut}%
+}% \tabu@setcleanup
+\def\tabu@cleanup {\begingroup
+ \globaldefs\@ne \tabu@everyrowtrue
+ \let\tabu@arc@G \tabu@arc@Gsave
+ \let\CT@arc@ \tabu@arc@G
+ \let\tabu@drsc@G \tabu@drsc@Gsave
+ \let\CT@drsc@ \tabu@drsc@G
+ \let\tabu@ls@G \tabu@ls@Gsave
+ \let\tabu@ls@ \tabu@ls@G
+ \let\tabu@rc@G \tabu@rc@Gsave
+ \let\tabu@rc@ \tabu@rc@G
+ \let\CT@do@color \relax
+ \let\tabu@evr@G \tabu@evr@Gsave
+ \let\tabu@celllalign \tabu@celllalign@save
+ \let\tabu@cellralign \tabu@cellralign@save
+ \let\tabu@cellleft \tabu@cellleft@save
+ \let\tabu@cellright \tabu@cellright@save
+ \let\tabu@@celllalign \tabu@@celllalign@save
+ \let\tabu@@cellralign \tabu@@cellralign@save
+ \let\tabu@@cellleft \tabu@@cellleft@save
+ \let\tabu@@cellright \tabu@@cellright@save
+ \let\tabu@rowfontreset \tabu@rowfontreset@save
+ \let\tabu@@rowfontreset \tabu@@rowfontreset@save
+ \tabu@naturalX =\tabu@naturalX@save
+ \let\tabu@naturalXmax \tabu@naturalXmax@save
+ \let\tabu@naturalXmin \tabu@naturalXmin@save
+ \let\tabu@mkarstrut \tabu@mkarstrut@save
+ \c@taburow =\c@taburow@save
+ \ifcase \tabu@nested \tabu@alloc \m@ne\fi
+ \endgroup % <end of \globaldefs>
+ \ifcase \tabu@nested
+ \the\tabu@footnotes \global\tabu@footnotes{}%
+ \tabu@afterendpar \tabu@elapsedtime
+ \fi
+ \tabu@clarstrut
+ \everyrow\expandafter {\tabu@evr@G}%
+}% \tabu@cleanup
+\let\tabu@afterendpar \relax
+\def\tabu@setreset {%
+ \edef\tabu@savedparams {% \relax for \tabu@message@save
+ \ifmmode \col@sep \the\arraycolsep
+ \else \col@sep \the\tabcolsep \fi \relax
+ \arrayrulewidth \the\arrayrulewidth \relax
+ \doublerulesep \the\doublerulesep \relax
+ \extratabsurround \the\extratabsurround \relax
+ \extrarowheight \the\extrarowheight \relax
+ \extrarowdepth \the\extrarowdepth \relax
+ \abovetabulinesep \the\abovetabulinesep \relax
+ \belowtabulinesep \the\belowtabulinesep \relax
+ \def\noexpand\arraystretch{\arraystretch}%
+ \ifdefined\minrowclearance \minrowclearance\the\minrowclearance\relax\fi}%
+ \begingroup
+ \@temptokena\expandafter{\tabu@savedparams}% => only for \savetabu / \usetabu
+ \ifx \tabu@arc@L\relax \else \tabu@setsave \tabu@arc@L \fi
+ \ifx \tabu@drsc@L\relax \else \tabu@setsave \tabu@drsc@L \fi
+ \tabu@setsave \tabu@ls@L \tabu@setsave \tabu@evr@L
+ \expandafter \endgroup \expandafter
+ \def\expandafter\tabu@saved@ \expandafter{\the\@temptokena
+ \let\tabu@arc@G \tabu@arc@L
+ \let\tabu@drsc@G \tabu@drsc@L
+ \let\tabu@ls@G \tabu@ls@L
+ \let\tabu@rc@G \tabu@rc@L
+ \let\tabu@evr@G \tabu@evr@L}%
+ \def\tabu@reset{\tabu@savedparams
+ \tabu@everyrowtrue \c@taburow \z@
+ \let\CT@arc@ \tabu@arc@L
+ \let\CT@drsc@ \tabu@drsc@L
+ \let\tabu@ls@ \tabu@ls@L
+ \let\tabu@rc@ \tabu@rc@L
+ \global\tabu@alloc \tabu@alloc@save
+ \everyrow\expandafter{\tabu@evr@L}}%
+}% \tabu@reset
+\def\tabu@setsave #1{\expandafter\tabu@sets@ve #1\@nil{#1}}
+\long\def\tabu@sets@ve #1\@nil #2{\@temptokena\expandafter{\the\@temptokena \def#2{#1}}}
+%% The Rewritting Process -------------------------------------------
+\def\tabu@newcolumntype #1{%
+ \expandafter\tabu@new@columntype
+ \csname NC@find@\string#1\expandafter\endcsname
+ \csname NC@rewrite@\string#1\endcsname
+ {#1}%
+}% \tabu@newcolumntype
+\def\tabu@new@columntype #1#2#3{%
+ \def#1##1#3{\NC@{##1}}%
+ \let#2\relax \newcommand*#2%
+}% \tabu@new@columntype
+\def\tabu@privatecolumntype #1{%
+ \expandafter\tabu@private@columntype
+ \csname NC@find@\string#1\expandafter\endcsname
+ \csname NC@rewrite@\string#1\expandafter\endcsname
+ \csname tabu@NC@find@\string#1\expandafter\endcsname
+ \csname tabu@NC@rewrite@\string#1\endcsname
+ {#1}%
+}% \tabu@privatecolumntype
+\def\tabu@private@columntype#1#2#3#4{%
+ \g@addto@macro\tabu@privatecolumns{\let#1#3\let#2#4}%
+ \tabu@new@columntype#3#4%
+}% \tabu@private@columntype
+\let\tabu@privatecolumns \@empty
+\newcommand*\tabucolumn [1]{\expandafter \def \expandafter
+ \tabu@highprioritycolumns\expandafter{\tabu@highprioritycolumns
+ \NC@do #1}}%
+\let\tabu@highprioritycolumns \@empty
+%% The | ``column'' : rewriting process --------------------------
+\tabu@privatecolumntype |{\tabu@rewritevline}
+\newcommand*\tabu@rewritevline[1][]{\tabu@vlinearg{#1}%
+ \expandafter \NC@find \tabu@rewritten}
+\def\tabu@lines #1{%
+ \ifx|#1\else \tabu@privatecolumntype #1{\tabu@rewritevline}\fi
+ \NC@list\expandafter{\the\NC@list \NC@do #1}%
+}% \tabu@lines@
+\def\tabu@vlinearg #1{%
+ \ifx\\#1\\\def\tabu@thestyle {\tabu@ls@}%
+ \else\tabu@getline {#1}%
+ \fi
+ \def\tabu@rewritten ##1{\def\tabu@rewritten{!{##1\tabu@thevline}}%
+ }\expandafter\tabu@rewritten\expandafter{\tabu@thestyle}%
+ \expandafter \tabu@keepls \tabu@thestyle \@nil
+}% \tabu@vlinearg
+\def\tabu@keepls #1\@nil{%
+ \ifcat $\@cdr #1\@nil $%
+ \ifx \relax#1\else
+ \ifx \tabu@ls@#1\else
+ \let#1\relax
+ \xdef\tabu@mkpreambuffer{\tabu@mkpreambuffer
+ \tabu@savels\noexpand#1}\fi\fi\fi
+}% \tabu@keepls
+\def\tabu@thevline {\begingroup
+ \ifdefined\tabu@leaders
+ \setbox\@tempboxa=\vtop to\dimexpr
+ \ht\@arstrutbox+\dp\@arstrutbox{{\tabu@thevleaders}}%
+ \ht\@tempboxa=\ht\@arstrutbox \dp\@tempboxa=\dp\@arstrutbox
+ \box\@tempboxa
+ \else
+ \tabu@thevrule
+ \fi \endgroup
+}% \tabu@thevline
+\def\tabu@savels #1{%
+ \expandafter\let\csname\string#1\endcsname #1%
+ \expandafter\def\expandafter\tabu@reset\expandafter{\tabu@reset
+ \tabu@resetls#1}}%
+\def\tabu@resetls #1{\expandafter\let\expandafter#1\csname\string#1\endcsname}%
+%% \multicolumn inside tabu environment -----------------------------
+\tabu@newcolumntype \tabu@rewritemulticolumn{%
+ \aftergroup \tabu@endrewritemulticolumn % after \@mkpream group
+ \NC@list{\NC@do *}\tabu@textbar \tabu@lines
+ \tabu@savedecl
+ \tabu@privatecolumns
+ \NC@list\expandafter{\the\expandafter\NC@list \tabu@NC@list}%
+ \let\tabu@savels \relax
+ \NC@find
+}% \tabu@rewritemulticolumn
+\def\tabu@endrewritemulticolumn{\gdef\tabu@mkpreambuffer{}\endgroup}
+\def\tabu@multicolumn{\tabu@ifenvir \tabu@multic@lumn \tabu@multicolumnORI}
+\long\def\tabu@multic@lumn #1#2#3{\multispan{#1}\begingroup
+ \tabu@everyrowtrue
+ \NC@list{\NC@do \tabu@rewritemulticolumn}%
+ \expandafter\@gobbletwo % gobbles \multispan{#1}
+ \tabu@multicolumnORI{#1}{\tabu@rewritemulticolumn #2}%
+ {\iftabuscantokens \tabu@rescan \else \expandafter\@firstofone \fi
+ {#3}}%
+}% \tabu@multic@lumn
+%% The X column(s): rewriting process -----------------------------
+\tabu@privatecolumntype X[1][]{\begingroup \tabu@siunitx{\endgroup \tabu@rewriteX {#1}}}
+\def\tabu@nosiunitx #1{#1{}{}\expandafter \NC@find \tabu@rewritten }
+\def\tabu@siunitx #1{\@ifnextchar \bgroup
+ {\tabu@rewriteX@Ss{#1}}
+ {\tabu@nosiunitx{#1}}}
+\def\tabu@rewriteX@Ss #1#2{\@temptokena{}%
+ \@defaultunits \let\tabu@temp =#2\relax\@nnil
+ \ifodd 1\ifx S\tabu@temp \else \ifx s\tabu@temp \else 0 \fi\fi
+ \def\NC@find{\def\NC@find >####1####2<####3\relax{#1 {####1}{####3}%
+ }\expandafter\NC@find \the\@temptokena \relax
+ }\expandafter\NC@rewrite@S \@gobble #2\relax
+ \else \tabu@siunitxerror
+ \fi
+ \expandafter \NC@find \tabu@rewritten
+}% \tabu@rewriteX@Ss
+\def\tabu@siunitxerror {\PackageError{tabu}{Not a S nor s column !
+ \MessageBreak X column can only embed siunitx S or s columns}\@ehd
+}% \tabu@siunitxerror
+\def\tabu@rewriteX #1#2#3{\tabu@Xarg {#1}{#2}{#3}%
+ \iftabu@measuring
+ \else \tabu@measuringtrue % first X column found in the preamble
+ \let\@halignto \relax \let\tabu@halignto \relax
+ \iftabu@spread \tabu@spreadtarget \tabu@target \tabu@target \z@
+ \else \tabu@spreadtarget \z@ \fi
+ \ifdim \tabu@target=\z@
+ \setlength\tabu@target \tabu@thetarget
+ \tabu@message{\tabu@message@defaulttarget}%
+ \else \tabu@message{\tabu@message@target}\fi
+ \fi
+}% \tabu@rewriteX
+\def\tabu@rewriteXrestore #1#2#3{\let\@halignto \relax
+ \def\tabu@rewritten{l}}
+\def\tabu@Xarg #1#2#3{%
+ \advance\tabu@Xcol \@ne \let\tabu@Xlcr \@empty
+ \let\tabu@Xdisp \@empty \let\tabu@Xmath \@empty
+ \ifx\\#1\\% <shortcut when no option>
+ \def\tabu@rewritten{p}\tabucolX \p@ % <default coef = 1>
+ \else
+ \let\tabu@rewritten \@empty \let\tabu@temp \@empty \tabucolX \z@
+ \tabu@Xparse {}#1\relax
+ \fi
+ \tabu@Xrewritten{#2}{#3}%
+}% \tabu@Xarg
+\def\tabu@Xparse #1{\futurelet\@let@token \tabu@Xtest}
+\expandafter\def\expandafter\tabu@Xparsespace\space{\tabu@Xparse{}}
+\def\tabu@Xtest{%
+ \ifcase \ifx \relax\@let@token \z@ \else
+ \if ,\@let@token \m@ne\else
+ \if p\@let@token 1\else
+ \if m\@let@token 2\else
+ \if b\@let@token 3\else
+ \if l\@let@token 4\else
+ \if c\@let@token 5\else
+ \if r\@let@token 6\else
+ \if j\@let@token 7\else
+ \if L\@let@token 8\else
+ \if C\@let@token 9\else
+ \if R\@let@token 10\else
+ \if J\@let@token 11\else
+ \ifx \@sptoken\@let@token 12\else
+ \if .\@let@token 13\else
+ \if -\@let@token 13\else
+ \ifcat $\@let@token 14\else
+ 15\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\relax
+ \or \tabu@Xtype {p}%
+ \or \tabu@Xtype {m}%
+ \or \tabu@Xtype {b}%
+ \or \tabu@Xalign \raggedright\relax
+ \or \tabu@Xalign \centering\relax
+ \or \tabu@Xalign \raggedleft\relax
+ \or \tabu@Xalign \tabu@justify\relax
+ \or \tabu@Xalign \RaggedRight\raggedright
+ \or \tabu@Xalign \Centering\centering
+ \or \tabu@Xalign \RaggedLeft\raggedleft
+ \or \tabu@Xalign \justifying\tabu@justify
+ \or \expandafter \tabu@Xparsespace
+ \or \expandafter \tabu@Xcoef
+ \or \expandafter \tabu@Xm@th
+ \or \tabu@Xcoef{}%
+ \else\expandafter \tabu@Xparse
+ \fi
+}% \tabu@Xtest
+\def\tabu@Xalign #1#2{%
+ \ifx \tabu@Xlcr\@empty \else \PackageWarning{tabu}
+ {Duplicate horizontal alignment specification}\fi
+ \ifdefined#1\def\tabu@Xlcr{#1}\let#1\relax
+ \else \def\tabu@Xlcr{#2}\let#2\relax\fi
+ \expandafter\tabu@Xparse
+}% \tabu@Xalign
+\def\tabu@Xtype #1{%
+ \ifx \tabu@rewritten\@empty \else \PackageWarning{tabu}
+ {Duplicate vertical alignment specification}\fi
+ \def\tabu@rewritten{#1}\expandafter\tabu@Xparse
+}% \tabu@Xtype
+\def\tabu@Xcoef#1{\edef\tabu@temp{\tabu@temp#1}%
+ \afterassignment\tabu@Xc@ef \tabu@cnt\number\if-#10\fi
+}% \tabu@Xcoef
+\def\tabu@Xc@ef{\advance\tabucolX \tabu@temp\the\tabu@cnt\p@
+ \tabu@Xparse{}%
+}% \tabu@Xc@ef
+\def\tabu@Xm@th #1{\futurelet \@let@token \tabu@Xd@sp}
+\def\tabu@Xd@sp{\let\tabu@Xmath=$%
+ \ifx $\@let@token \def\tabu@Xdisp{\displaystyle}%
+ \expandafter\tabu@Xparse
+ \else \expandafter\tabu@Xparse\expandafter{\expandafter}%
+ \fi
+}% \tabu@Xd@sp
+\def\tabu@Xrewritten {%
+ \ifx \tabu@rewritten\@empty \def\tabu@rewritten{p}\fi
+ \ifdim \tabucolX<\z@ \tabu@negcoeftrue
+ \else\ifdim \tabucolX=\z@ \tabucolX \p@
+ \fi\fi
+ \edef\tabu@temp{{\the\tabu@Xcol}{\tabu@strippt\tabucolX}}%
+ \edef\tabu@Xcoefs{\tabu@Xcoefs \tabu@ \tabu@temp}%
+ \edef\tabu@rewritten ##1##2{\def\noexpand\tabu@rewritten{%
+ >{\tabu@Xlcr \ifx$\tabu@Xmath$\tabu@Xdisp\fi ##1}%
+ \tabu@rewritten {\tabu@hsize \tabu@temp}%
+ <{##2\ifx$\tabu@Xmath$\fi}}%
+ }\tabu@rewritten
+}% \tabu@Xrewritten
+\def\tabu@hsize #1#2{%
+ \ifdim #2\p@<\z@
+ \ifdim \tabucolX=\maxdimen \tabu@wd{#1}\else
+ \ifdim \tabu@wd{#1}<-#2\tabucolX \tabu@wd{#1}\else -#2\tabucolX\fi
+ \fi
+ \else #2\tabucolX
+ \fi
+}% \tabu@hsize
+%% \usetabu and \preamble: rewritting process ---------------------
+\tabu@privatecolumntype \usetabu [1]{%
+ \ifx\\#1\\\tabu@saveerr{}\else
+ \@ifundefined{tabu@saved@\string#1}
+ {\tabu@saveerr{#1}}
+ {\let\tabu@rewriteX \tabu@rewriteXrestore
+ \csname tabu@saved@\string#1\expandafter\endcsname\expandafter\@ne}%
+ \fi
+}% \NC@rewrite@\usetabu
+\tabu@privatecolumntype \preamble [1]{%
+ \ifx\\#1\\\tabu@saveerr{}\else
+ \@ifundefined{tabu@saved@\string#1}
+ {\tabu@saveerr{#1}}
+ {\csname tabu@saved@\string#1\expandafter\endcsname\expandafter\z@}%
+ \fi
+}% \NC@rewrite@\preamble
+%% Controlling the rewritting process -------------------------------
+\tabu@newcolumntype \tabu@rewritefirst{%
+ \iftabu@long \aftergroup \tabu@longpream % <the whole implementation is here !>
+ \else \aftergroup \tabu@pream
+ \fi
+ \let\tabu@ \relax \let\tabu@hsize \relax
+ \let\tabu@Xcoefs \@empty \let\tabu@savels \relax
+ \tabu@Xcol \z@ \tabu@cnt \tw@
+ \gdef\tabu@mkpreambuffer{\tabu@{}}\tabu@measuringfalse
+ \global\setbox\@arstrutbox \box\@arstrutbox
+ \NC@list{\NC@do *}\tabu@textbar \tabu@lines
+ \NC@list\expandafter{\the\NC@list \NC@do X}%
+ \iftabu@siunitx % <siunitx S and s columns>
+ \NC@list\expandafter{\the\NC@list \NC@do S\NC@do s}\fi
+ \NC@list\expandafter{\the\expandafter\NC@list \tabu@highprioritycolumns}%
+ \expandafter\def\expandafter\tabu@NC@list\expandafter{%
+ \the\expandafter\NC@list \tabu@NC@list}% % * | X S <original>
+ \NC@list\expandafter{\expandafter \NC@do \expandafter\usetabu
+ \expandafter \NC@do \expandafter\preamble
+ \the\NC@list \NC@do \tabu@rewritemiddle
+ \NC@do \tabu@rewritelast}%
+ \tabu@savedecl
+ \tabu@privatecolumns
+ \edef\tabu@prev{\the\@temptokena}\NC@find \tabu@rewritemiddle
+}% NC@rewrite@\tabu@rewritefirst
+\tabu@newcolumntype \tabu@rewritemiddle{%
+ \edef\tabu@temp{\the\@temptokena}\NC@find \tabu@rewritelast
+}% \NC@rewrite@\tabu@rewritemiddle
+\tabu@newcolumntype \tabu@rewritelast{%
+ \ifx \tabu@temp\tabu@prev \advance\tabu@cnt \m@ne
+ \NC@list\expandafter{\tabu@NC@list \NC@do \tabu@rewritemiddle
+ \NC@do \tabu@rewritelast}%
+ \else \let\tabu@prev\tabu@temp
+ \fi
+ \ifcase \tabu@cnt \expandafter\tabu@endrewrite
+ \else \expandafter\NC@find \expandafter\tabu@rewritemiddle
+ \fi
+}% \NC@rewrite@\tabu@rewritelast
+%% Choosing the strategy --------------------------------------------
+\def\tabu@endrewrite {%
+ \let\tabu@temp \NC@find
+ \ifx \@arrayright\relax \let\@arrayright \@empty \fi
+ \count@=%
+ \ifx \@finalstrut\tabu@finalstrut \z@ % outer in mode 0 print
+ \iftabu@measuring
+ \xdef\tabu@mkpreambuffer{\tabu@mkpreambuffer
+ \tabu@target \csname tabu@\the\tabu@nested.T\endcsname
+ \tabucolX \csname tabu@\the\tabu@nested.X\endcsname
+ \edef\@halignto {\ifx\@arrayright\@empty to\tabu@target\fi}}%
+ \fi
+ \else\iftabu@measuring 4 % X columns
+ \xdef\tabu@mkpreambuffer{\tabu@{\tabu@mkpreambuffer
+ \tabu@target \the\tabu@target
+ \tabu@spreadtarget \the\tabu@spreadtarget}%
+ \def\noexpand\tabu@Xcoefs{\tabu@Xcoefs}%
+ \edef\tabu@halignto{\ifx \@arrayright\@empty to\tabu@target\fi}}%
+ \let\tabu@Xcoefs \relax
+ \else\ifcase\tabu@nested \thr@@ % outer, no X
+ \global\let\tabu@afterendpar \relax
+ \else \@ne % inner, no X, outer in mode 1 or 2
+ \fi
+ \ifdefined\tabu@usetabu
+ \else \ifdim\tabu@target=\z@
+ \else \let\tabu@temp \tabu@extracolsep
+ \fi\fi
+ \fi
+ \fi
+ \xdef\tabu@mkpreambuffer{\count@ \the\count@ \tabu@mkpreambuffer}%
+ \tabu@temp
+}% \tabu@endrewrite
+\def\tabu@extracolsep{\@defaultunits \expandafter\let
+ \expandafter\tabu@temp \expandafter=\the\@temptokena \relax\@nnil
+ \ifx \tabu@temp\@sptoken
+ \expandafter\tabu@gobblespace \expandafter\tabu@extracolsep
+ \else
+ \edef\tabu@temp{\noexpand\NC@find
+ \if |\noexpand\tabu@temp @%
+ \else\if !\noexpand\tabu@temp @%
+ \else !%
+ \fi\fi
+ {\noexpand\extracolsep\noexpand\@flushglue}}%
+ \fi
+ \tabu@temp
+}% \tabu@extrac@lsep
+%% Implementing the strategy ----------------------------------------
+\long\def\tabu@pream #1\@preamble {%
+ \let\tabu@ \tabu@@ \tabu@mkpreambuffer \tabu@aftergroupcleanup
+ \NC@list\expandafter {\tabu@NC@list}% in case of nesting...
+ \ifdefined\tabu@usetabu \tabu@usetabu \tabu@target \z@ \fi
+ \let\tabu@savedpreamble \@preamble
+ \global\let\tabu@elapsedtime \relax
+ \tabu@thebody ={#1\tabu@aftergroupcleanup}%
+ \tabu@thebody =\expandafter{\the\expandafter\tabu@thebody
+ \@preamble}%
+ \edef\tabuthepreamble {\the\tabu@thebody}% ( no @ allowed for \scantokens )
+ \tabu@select
+}% \tabu@pream
+\long\def\tabu@longpream #1\LT@bchunk #2\LT@bchunk{%
+ \let\tabu@ \tabu@@ \tabu@mkpreambuffer \tabu@aftergroupcleanup
+ \NC@list\expandafter {\tabu@NC@list}% in case of nesting...
+ \let\tabu@savedpreamble \@preamble
+ \global\let\tabu@elapsedtime \relax
+ \tabu@thebody ={#1\LT@bchunk #2\tabu@aftergroupcleanup \LT@bchunk}%
+ \edef\tabuthepreamble {\the\tabu@thebody}% ( no @ allowed for \scantokens )
+ \tabu@select
+}% \tabu@longpream
+\def\tabu@select {%
+ \ifnum\tabu@nested>\z@ \tabuscantokensfalse \fi
+ \ifnum \count@=\@ne \iftabu@measuring \count@=\tw@ \fi\fi
+ \ifcase \count@
+ \global\let\tabu@elapsedtime \relax
+ \tabu@seteverycr
+ \expandafter \tabuthepreamble % vertical adjustment (inheritated from outer)
+ \or % exit in vertical measure + struts per cell because no X and outer in mode 3
+ \tabu@evr{\tabu@verticalinit}\tabu@celllalign@def{\tabu@verticalmeasure}%
+ \def\tabu@cellralign{\tabu@verticalspacing}%
+ \tabu@seteverycr
+ \expandafter \tabuthepreamble
+ \or % exit without measure because no X and outer in mode 4
+ \tabu@evr{}\tabu@celllalign@def{}\let\tabu@cellralign \@empty
+ \tabu@seteverycr
+ \expandafter \tabuthepreamble
+ \else % needs trials
+ \tabu@evr{}\tabu@celllalign@def{}\let\tabu@cellralign \@empty
+ \tabu@savecounters
+ \expandafter \tabu@setstrategy
+ \fi
+}% \tabu@select
+\def\tabu@@ {\gdef\tabu@mkpreambuffer}
+%% Protections to set up before trials ------------------------------
+\def\tabu@setstrategy {\begingroup % <trials group>
+ \tabu@trialh@@k \tabu@cnt \z@ % number of trials
+ \hbadness \@M \let\hbadness \@tempcnta
+ \hfuzz \maxdimen \let\hfuzz \@tempdima
+ \let\write \tabu@nowrite\let\GenericError \tabu@GenericError
+ \let\savetabu \@gobble \let\tabudefaulttarget \linewidth
+ \let\@footnotetext \@gobble \let\@xfootnote \tabu@xfootnote
+ \let\color \tabu@nocolor\let\rowcolor \tabu@norowcolor
+ \let\tabu@aftergroupcleanup \relax % only after the last trial
+ \tabu@mkpreambuffer
+ \ifnum \count@>\thr@@ \let\@halignto \@empty \tabucolX@init
+ \def\tabu@lasttry{\m@ne\p@}\fi
+ \begingroup \iffalse{\fi \ifnum0=`}\fi
+ \toks@{}\def\tabu@stack{b}\iftabuscantokens \endlinechar=10 \obeyspaces \fi %
+ \tabu@collectbody \tabu@strategy %
+}% \tabu@setstrategy
+\def\tabu@savecounters{%
+ \def\@elt ##1{\csname c@##1\endcsname\the\csname c@##1\endcsname}%
+ \edef\tabu@clckpt {\begingroup \globaldefs=\@ne \cl@@ckpt \endgroup}\let\@elt \relax
+}% \tabu@savecounters
+\def\tabucolX@init {% \tabucolX <= \tabu@target / (sum coefs > 0)
+ \dimen@ \z@ \tabu@Xsum \z@ \tabucolX \z@ \let\tabu@ \tabu@Xinit \tabu@Xcoefs
+ \ifdim \dimen@>\z@
+ \@tempdima \dimexpr \tabu@target *\p@/\dimen@ + \tabu@hfuzz\relax
+ \ifdim \tabucolX<\@tempdima \tabucolX \@tempdima \fi
+ \fi
+}% \tabucolX@init
+\def\tabu@Xinit #1#2{\tabu@Xcol #1 \advance \tabu@Xsum
+ \ifdim #2\p@>\z@ #2\p@ \advance\dimen@ #2\p@
+ \else -#2\p@ \tabu@negcoeftrue
+ \@tempdima \dimexpr \tabu@target*\p@/\dimexpr-#2\p@\relax \relax
+ \ifdim \tabucolX<\@tempdima \tabucolX \@tempdima \fi
+ \tabu@wddef{#1}{0pt}%
+ \fi
+}% \tabu@Xinit
+%% Collecting the environment body ----------------------------------
+\long\def\tabu@collectbody #1#2\end #3{%
+ \edef\tabu@stack{\tabu@pushbegins #2\begin\end\expandafter\@gobble\tabu@stack}%
+ \ifx \tabu@stack\@empty
+ \toks@\expandafter{\expandafter\tabu@thebody\expandafter{\the\toks@ #2}%
+ \def\tabu@end@envir{\end{#3}}%
+ \iftabuscantokens
+ \iftabu@long \def\tabu@endenvir {\end{#3}\tabu@gobbleX}%
+ \else \def\tabu@endenvir {\let\endarray \@empty
+ \end{#3}\tabu@gobbleX}%
+ \fi
+ \else \def\tabu@endenvir {\end{#3}}\fi}%
+ \let\tabu@collectbody \tabu@endofcollect
+ \else\def\tabu@temp{#3}%
+ \ifx \tabu@temp\@empty \toks@\expandafter{\the\toks@ #2\end }%
+ \else \ifx\tabu@temp\tabu@@spxiii \toks@\expandafter{\the\toks@ #2\end #3}%
+ \else \ifx\tabu@temp\tabu@X \toks@\expandafter{\the\toks@ #2\end #3}%
+ \else \toks@\expandafter{\the\toks@ #2\end{#3}}%
+ \fi\fi\fi
+ \fi
+ \tabu@collectbody{#1}%
+}% \tabu@collectbody
+\long\def\tabu@pushbegins#1\begin#2{\ifx\end#2\else b\expandafter\tabu@pushbegins\fi}%
+\def\tabu@endofcollect #1{\ifnum0=`{}\fi
+ \expandafter\endgroup \the\toks@ #1%
+}% \tabu@endofcollect
+%% The trials: switching between strategies -------------------------
+\def\tabu@strategy {\relax % stops \count@ assignment !
+ \ifcase\count@ % case 0 = print with vertical adjustment (outer is finished)
+ \expandafter \tabu@endoftrials
+ \or % case 1 = exit in vertical measure (outer in mode 3)
+ \expandafter\xdef\csname tabu@\the\tabu@nested.T\endcsname{\the\tabu@target}%
+ \expandafter\xdef\csname tabu@\the\tabu@nested.X\endcsname{\the\tabucolX}%
+ \expandafter \tabu@endoftrials
+ \or % case 2 = exit with a rule replacing the table (outer in mode 4)
+ \expandafter \tabu@quickend
+ \or % case 3 = outer is in mode 3 because of no X
+ \begingroup
+ \tabu@evr{\tabu@verticalinit}\tabu@celllalign@def{\tabu@verticalmeasure}%
+ \def\tabu@cellralign{\tabu@verticalspacing}%
+ \expandafter \tabu@measuring
+ \else % case 4 = horizontal measure
+ \begingroup
+ \global\let\tabu@elapsedtime \tabu@message@etime
+ \long\def\multicolumn##1##2##3{\multispan{##1}}%
+ \let\tabu@startpboxORI \@startpbox
+ \iftabu@spread
+ \def\tabu@naturalXmax {\z@}%
+ \let\tabu@naturalXmin \tabu@naturalXmax
+ \tabu@evr{\global\tabu@naturalX \z@}%
+ \let\@startpbox \tabu@startpboxmeasure
+ \else\iftabu@negcoef
+ \let\@startpbox \tabu@startpboxmeasure
+ \else \let\@startpbox \tabu@startpboxquick
+ \fi\fi
+ \expandafter \tabu@measuring
+ \fi
+}% \tabu@strategy
+\def\tabu@measuring{\expandafter \tabu@trial \expandafter
+ \count@ \the\count@ \tabu@endtrial
+}% \tabu@measuring
+\def\tabu@trial{\iftabu@long \tabu@longtrial \else \tabu@shorttrial \fi}
+\def\tabu@shorttrial {\setbox\tabu@box \hbox\bgroup \tabu@seteverycr
+ \ifx \tabu@savecounters\relax \else
+ \let\tabu@savecounters \relax \tabu@clckpt \fi
+ $\iftabuscantokens \tabu@rescan \else \expandafter\@secondoftwo \fi
+ \expandafter{\expandafter \tabuthepreamble
+ \the\tabu@thebody
+ \csname tabu@adl@endtrial\endcsname
+ \endarray}$\egroup % got \tabu@box
+}% \tabu@shorttrial
+\def\tabu@longtrial {\setbox\tabu@box \hbox\bgroup \tabu@seteverycr
+ \ifx \tabu@savecounters\relax \else
+ \let\tabu@savecounters \relax \tabu@clckpt \fi
+ \iftabuscantokens \tabu@rescan \else \expandafter\@secondoftwo \fi
+ \expandafter{\expandafter \tabuthepreamble
+ \the\tabu@thebody
+ \tabuendlongtrial}\egroup % got \tabu@box
+}% \tabu@longtrial
+\def\tabuendlongtrial{% no @ allowed for \scantokens
+ \LT@echunk \global\setbox\@ne \hbox{\unhbox\@ne}\kern\wd\@ne
+ \LT@get@widths
+}% \tabuendlongtrial
+\def\tabu@adl@endtrial{% <arydshln in nested trials - problem for global column counters!>
+ \crcr \noalign{\global\adl@ncol \tabu@nbcols}}% anything global is crap, junky and fails !
+\def\tabu@seteverycr {\tabu@reset
+ \everycr \expandafter{\the\everycr \tabu@everycr}%
+ \let\everycr \tabu@noeverycr % <for ialign>
+}% \tabu@seteverycr
+\def\tabu@noeverycr{{\aftergroup\tabu@restoreeverycr \afterassignment}\toks@}
+\def\tabu@restoreeverycr {\let\everycr \tabu@@everycr}
+\def\tabu@everycr {\iftabu@everyrow \noalign{\tabu@everyrow}\fi}
+\def\tabu@endoftrials {%
+ \iftabuscantokens \expandafter\@firstoftwo
+ \else \expandafter\@secondoftwo
+ \fi
+ {\expandafter \tabu@closetrialsgroup \expandafter
+ \tabu@rescan \expandafter{%
+ \expandafter\tabuthepreamble
+ \the\expandafter\tabu@thebody
+ \iftabu@long \else \endarray \fi}}
+ {\expandafter\tabu@closetrialsgroup \expandafter
+ \tabuthepreamble
+ \the\tabu@thebody}%
+ \tabu@endenvir % Finish !
+}% \tabu@endoftrials
+\def\tabu@closetrialsgroup {%
+ \toks@\expandafter{\tabu@endenvir}%
+ \edef\tabu@bufferX{\endgroup
+ \tabucolX \the\tabucolX
+ \tabu@target \the\tabu@target
+ \tabu@cnt \the\tabu@cnt
+ \def\noexpand\tabu@endenvir{\the\toks@}%
+ %Quid de \@halignto = \tabu@halignto ??
+ }% \tabu@bufferX
+ \tabu@bufferX
+ \ifcase\tabu@nested % print out (outer in mode 0)
+ \global\tabu@cnt \tabu@cnt
+ \tabu@evr{\tabu@verticaldynamicadjustment}%
+ \tabu@celllalign@def{\everypar{}}\let\tabu@cellralign \@empty
+ \let\@finalstrut \tabu@finalstrut
+ \else % vertical measure of nested tabu
+ \tabu@evr{\tabu@verticalinit}%
+ \tabu@celllalign@def{\tabu@verticalmeasure}%
+ \def\tabu@cellralign{\tabu@verticalspacing}%
+ \fi
+ \tabu@clckpt \let\@halignto \tabu@halignto
+ \let\@halignto \@empty
+ \tabu@seteverycr
+ \ifdim \tabustrutrule>\z@ \ifnum\tabu@nested=\z@
+ \setbox\@arstrutbox \box\voidb@x % force \@arstrutbox to be rebuilt (visible struts)
+ \fi\fi
+}% \tabu@closetrialsgroup
+\def\tabu@quickend {\expandafter \endgroup \expandafter
+ \tabu@target \the\tabu@target \tabu@quickrule
+ \let\endarray \relax \tabu@endenvir
+}% \tabu@quickend
+\def\tabu@endtrial {\relax % stops \count@ assignment !
+ \ifcase \count@ \tabu@err % case 0 = impossible here
+ \or \tabu@err % case 1 = impossible here
+ \or \tabu@err % case 2 = impossible here
+ \or % case 3 = outer goes into mode 0
+ \def\tabu@bufferX{\endgroup}\count@ \z@
+ \else % case 4 = outer goes into mode 3
+ \iftabu@spread \tabu@spreadarith % inner into mode 1 (outer in mode 3)
+ \else \tabu@arith % or 2 (outer in mode 4)
+ \fi
+ \count@=%
+ \ifcase\tabu@nested \thr@@ % outer goes into mode 3
+ \else\iftabu@measuring \tw@ % outer is in mode 4
+ \else \@ne % outer is in mode 3
+ \fi\fi
+ \edef\tabu@bufferX{\endgroup
+ \tabucolX \the\tabucolX
+ \tabu@target \the\tabu@target}%
+ \fi
+ \expandafter \tabu@bufferX \expandafter
+ \count@ \the\count@ \tabu@strategy
+}% \tabu@endtrial
+\def\tabu@err{\errmessage{(tabu) Internal impossible error! (\count@=\the\count@)}}
+%% The algorithms: compute the widths / stop or go on ---------------
+\def\tabu@arithnegcoef {%
+ \@tempdima \z@ \dimen@ \z@ \let\tabu@ \tabu@arith@negcoef \tabu@Xcoefs
+}% \tabu@arithnegcoef
+\def\tabu@arith@negcoef #1#2{%
+ \ifdim #2\p@>\z@ \advance\dimen@ #2\p@ % saturated by definition
+ \advance\@tempdima #2\tabucolX
+ \else
+ \ifdim -#2\tabucolX <\tabu@wd{#1}% c_i X < natural width <= \tabu@target-> saturated
+ \advance\dimen@ -#2\p@
+ \advance\@tempdima -#2\tabucolX
+ \else
+ \advance\@tempdima \tabu@wd{#1}% natural width <= c_i X => neutralised
+ \ifdim \tabu@wd{#1}<\tabu@target \else % neutralised
+ \advance\dimen@ -#2\p@ % saturated (natural width = tabu@target)
+ \fi
+ \fi
+ \fi
+}% \tabu@arith@negcoef
+\def\tabu@givespace #1#2{% here \tabu@DELTA < \z@
+ \ifdim \@tempdima=\z@
+ \tabu@wddef{#1}{\the\dimexpr -\tabu@DELTA*\p@/\tabu@Xsum}%
+ \else
+ \tabu@wddef{#1}{\the\dimexpr \tabu@hsize{#1}{#2}
+ *(\p@ -\tabu@DELTA*\p@/\@tempdima)/\p@\relax}%
+ \fi
+}% \tabu@givespace
+\def\tabu@arith {\advance\tabu@cnt \@ne
+ \ifnum \tabu@cnt=\@ne \tabu@message{\tabu@titles}\fi
+ \tabu@arithnegcoef
+ \@tempdimb \dimexpr \wd\tabu@box -\@tempdima \relax % <incompressible material>
+ \tabu@DELTA = \dimexpr \wd\tabu@box - \tabu@target \relax
+ \tabu@message{\tabu@message@arith}%
+ \ifdim \tabu@DELTA <\tabu@hfuzz
+ \ifdim \tabu@DELTA<\z@ % wd (tabu)<\tabu@target ?
+ \let\tabu@ \tabu@givespace \tabu@Xcoefs
+ \advance\@tempdima \@tempdimb \advance\@tempdima -\tabu@DELTA % for message
+ \else % already converged: nothing to do but nearly impossible...
+ \fi
+ \tabucolX \maxdimen
+ \tabu@measuringfalse
+ \else % need for narrower X columns
+ \tabucolX =\dimexpr (\@tempdima -\tabu@DELTA) *\p@/\tabu@Xsum \relax
+ \tabu@measuringtrue
+ \@whilesw \iftabu@measuring\fi {%
+ \advance\tabu@cnt \@ne
+ \tabu@arithnegcoef
+ \tabu@DELTA =\dimexpr \@tempdima+\@tempdimb -\tabu@target \relax % always < 0 here
+ \tabu@message{\tabu@header
+ \tabu@msgalign \tabucolX { }{ }{ }{ }{ }\@@
+ \tabu@msgalign \@tempdima+\@tempdimb { }{ }{ }{ }{ }\@@
+ \tabu@msgalign \tabu@target { }{ }{ }{ }{ }\@@
+ \tabu@msgalign@PT \dimen@ { }{}{}{}{}{}{}\@@
+ \ifdim -\tabu@DELTA<\tabu@hfuzz \tabu@spaces target ok\else
+ \tabu@msgalign \dimexpr -\tabu@DELTA *\p@/\dimen@ {}{}{}{}{}\@@
+ \fi}%
+ \ifdim -\tabu@DELTA<\tabu@hfuzz
+ \advance\@tempdima \@tempdimb % for message
+ \tabu@measuringfalse
+ \else
+ \advance\tabucolX \dimexpr -\tabu@DELTA *\p@/\dimen@ \relax
+ \fi
+ }%
+ \fi
+ \tabu@message{\tabu@message@reached}%
+ \edef\tabu@bufferX{\endgroup \tabu@cnt \the\tabu@cnt
+ \tabucolX \the\tabucolX
+ \tabu@target \the\tabu@target}%
+}% \tabu@arith
+\def\tabu@spreadarith {%
+ \dimen@ \z@ \@tempdima \tabu@naturalXmax \let\tabu@ \tabu@spread@arith \tabu@Xcoefs
+ \edef\tabu@naturalXmin {\the\dimexpr\tabu@naturalXmin*\dimen@/\p@}%
+ \@tempdimc =\dimexpr \wd\tabu@box -\tabu@naturalXmax+\tabu@naturalXmin \relax
+ \iftabu@measuring
+ \tabu@target =\dimexpr \@tempdimc+\tabu@spreadtarget \relax
+ \edef\tabu@bufferX{\endgroup \tabucolX \the\tabucolX \tabu@target\the\tabu@target}%
+ \else
+ \tabu@message{\tabu@message@spreadarith}%
+ \ifdim \dimexpr \@tempdimc+\tabu@spreadtarget >\tabu@target
+ \tabu@message{(tabu) spread
+ \ifdim \@tempdimc>\tabu@target useless here: default target used%
+ \else too large: reduced to fit default target\fi.}%
+ \else
+ \tabu@target =\dimexpr \@tempdimc+\tabu@spreadtarget \relax
+ \tabu@message{(tabu) spread: New target set to \the\tabu@target^^J}%
+ \fi
+ \begingroup \let\tabu@wddef \@gobbletwo
+ \@tempdimb \@tempdima
+ \tabucolX@init
+ \tabu@arithnegcoef
+ \wd\tabu@box =\dimexpr \wd\tabu@box +\@tempdima-\@tempdimb \relax
+ \expandafter\endgroup \expandafter\tabucolX \the\tabucolX
+ \tabu@arith
+ \fi
+}% \tabu@spreadarith
+\def\tabu@spread@arith #1#2{%
+ \ifdim #2\p@>\z@ \advance\dimen@ #2\p@
+ \else \advance\@tempdima \tabu@wd{#1}\relax
+ \fi
+}% \tabu@spread@arith
+%% Reporting in the .log file ---------------------------------------
+\def\tabu@message@defaulttarget{%
+ \ifnum\tabu@nested=\z@^^J(tabu) Default target:
+ \ifx\tabudefaulttarget\linewidth \string\linewidth
+ \ifdim \tabu@thetarget=\linewidth \else
+ -\the\dimexpr\linewidth-\tabu@thetarget\fi =
+ \else\ifx\tabudefaulttarget\linegoal\string\linegoal=
+ \fi\fi
+ \else (tabu) Default target (nested): \fi
+ \the\tabu@target \on@line
+ \ifnum\tabu@nested=\z@ , page \the\c@page\fi}
+\def\tabu@message@target {^^J(tabu) Target specified:
+ \the\tabu@target \on@line, page \the\c@page}
+\def\tabu@message@arith {\tabu@header
+ \tabu@msgalign \tabucolX { }{ }{ }{ }{ }\@@
+ \tabu@msgalign \wd\tabu@box { }{ }{ }{ }{ }\@@
+ \tabu@msgalign \tabu@target { }{ }{ }{ }{ }\@@
+ \tabu@msgalign@PT \dimen@ { }{}{}{}{}{}{}\@@
+ \ifdim \tabu@DELTA<\tabu@hfuzz giving space\else
+ \tabu@msgalign \dimexpr (\@tempdima-\tabu@DELTA) *\p@/\tabu@Xsum -\tabucolX {}{}{}{}{}\@@
+ \fi
+}% \tabu@message@arith
+\def\tabu@message@spreadarith {\tabu@spreadheader
+ \tabu@msgalign \tabu@spreadtarget { }{ }{ }{ }{}\@@
+ \tabu@msgalign \wd\tabu@box { }{ }{ }{ }{}\@@
+ \tabu@msgalign -\tabu@naturalXmax { }{}{}{}{}\@@
+ \tabu@msgalign \tabu@naturalXmin { }{ }{ }{ }{}\@@
+ \tabu@msgalign \ifdim \dimexpr\@tempdimc>\tabu@target \tabu@target
+ \else \@tempdimc+\tabu@spreadtarget \fi
+ {}{}{}{}{}\@@}
+\def\tabu@message@negcoef #1#2{
+ \tabu@spaces\tabu@spaces\space * #1. X[\rem@pt#2]:
+ \space width = \tabu@wd {#1}
+ \expandafter\string\csname tabu@\the\tabu@nested.W\number#1\endcsname
+ \ifdim -\tabu@pt#2\tabucolX<\tabu@target
+ < \number-\rem@pt#2 X
+ = \the\dimexpr -\tabu@pt#2\tabucolX \relax
+ \else
+ <= \the\tabu@target\space < \number-\rem@pt#2 X\fi}
+\def\tabu@message@reached{\tabu@header
+ ******* Reached Target:
+ hfuzz = \tabu@hfuzz\on@line\space *******}
+\def\tabu@message@etime{\edef\tabu@stoptime{\the\pdfelapsedtime}%
+ \tabu@message{(tabu)\tabu@spaces Time elapsed during measure:
+ \the\numexpr(\tabu@stoptime-\tabu@starttime-32767)/65536\relax sec
+ \the\numexpr\numexpr(\tabu@stoptime-\tabu@starttime)
+ -\numexpr(\tabu@stoptime-\tabu@starttime-32767)/65536\relax*65536\relax
+ *1000/65536\relax ms \tabu@spaces(\the\tabu@cnt\space
+ cycle\ifnum\tabu@cnt>\@ne s\fi)^^J^^J}}
+\def\tabu@message@verticalsp {%
+ \ifdim \@tempdima>\tabu@ht
+ \ifdim \@tempdimb>\tabu@dp
+ \expandafter\expandafter\expandafter\string\tabu@ht =
+ \tabu@msgalign \@tempdima { }{ }{ }{ }{ }\@@
+ \expandafter\expandafter\expandafter\string\tabu@dp =
+ \tabu@msgalign \@tempdimb { }{ }{ }{ }{ }\@@^^J%
+ \else
+ \expandafter\expandafter\expandafter\string\tabu@ht =
+ \tabu@msgalign \@tempdima { }{ }{ }{ }{ }\@@^^J%
+ \fi
+ \else\ifdim \@tempdimb>\tabu@dp
+ \tabu@spaces\tabu@spaces\tabu@spaces
+ \expandafter\expandafter\expandafter\string\tabu@dp =
+ \tabu@msgalign \@tempdimb { }{ }{ }{ }{ }\@@^^J\fi
+ \fi
+}% \tabu@message@verticalsp
+\edef\tabu@spaces{\@spaces}
+\def\tabu@strippt{\expandafter\tabu@pt\the}
+{\@makeother\P \@makeother\T\lowercase{\gdef\tabu@pt #1PT{#1}}}
+\def\tabu@msgalign{\expandafter\tabu@msg@align\the\dimexpr}
+\def\tabu@msgalign@PT{\expandafter\tabu@msg@align\romannumeral-`\0\tabu@strippt}
+\def\do #1{%
+ \def\tabu@msg@align##1.##2##3##4##5##6##7##8##9\@@{%
+ \ifnum##1<10 #1 #1\else
+ \ifnum##1<100 #1 \else
+ \ifnum##1<\@m #1\fi\fi\fi
+ ##1.##2##3##4##5##6##7##8#1}%
+ \def\tabu@header{(tabu) \ifnum\tabu@cnt<10 #1\fi\the\tabu@cnt) }%
+ \def\tabu@titles{\ifnum \tabu@nested=\z@
+ (tabu) Try#1 #1 tabu X #1 #1 #1tabu Width #1 #1 Target
+ #1 #1 #1 Coefs #1 #1 #1 Update^^J\fi}%
+ \def\tabu@spreadheader{%
+ (tabu) Try#1 #1 Spread #1 #1 tabu Width #1 #1 #1 Nat. X #1 #1 #1 #1Nat. Min.
+ #1 New Target^^J%
+ (tabu) sprd}
+ \def\tabu@message@save {\begingroup
+ \def\x ####1{\tabu@msg@align ####1{ }{ }{ }{ }{}\@@}
+ \def\z ####1{\expandafter\x\expandafter{\romannumeral-`\0\tabu@strippt
+ \dimexpr####1\p@{ }{ }}}%
+ \let\color \relax \def\tabu@rulesstyle ####1####2{\detokenize{####1}}%
+ \let\CT@arc@ \relax \let\@preamble \@gobble
+ \let\tabu@savedpream \@firstofone
+ \let\tabu@savedparams \@firstofone
+ \def\tabu@target ####1\relax {(tabu) target #1 #1 #1 #1 #1 = \x{####1}^^J}%
+ \def\tabucolX ####1\relax {(tabu) X columns width#1 = \x{####1}^^J}%
+ \def\tabu@nbcols ####1\relax {(tabu) Number of columns: \z{####1}^^J}%
+ \def\tabu@aligndefault ####1{(tabu) Default alignment: #1 #1 ####1^^J}%
+ \def\col@sep ####1\relax {(tabu) column sep #1 #1 #1 = \x{####1}^^J}%
+ \def\arrayrulewidth ####1\relax{(tabu) arrayrulewidth #1 = \x{####1}}%
+ \def\doublerulesep ####1\relax { doublerulesep = \x{####1}^^J}%
+ \def\extratabsurround####1\relax{(tabu) extratabsurround = \x{####1}^^J}%
+ \def\extrarowheight ####1\relax{(tabu) extrarowheight #1 = \x{####1}}%
+ \def\extrarowdepth ####1\relax {extrarowdepth = \x{####1}^^J}%
+ \def\abovetabulinesep####1\relax{(tabu) abovetabulinesep=\x{####1} }%
+ \def\belowtabulinesep####1\relax{ belowtabulinesep=\x{####1}^^J}%
+ \def\arraystretch ####1{(tabu) arraystretch #1 #1 = \z{####1}^^J}%
+ \def\minrowclearance####1\relax{(tabu) minrowclearance #1 = \x{####1}^^J}%
+ \def\tabu@arc@L ####1{(tabu) taburulecolor #1 #1 = ####1^^J}%
+ \def\tabu@drsc@L ####1{(tabu) tabudoublerulecolor= ####1^^J}%
+ \def\tabu@evr@L ####1{(tabu) everyrow #1 #1 #1 #1 = \detokenize{####1}^^J}%
+ \def\tabu@ls@L ####1{(tabu) line style = \detokenize{####1}^^J}%
+ \def\NC@find ####1\@nil{(tabu) tabu preamble#1 #1 = \detokenize{####1}^^J}%
+ \def\tabu@wddef####1####2{(tabu) Natural width ####1 = \x{####2}^^J}%
+ \let\edef \@gobbletwo \let\def \@empty \let\let \@gobbletwo
+ \tabu@message{%
+ (tabu) \string\savetabu{\tabu@temp}: \on@line^^J%
+ \tabu@usetabu \@nil^^J}%
+ \endgroup}
+}\do{ }
+%% Measuring the natural width (varwidth) - store the results -------
+\def\tabu@startpboxmeasure #1{\bgroup % entering \vtop
+ \edef\tabu@temp{\expandafter\@secondoftwo \ifx\tabu@hsize #1\else\relax\fi}%
+ \ifodd 1\ifx \tabu@temp\@empty 0 \else % starts with \tabu@hsize ?
+ \iftabu@spread \else % if spread -> measure
+ \ifdim \tabu@temp\p@>\z@ 0 \fi\fi\fi% if coef>0 -> do not measure
+ \let\@startpbox \tabu@startpboxORI % restore immediately (nesting)
+ \tabu@measuringtrue % for the quick option...
+ \tabu@Xcol =\expandafter\@firstoftwo\ifx\tabu@hsize #1\fi
+ \ifdim \tabu@temp\p@>\z@ \ifdim \tabu@temp\tabucolX<\tabu@target
+ \tabu@target=\tabu@temp\tabucolX \fi\fi
+ \setbox\tabu@box \hbox \bgroup
+ \begin{varwidth}\tabu@target
+ \let\FV@ListProcessLine \tabu@FV@ListProcessLine % \hbox to natural width...
+ \narrowragged \arraybackslash \parfillskip \@flushglue
+ \ifdefined\pdfadjustspacing \pdfadjustspacing\z@ \fi
+ \bgroup \aftergroup\tabu@endpboxmeasure
+ \ifdefined \cellspacetoplimit \tabu@cellspacepatch \fi
+ \else \expandafter\@gobble
+ \tabu@startpboxquick{#1}% \@gobble \bgroup
+ \fi
+}% \tabu@startpboxmeasure
+\def\tabu@cellspacepatch{\def\bcolumn##1\@nil{}\let\ecolumn\@empty
+ \bgroup\color@begingroup}
+\def\tabu@endpboxmeasure {%
+ \@finalstrut \@arstrutbox
+ \end{varwidth}\egroup % <got my \tabu@box>
+ \ifdim \tabu@temp\p@ <\z@ % neg coef
+ \ifdim \tabu@wd\tabu@Xcol <\wd\tabu@box
+ \tabu@wddef\tabu@Xcol {\the\wd\tabu@box}%
+ \tabu@debug{\tabu@message@endpboxmeasure}%
+ \fi
+ \else % spread coef>0
+ \global\advance \tabu@naturalX \wd\tabu@box
+ \@tempdima =\dimexpr \wd\tabu@box *\p@/\dimexpr \tabu@temp\p@\relax \relax
+ \ifdim \tabu@naturalXmax <\tabu@naturalX
+ \xdef\tabu@naturalXmax {\the\tabu@naturalX}\fi
+ \ifdim \tabu@naturalXmin <\@tempdima
+ \xdef\tabu@naturalXmin {\the\@tempdima}\fi
+ \fi
+ \box\tabu@box \egroup % end of \vtop (measure) restore \tabu@target
+}% \tabu@endpboxmeasure
+\def\tabu@wddef #1{\expandafter\xdef
+ \csname tabu@\the\tabu@nested.W\number#1\endcsname}
+\def\tabu@wd #1{\csname tabu@\the\tabu@nested.W\number#1\endcsname}
+\def\tabu@message@endpboxmeasure{\tabu@spaces\tabu@spaces<-> % <-> save natural wd
+ \the\tabu@Xcol. X[\tabu@temp]:
+ target = \the\tabucolX \space
+ \expandafter\expandafter\expandafter\string\tabu@wd\tabu@Xcol
+ =\tabu@wd\tabu@Xcol
+}% \tabu@message@endpboxmeasure
+\def\tabu@startpboxquick {\bgroup
+ \let\@startpbox \tabu@startpboxORI % restore immediately
+ \let\tabu \tabu@quick % \begin is expanded before...
+ \expandafter\@gobble \@startpbox % gobbles \bgroup
+}% \tabu@startpboxquick
+\def\tabu@quick {\begingroup \iffalse{\fi \ifnum0=`}\fi
+ \toks@{}\def\tabu@stack{b}\tabu@collectbody \tabu@endquick
+}% \tabu@quick
+\def\tabu@endquick {%
+ \ifodd 1\ifx\tabu@end@envir\tabu@endtabu \else
+ \ifx\tabu@end@envir\tabu@endtabus \else 0\fi\fi\relax
+ \endgroup
+ \else \let\endtabu \relax
+ \tabu@end@envir
+ \fi
+}% \tabu@quick
+\def\tabu@endtabu {\end{tabu}}
+\def\tabu@endtabus {\end{tabu*}}
+%% Measuring the heights and depths - store the results -------------
+\def\tabu@verticalmeasure{\everypar{}%
+ \ifnum \currentgrouptype>12 % 14=semi-simple, 15=math shift group
+ \setbox\tabu@box =\hbox\bgroup
+ \let\tabu@verticalspacing \tabu@verticalsp@lcr
+ \d@llarbegin % after \hbox ...
+ \else
+ \edef\tabu@temp{\ifnum\currentgrouptype=5\vtop
+ \else\ifnum\currentgrouptype=12\vcenter
+ \else\vbox\fi\fi}%
+ \setbox\tabu@box \hbox\bgroup$\tabu@temp \bgroup
+ \let\tabu@verticalspacing \tabu@verticalsp@pmb
+ \fi
+}% \tabu@verticalmeasure
+\def\tabu@verticalsp@lcr{%
+ \d@llarend \egroup % <got my \tabu@box>
+ \@tempdima \dimexpr \ht\tabu@box+\abovetabulinesep
+ \@tempdimb \dimexpr \dp\tabu@box+\belowtabulinesep \relax
+ \ifdim\tabustrutrule>\z@ \tabu@debug{\tabu@message@verticalsp}\fi
+ \ifdim \tabu@ht<\@tempdima \tabu@htdef{\the\@tempdima}\fi
+ \ifdim \tabu@dp<\@tempdimb \tabu@dpdef{\the\@tempdimb}\fi
+ \noindent\vrule height\@tempdima depth\@tempdimb
+}% \tabu@verticalsp@lcr
+\def\tabu@verticalsp@pmb{% inserts struts as needed
+ \par \expandafter\egroup
+ \expandafter$\expandafter
+ \egroup \expandafter
+ \@tempdimc \the\prevdepth
+ \@tempdima \dimexpr \ht\tabu@box+\abovetabulinesep
+ \@tempdimb \dimexpr \dp\tabu@box+\belowtabulinesep \relax
+ \ifdim\tabustrutrule>\z@ \tabu@debug{\tabu@message@verticalsp}\fi
+ \ifdim \tabu@ht<\@tempdima \tabu@htdef{\the\@tempdima}\fi
+ \ifdim \tabu@dp<\@tempdimb \tabu@dpdef{\the\@tempdimb}\fi
+ \let\@finalstrut \@gobble
+ \hrule height\@tempdima depth\@tempdimb width\hsize
+%% \box\tabu@box
+}% \tabu@verticalsp@pmb
+
+\def\tabu@verticalinit{%
+ \ifnum \c@taburow=\z@ \tabu@rearstrut \fi % after \tabu@reset !
+ \advance\c@taburow \@ne
+ \tabu@htdef{\the\ht\@arstrutbox}\tabu@dpdef{\the\dp\@arstrutbox}%
+ \advance\c@taburow \m@ne
+}% \tabu@verticalinit
+\def\tabu@htdef {\expandafter\xdef \csname tabu@\the\tabu@nested.H\the\c@taburow\endcsname}
+\def\tabu@ht {\csname tabu@\the\tabu@nested.H\the\c@taburow\endcsname}
+\def\tabu@dpdef {\expandafter\xdef \csname tabu@\the\tabu@nested.D\the\c@taburow\endcsname}
+\def\tabu@dp {\csname tabu@\the\tabu@nested.D\the\c@taburow\endcsname}
+\def\tabu@verticaldynamicadjustment {%
+ \advance\c@taburow \@ne
+ \extrarowheight \dimexpr\tabu@ht - \ht\strutbox
+ \extrarowdepth \dimexpr\tabu@dp - \dp\strutbox
+ \let\arraystretch \@empty
+ \advance\c@taburow \m@ne
+}% \tabu@verticaldynamicadjustment
+\def\tabuphantomline{\crcr \noalign{%
+ {\globaldefs \@ne
+ \setbox\@arstrutbox \box\voidb@x
+ \let\tabu@@celllalign \tabu@celllalign
+ \let\tabu@@cellralign \tabu@cellralign
+ \let\tabu@@cellleft \tabu@cellleft
+ \let\tabu@@cellright \tabu@cellright
+ \let\tabu@@thevline \tabu@thevline
+ \let\tabu@celllalign \@empty
+ \let\tabu@cellralign \@empty
+ \let\tabu@cellright \@empty
+ \let\tabu@cellleft \@empty
+ \let\tabu@thevline \relax}%
+ \edef\tabu@temp{\tabu@multispan \tabu@nbcols{\noindent &}}%
+ \toks@\expandafter{\tabu@temp \noindent\tabu@everyrowfalse \cr
+ \noalign{\tabu@rearstrut
+ {\globaldefs\@ne
+ \let\tabu@celllalign \tabu@@celllalign
+ \let\tabu@cellralign \tabu@@cellralign
+ \let\tabu@cellleft \tabu@@cellleft
+ \let\tabu@cellright \tabu@@cellright
+ \let\tabu@thevline \tabu@@thevline}}}%
+ \expandafter}\the\toks@
+}% \tabuphantomline
+%% \firsthline and \lasthline corrections ---------------------------
+\def\tabu@firstline {\tabu@hlineAZ \tabu@firsthlinecorrection {}}
+\def\tabu@firsthline{\tabu@hlineAZ \tabu@firsthlinecorrection \hline}
+\def\tabu@lastline {\tabu@hlineAZ \tabu@lasthlinecorrection {}}
+\def\tabu@lasthline {\tabu@hlineAZ \tabu@lasthlinecorrection \hline}
+\def\tabu@hline {% replaces \hline if no colortbl (see \AtBeginDocument)
+ \noalign{\ifnum0=`}\fi
+ {\CT@arc@\hrule height\arrayrulewidth}%
+ \futurelet \tabu@temp \tabu@xhline
+}% \tabu@hline
+\def\tabu@xhline{%
+ \ifx \tabu@temp \hline
+ {\ifx \CT@drsc@\relax \vskip
+ \else\ifx \CT@drsc@\@empty \vskip
+ \else \CT@drsc@\hrule height
+ \fi\fi
+ \doublerulesep}%
+ \fi
+ \ifnum0=`{\fi}%
+}% \tabu@xhline
+\def\tabu@hlineAZ #1#2{\noalign{\ifnum0=`}\fi \dimen@ \z@ \count@ \z@
+ \toks@{}\def\tabu@hlinecorrection{#1}\def\tabu@temp{#2}%
+ \tabu@hlineAZsurround
+}% \tabu@hlineAZ
+\newcommand*\tabu@hlineAZsurround[1][\extratabsurround]{%
+ \extratabsurround #1\let\tabucline \tabucline@scan
+ \let\hline \tabu@hlinescan \let\firsthline \hline
+ \let\cline \tabu@clinescan \let\lasthline \hline
+ \expandafter \futurelet \expandafter \tabu@temp
+ \expandafter \tabu@nexthlineAZ \tabu@temp
+}% \tabu@hlineAZsurround
+\def\tabu@hlinescan {\tabu@thick \arrayrulewidth \tabu@xhlineAZ \hline}
+\def\tabu@clinescan #1{\tabu@thick \arrayrulewidth \tabu@xhlineAZ {\cline{#1}}}
+\def\tabucline@scan{\@testopt \tabucline@sc@n {}}
+\def\tabucline@sc@n #1[#2]{\tabu@xhlineAZ {\tabucline[{#1}]{#2}}}
+\def\tabu@nexthlineAZ{%
+ \ifx \tabu@temp\hline \else
+ \ifx \tabu@temp\cline \else
+ \ifx \tabu@temp\tabucline \else
+ \tabu@hlinecorrection
+ \fi\fi\fi
+}% \tabu@nexthlineAZ
+\def\tabu@xhlineAZ #1{%
+ \toks@\expandafter{\the\toks@ #1}%
+ \@tempdimc \tabu@thick % The last line width
+ \ifcase\count@ \@tempdimb \tabu@thick % The first line width
+ \else \advance\dimen@ \dimexpr \tabu@thick+\doublerulesep \relax
+ \fi
+ \advance\count@ \@ne \futurelet \tabu@temp \tabu@nexthlineAZ
+}% \tabu@xhlineAZ
+\def\tabu@firsthlinecorrection{% \count@ = number of \hline -1
+ \@tempdima \dimexpr \ht\@arstrutbox+\dimen@
+ \edef\firsthline{% <local in \noalign>
+ \omit \hbox to\z@{\hss{\noexpand\tabu@DBG{yellow}\vrule
+ height \the\dimexpr\@tempdima+\extratabsurround
+ depth \dp\@arstrutbox
+ width \tabustrutrule}\hss}\cr
+ \noalign{\vskip -\the\dimexpr \@tempdima+\@tempdimb
+ +\dp\@arstrutbox \relax}%
+ \the\toks@
+ }\ifnum0=`{\fi
+ \expandafter}\firsthline % we are then !
+}% \tabu@firsthlinecorrection
+\def\tabu@lasthlinecorrection{%
+ \@tempdima \dimexpr \dp\@arstrutbox+\dimen@+\@tempdimb+\@tempdimc
+ \edef\lasthline{% <local in \noalign>
+ \the\toks@
+ \noalign{\vskip -\the\dimexpr\dimen@+\@tempdimb+\dp\@arstrutbox}%
+ \omit \hbox to\z@{\hss{\noexpand\tabu@DBG{yellow}\vrule
+ depth \the\dimexpr \dp\@arstrutbox+\@tempdimb+\dimen@
+ +\extratabsurround-\@tempdimc
+ height \z@
+ width \tabustrutrule}\hss}\cr
+ }\ifnum0=`{\fi
+ \expandafter}\lasthline % we are then !
+}% \tabu@lasthlinecorrection
+\def\tabu@LT@@hline{%
+ \ifx\LT@next\hline
+ \global\let\LT@next \@gobble
+ \ifx \CT@drsc@\relax
+ \gdef\CT@LT@sep{%
+ \noalign{\penalty-\@medpenalty\vskip\doublerulesep}}%
+ \else
+ \gdef\CT@LT@sep{%
+ \multispan\LT@cols{%
+ \CT@drsc@\leaders\hrule\@height\doublerulesep\hfill}\cr}%
+ \fi
+ \else
+ \global\let\LT@next\empty
+ \gdef\CT@LT@sep{%
+ \noalign{\penalty-\@lowpenalty\vskip-\arrayrulewidth}}%
+ \fi
+ \ifnum0=`{\fi}%
+ \multispan\LT@cols
+ {\CT@arc@\leaders\hrule\@height\arrayrulewidth\hfill}\cr
+ \CT@LT@sep
+ \multispan\LT@cols
+ {\CT@arc@\leaders\hrule\@height\arrayrulewidth\hfill}\cr
+ \noalign{\penalty\@M}%
+ \LT@next
+}% \tabu@LT@@hline
+%% Horizontal lines : \tabucline ------------------------------------
+\let\tabu@start \@tempcnta
+\let\tabu@stop \@tempcntb
+\newcommand*\tabucline{\noalign{\ifnum0=`}\fi \tabu@cline}
+\newcommand*\tabu@cline[2][]{\tabu@startstop{#2}%
+ \ifnum \tabu@stop<\z@ \toks@{}%
+ \else \tabu@clinearg{#1}\tabu@thestyle
+ \edef\tabucline{\toks@{%
+ \ifnum \tabu@start>\z@ \omit
+ \tabu@multispan\tabu@start {\span\omit}&\fi
+ \omit \tabu@multispan\tabu@stop {\span\omit}%
+ \tabu@thehline\cr
+ }}\tabucline
+ \tabu@tracinglines{(tabu:tabucline) Style: #1^^J\the\toks@^^J^^J}%
+ \fi
+ \futurelet \tabu@temp \tabu@xcline
+}% \tabu@cline
+\def\tabu@clinearg #1{%
+ \ifx\\#1\\\let\tabu@thestyle \tabu@ls@
+ \else \@defaultunits \expandafter\let\expandafter\@tempa
+ \romannumeral-`\0#1\relax \@nnil
+ \ifx \hbox\@tempa \tabu@clinebox{#1}%
+ \else\ifx \box\@tempa \tabu@clinebox{#1}%
+ \else\ifx \vbox\@tempa \tabu@clinebox{#1}%
+ \else\ifx \vtop\@tempa \tabu@clinebox{#1}%
+ \else\ifx \copy\@tempa \tabu@clinebox{#1}%
+ \else\ifx \leaders\@tempa \tabu@clineleads{#1}%
+ \else\ifx \cleaders\@tempa \tabu@clineleads{#1}%
+ \else\ifx \xleaders\@tempa \tabu@clineleads{#1}%
+ \else\tabu@getline {#1}%
+ \fi\fi\fi\fi\fi\fi\fi\fi
+ \fi
+}% \tabu@clinearg
+\def\tabu@clinebox #1{\tabu@clineleads{\xleaders#1\hss}}
+\def\tabu@clineleads #1{%
+ \let\tabu@thestyle \relax \let\tabu@leaders \@undefined
+ \gdef\tabu@thehrule{#1}}
+\def\tabu@thehline{\begingroup
+ \ifdefined\tabu@leaders
+ \noexpand\tabu@thehleaders
+ \else \noexpand\tabu@thehrule
+ \fi \endgroup
+}% \tabu@thehline
+\def\tabu@xcline{%
+ \ifx \tabu@temp\tabucline
+ \toks@\expandafter{\the\toks@ \noalign
+ {\ifx\CT@drsc@\relax \vskip
+ \else \CT@drsc@\hrule height
+ \fi
+ \doublerulesep}}%
+ \fi
+ \tabu@docline
+}% \tabu@xcline
+\def\tabu@docline {\ifnum0=`{\fi \expandafter}\the\toks@}
+\def\tabu@docline@evr {\xdef\tabu@doclineafter{\the\toks@}%
+ \ifnum0=`{\fi}\aftergroup\tabu@doclineafter}
+\def\tabu@multispan #1#2{%
+ \ifnum\numexpr#1>\@ne #2\expandafter\tabu@multispan
+ \else \expandafter\@gobbletwo
+ \fi {#1-1}{#2}%
+}% \tabu@multispan
+\def\tabu@startstop #1{\tabu@start@stop #1\relax 1-\tabu@nbcols \@nnil}
+\def\tabu@start@stop #1-#2\@nnil{%
+ \@defaultunits \tabu@start\number 0#1\relax \@nnil
+ \@defaultunits \tabu@stop \number 0#2\relax \@nnil
+ \tabu@stop \ifnum \tabu@start>\tabu@nbcols \m@ne
+ \else\ifnum \tabu@stop=\z@ \tabu@nbcols
+ \else\ifnum \tabu@stop>\tabu@nbcols \tabu@nbcols
+ \else \tabu@stop
+ \fi\fi\fi
+ \advance\tabu@start \m@ne
+ \ifnum \tabu@start>\z@ \advance\tabu@stop -\tabu@start \fi
+}% \tabu@start@stop
+%% Numbers: siunitx S columns (and \tabudecimal) -------------------
+\def\tabu@tabudecimal #1{%
+ \def\tabu@decimal{#1}\@temptokena{}%
+ \let\tabu@getdecimal@ \tabu@getdecimal@ignorespaces
+ \tabu@scandecimal
+}% \tabu@tabudecimal
+\def\tabu@scandecimal{\futurelet \tabu@temp \tabu@getdecimal@}
+\def\tabu@skipdecimal#1{#1\tabu@scandecimal}
+\def\tabu@getdecimal@ignorespaces{%
+ \ifcase 0\ifx\tabu@temp\ignorespaces\else
+ \ifx\tabu@temp\@sptoken1\else
+ 2\fi\fi\relax
+ \let\tabu@getdecimal@ \tabu@getdecimal
+ \expandafter\tabu@skipdecimal
+ \or \expandafter\tabu@gobblespace\expandafter\tabu@scandecimal
+ \else \expandafter\tabu@skipdecimal
+ \fi
+}% \tabu@getdecimal@ignorespaces
+\def\tabu@get@decimal#1{\@temptokena\expandafter{\the\@temptokena #1}%
+ \tabu@scandecimal}
+\def\do#1{%
+ \def\tabu@get@decimalspace#1{%
+ \@temptokena\expandafter{\the\@temptokena #1}\tabu@scandecimal}%
+}\do{ }
+\let\tabu@@tabudecimal \tabu@tabudecimal
+\def\tabu@getdecimal{%
+ \ifcase 0\ifx 0\tabu@temp\else
+ \ifx 1\tabu@temp\else
+ \ifx 2\tabu@temp\else
+ \ifx 3\tabu@temp\else
+ \ifx 4\tabu@temp\else
+ \ifx 5\tabu@temp\else
+ \ifx 6\tabu@temp\else
+ \ifx 7\tabu@temp\else
+ \ifx 8\tabu@temp\else
+ \ifx 9\tabu@temp\else
+ \ifx .\tabu@temp\else
+ \ifx ,\tabu@temp\else
+ \ifx -\tabu@temp\else
+ \ifx +\tabu@temp\else
+ \ifx e\tabu@temp\else
+ \ifx E\tabu@temp\else
+ \ifx\tabu@cellleft\tabu@temp1\else
+ \ifx\ignorespaces\tabu@temp1\else
+ \ifx\@sptoken\tabu@temp2\else
+ 3\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\relax
+ \expandafter\tabu@get@decimal
+ \or \expandafter\tabu@skipdecimal
+ \or \expandafter\tabu@get@decimalspace
+ \else\expandafter\tabu@printdecimal
+ \fi
+}% \tabu@getdecimal
+\def\tabu@printdecimal{%
+ \edef\tabu@temp{\the\@temptokena}%
+ \ifx\tabu@temp\@empty\else
+ \ifx\tabu@temp\space\else
+ \expandafter\tabu@decimal\expandafter{\the\@temptokena}%
+ \fi\fi
+}% \tabu@printdecimal
+%% Verbatim inside X columns ----------------------------------------
+\def\tabu@verbatim{%
+ \let\verb \tabu@verb
+ \let\FV@DefineCheckEnd \tabu@FV@DefineCheckEnd
+}% \tabu@verbatim
+\let\tabu@ltx@verb \verb
+\def\tabu@verb{\@ifstar {\tabu@ltx@verb*} \tabu@ltx@verb}
+\def\tabu@fancyvrb {%
+ \def\tabu@FV@DefineCheckEnd ##1{%
+ \def\tabu@FV@DefineCheckEnd{%
+ ##1% <original definition (if fancyvrb is loaded)>
+ \let\FV@CheckEnd \tabu@FV@CheckEnd
+ \let\FV@@CheckEnd \tabu@FV@@CheckEnd
+ \let\FV@@@CheckEnd \tabu@FV@@@CheckEnd
+ \edef\FV@EndScanning{%
+ \def\noexpand\next{\noexpand\end{\FV@EnvironName}}%
+ \global\let\noexpand\FV@EnvironName\relax
+ \noexpand\next}%
+ \xdef\FV@EnvironName{\detokenize\expandafter{\FV@EnvironName}}}%
+ }\expandafter\tabu@FV@DefineCheckEnd\expandafter{\FV@DefineCheckEnd}
+}% \tabu@fancyvrb
+\def\tabu@FV@CheckEnd #1{\expandafter\FV@@CheckEnd \detokenize{#1\end{}}\@nil}
+\edef\tabu@FV@@@CheckEnd {\detokenize{\end{}}}
+\begingroup
+\catcode`\[1 \catcode`\]2
+\@makeother\{ \@makeother\}
+ \edef\x[\endgroup
+ \def\noexpand\tabu@FV@@CheckEnd ##1\detokenize[\end{]##2\detokenize[}]##3%
+ ]\x \@nil{\def\@tempa{#2}\def\@tempb{#3}}
+\def\tabu@FV@ListProcessLine #1{%
+ \hbox {%to \hsize{%
+ \kern\leftmargin
+ \hbox {%to \linewidth{%
+ \FV@LeftListNumber
+ \FV@LeftListFrame
+ \FancyVerbFormatLine{#1}\hss
+%% DG/SR modification begin - Jan. 28, 1998 (for numbers=right add-on)
+%% \FV@RightListFrame}%
+ \FV@RightListFrame
+ \FV@RightListNumber}%
+%% DG/SR modification end
+ \hss}}
+%% \savetabu --------------------------------------------------------
+\newcommand*\savetabu[1]{\noalign{%
+ \tabu@sanitizearg{#1}\tabu@temp
+ \ifx \tabu@temp\@empty \tabu@savewarn{}{The tabu will not be saved}\else
+ \@ifundefined{tabu@saved@\tabu@temp}{}{\tabu@savewarn{#1}{Overwritting}}%
+ \ifdefined\tabu@restored \expandafter\let
+ \csname tabu@saved@\tabu@temp \endcsname \tabu@restored
+ \else {\tabu@save}%
+ \fi
+ \fi}%
+}% \savetabu
+\def\tabu@save {%
+ \toks0\expandafter{\tabu@saved@}%
+ \iftabu@negcoef
+ \let\tabu@wddef \relax \let\tabu@ \tabu@savewd \edef\tabu@savewd{\tabu@Xcoefs}%
+ \toks0\expandafter{\the\toks\expandafter0\tabu@savewd}\fi
+ \toks1\expandafter{\tabu@savedpream}%
+ \toks2\expandafter{\tabu@savedpreamble}%
+ \let\@preamble \relax
+ \let\tabu@savedpream \relax \let\tabu@savedparams \relax
+ \edef\tabu@preamble{%
+ \def\noexpand\tabu@aligndefault{\tabu@align}%
+ \def\tabu@savedparams {\noexpand\the\toks0}%
+ \def\tabu@savedpream {\noexpand\the\toks1}}%
+ \edef\tabu@usetabu{%
+ \def\@preamble {\noexpand\the\toks2}%
+ \tabu@target \the\tabu@target \relax
+ \tabucolX \the\tabucolX \relax
+ \tabu@nbcols \the\tabu@nbcols \relax
+ \def\noexpand\tabu@aligndefault{\tabu@align}%
+ \def\tabu@savedparams {\noexpand\the\toks0}%
+ \def\tabu@savedpream {\noexpand\the\toks1}}%
+ \let\tabu@aligndefault \relax \let\@sharp \relax
+ \edef\@tempa{\noexpand\tabu@s@ved
+ {\tabu@usetabu}
+ {\tabu@preamble}
+ {\the\toks1}}\@tempa
+ \tabu@message@save
+}% \tabu@save
+\long\def\tabu@s@ved #1#2#3{%
+ \def\tabu@usetabu{#1}% <for \tabu@message@save>
+ \expandafter\gdef\csname tabu@saved@\tabu@temp\endcsname ##1{%
+ \ifodd ##1% \usetabu
+ \tabu@measuringfalse \tabu@spreadfalse % Just in case...
+ \gdef\tabu@usetabu {%
+ \ifdim \tabu@target>\z@ \tabu@warn@usetabu \fi
+ \global\let\tabu@usetabu \@undefined
+ \def\@halignto {to\tabu@target}%
+ #1%
+ \ifx \tabu@align\tabu@aligndefault@text
+ \ifnum \tabu@nested=\z@
+ \let\tabu@align \tabu@aligndefault \fi\fi}%
+ \else % \preamble
+ \gdef\tabu@preamble {%
+ \global\let\tabu@preamble \@undefined
+ #2%
+ \ifx \tabu@align\tabu@aligndefault@text
+ \ifnum \tabu@nested=\z@
+ \let\tabu@align \tabu@aligndefault \fi\fi}%
+ \fi
+ #3}%
+}% \tabu@s@ved
+\def\tabu@aligndefault@text {\tabu@aligndefault}%
+\def\tabu@warn@usetabu {\PackageWarning{tabu}
+ {Specifying a target with \string\usetabu\space is useless
+ \MessageBreak The target cannot be changed!}}
+\def\tabu@savewd #1#2{\ifdim #2\p@<\z@ \tabu@wddef{#1}{\tabu@wd{#1}}\fi}
+\def\tabu@savewarn#1#2{\PackageInfo{tabu}
+ {User-name `#1' already used for \string\savetabu
+ \MessageBreak #2}}%
+\def\tabu@saveerr#1{\PackageError{tabu}
+ {User-name `#1' is unknown for \string\usetabu
+ \MessageBreak I cannot restore an unknown preamble!}\@ehd}
+%% \rowfont ---------------------------------------------------------
+\newskip \tabu@cellskip
+\def\tabu@rowfont{\ifdim \baselineskip=\z@\noalign\fi
+ {\ifnum0=`}\fi \tabu@row@font}
+\newcommand*\tabu@row@font[2][]{%
+ \ifnum7=\currentgrouptype
+ \global\let\tabu@@cellleft \tabu@cellleft
+ \global\let\tabu@@cellright \tabu@cellright
+ \global\let\tabu@@celllalign \tabu@celllalign
+ \global\let\tabu@@cellralign \tabu@cellralign
+ \global\let\tabu@@rowfontreset\tabu@rowfontreset
+ \fi
+ \global\let\tabu@rowfontreset \tabu@rowfont@reset
+ \expandafter\gdef\expandafter\tabu@cellleft\expandafter{\tabu@cellleft #2}%
+ \ifcsname tabu@cell@#1\endcsname % row alignment
+ \csname tabu@cell@#1\endcsname \fi
+ \ifnum0=`{\fi}% end of group / noalign group
+}% \rowfont
+\def\tabu@ifcolorleavevmode #1{\let\color \tabu@leavevmodecolor #1\let\color\tabu@color}%
+\def\tabu@rowfont@reset{%
+ \global\let\tabu@rowfontreset \tabu@@rowfontreset
+ \global\let\tabu@cellleft \tabu@@cellleft
+ \global\let\tabu@cellright \tabu@@cellright
+ \global\let\tabu@cellfont \@empty
+ \global\let\tabu@celllalign \tabu@@celllalign
+ \global\let\tabu@cellralign \tabu@@cellralign
+}% \tabu@@rowfontreset
+\let\tabu@rowfontreset \@empty % overwritten \AtBeginDocument if colortbl
+%% \tabu@prepnext@tok -----------------------------------------------
+\newif \iftabu@cellright
+\def\tabu@prepnext@tok{%
+ \ifnum \count@<\z@ % <first initialisation>
+ \@tempcnta \@M % <not initialized by array.sty>
+ \tabu@nbcols\z@
+ \let\tabu@fornoopORI \@fornoop
+ \tabu@cellrightfalse
+ \else
+ \ifcase \numexpr \count@-\@tempcnta \relax % (case 0): prev. token is left
+ \advance \tabu@nbcols \@ne
+ \iftabu@cellright % before-previous token is right and is finished
+ \tabu@cellrightfalse % <only once>
+ \tabu@righttok
+ \fi
+ \tabu@lefttok
+ \or % (case 1) previous token is right
+ \tabu@cellrighttrue \let\@fornoop \tabu@lastnoop
+ \else % special column: do not change the token
+ \iftabu@cellright % before-previous token is right
+ \tabu@cellrightfalse
+ \tabu@righttok
+ \fi
+ \fi % \ifcase
+ \fi
+ \tabu@prepnext@tokORI
+}% \tabu@prepnext@tok
+\long\def\tabu@lastnoop#1\@@#2#3{\tabu@lastn@@p #2\@nextchar \in@\in@@}
+\def\tabu@lastn@@p #1\@nextchar #2#3\in@@{%
+ \ifx \in@#2\else
+ \let\@fornoop \tabu@fornoopORI
+ \xdef\tabu@mkpreambuffer{\tabu@nbcols\the\tabu@nbcols \tabu@mkpreambuffer}%
+ \toks0\expandafter{\expandafter\tabu@everyrowtrue \the\toks0}%
+ \expandafter\prepnext@tok
+ \fi
+}% \tabu@lastnoop
+\def\tabu@righttok{%
+ \advance \count@ \m@ne
+ \toks\count@\expandafter {\the\toks\count@ \tabu@cellright \tabu@cellralign}%
+ \advance \count@ \@ne
+}% \tabu@righttok
+\def\tabu@lefttok{\toks\count@\expandafter{\expandafter\tabu@celllalign
+ \the\toks\count@ \tabu@cellleft}% after because of $
+}% \tabu@lefttok
+%% Neutralisation of glues ------------------------------------------
+\let\tabu@cellleft \@empty
+\let\tabu@cellright \@empty
+\tabu@celllalign@def{\tabu@cellleft}%
+\let\tabu@cellralign \@empty
+\def\tabu@cell@align #1#2#3{%
+ \let\tabu@maybesiunitx \toks@ \tabu@celllalign
+ \global \expandafter \tabu@celllalign@def \expandafter {\the\toks@ #1}%
+ \toks@\expandafter{\tabu@cellralign #2}%
+ \xdef\tabu@cellralign{\the\toks@}%
+ \toks@\expandafter{\tabu@cellleft #3}%
+ \xdef\tabu@cellleft{\the\toks@}%
+}% \tabu@cell@align
+\def\tabu@cell@l{% force alignment to left
+ \tabu@cell@align
+ {\tabu@removehfil \raggedright \tabu@cellleft}% left
+ {\tabu@flush1\tabu@ignorehfil}% right
+ \raggedright
+}% \tabu@cell@l
+\def\tabu@cell@c{% force alignment to center
+ \tabu@cell@align
+ {\tabu@removehfil \centering \tabu@flush{.5}\tabu@cellleft}
+ {\tabu@flush{.5}\tabu@ignorehfil}
+ \centering
+}% \tabu@cell@c
+\def\tabu@cell@r{% force alignment to right
+ \tabu@cell@align
+ {\tabu@removehfil \raggedleft \tabu@flush1\tabu@cellleft}
+ \tabu@ignorehfil
+ \raggedleft
+}% \tabu@cell@r
+\def\tabu@cell@j{% force justification (for p, m, b columns)
+ \tabu@cell@align
+ {\tabu@justify\tabu@cellleft}
+ {}
+ \tabu@justify
+}% \tabu@cell@j
+\def\tabu@justify{%
+ \leftskip\z@skip \@rightskip\leftskip \rightskip\@rightskip
+ \parfillskip\@flushglue
+}% \tabu@justify
+%% ragged2e settings
+\def\tabu@cell@L{% force alignment to left (ragged2e)
+ \tabu@cell@align
+ {\tabu@removehfil \RaggedRight \tabu@cellleft}
+ {\tabu@flush 1\tabu@ignorehfil}
+ \RaggedRight
+}% \tabu@cell@L
+\def\tabu@cell@C{% force alignment to center (ragged2e)
+ \tabu@cell@align
+ {\tabu@removehfil \Centering \tabu@flush{.5}\tabu@cellleft}
+ {\tabu@flush{.5}\tabu@ignorehfil}
+ \Centering
+}% \tabu@cell@C
+\def\tabu@cell@R{% force alignment to right (ragged2e)
+ \tabu@cell@align
+ {\tabu@removehfil \RaggedLeft \tabu@flush 1\tabu@cellleft}
+ \tabu@ignorehfil
+ \RaggedLeft
+}% \tabu@cell@R
+\def\tabu@cell@J{% force justification (ragged2e)
+ \tabu@cell@align
+ {\justifying \tabu@cellleft}
+ {}
+ \justifying
+}% \tabu@cell@J
+\def\tabu@flush#1{%
+ \iftabu@colortbl % colortbl uses \hfill rather than \hfil
+ \hskip \ifnum13<\currentgrouptype \stretch{#1}%
+ \else \ifdim#1pt<\p@ \tabu@cellskip
+ \else \stretch{#1}
+ \fi\fi \relax
+ \else % array.sty
+ \ifnum 13<\currentgrouptype
+ \hfil \hskip1sp \relax \fi
+ \fi
+}% \tabu@flush
+\let\tabu@hfil \hfil
+\let\tabu@hfill \hfill
+\let\tabu@hskip \hskip
+\def\tabu@removehfil{%
+ \iftabu@colortbl
+ \unkern \tabu@cellskip =\lastskip
+ \ifnum\gluestretchorder\tabu@cellskip =\tw@ \hskip-\tabu@cellskip
+ \else \tabu@cellskip \z@skip
+ \fi
+ \else
+ \ifdim\lastskip=1sp\unskip\fi
+ \ifnum\gluestretchorder\lastskip =\@ne
+ \hfilneg % \hfilneg for array.sty but not for colortbl...
+ \fi
+ \fi
+}% \tabu@removehfil
+\def\tabu@ignorehfil{\aftergroup \tabu@nohfil}
+\def\tabu@nohfil{% \hfil -> do nothing + restore original \hfil
+ \def\hfil{\let\hfil \tabu@hfil}% local to (alignment template) group
+}% \tabu@nohfil
+\def\tabu@colortblalignments {% if colortbl
+ \def\tabu@nohfil{%
+ \def\hfil {\let\hfil \tabu@hfil}% local to (alignment template) group
+ \def\hfill {\let\hfill \tabu@hfill}% (colortbl uses \hfill) pfff...
+ \def\hskip ####1\relax{\let\hskip \tabu@hskip}}% local
+}% \tabu@colortblalignments
+%% Taking care of footnotes and hyperfootnotes ----------------------
+\long\def\tabu@footnotetext #1{%
+ \edef\@tempa{\the\tabu@footnotes
+ \noexpand\footnotetext [\the\csname c@\@mpfn\endcsname]}%
+ \global\tabu@footnotes\expandafter{\@tempa {#1}}}%
+\long\def\tabu@xfootnotetext [#1]#2{%
+ \global\tabu@footnotes\expandafter{\the\tabu@footnotes
+ \footnotetext [{#1}]{#2}}}
+\let\tabu@xfootnote \@xfootnote
+\long\def\tabu@Hy@ftntext{\tabu@Hy@ftntxt {\the \c@footnote }}
+\long\def\tabu@Hy@xfootnote [#1]{%
+ \begingroup
+ \value\@mpfn #1\relax
+ \protected@xdef \@thefnmark {\thempfn}%
+ \endgroup
+ \@footnotemark \tabu@Hy@ftntxt {#1}%
+}% \tabu@Hy@xfootnote
+\long\def\tabu@Hy@ftntxt #1#2{%
+ \edef\@tempa{%
+ \the\tabu@footnotes
+ \begingroup
+ \value\@mpfn #1\relax
+ \noexpand\protected@xdef\noexpand\@thefnmark {\noexpand\thempfn}%
+ \expandafter \noexpand \expandafter
+ \tabu@Hy@footnotetext \expandafter{\Hy@footnote@currentHref}%
+ }%
+ \global\tabu@footnotes\expandafter{\@tempa {#2}%
+ \endgroup}%
+}% \tabu@Hy@ftntxt
+\long\def\tabu@Hy@footnotetext #1#2{%
+ \H@@footnotetext{%
+ \ifHy@nesting
+ \hyper@@anchor {#1}{#2}%
+ \else
+ \Hy@raisedlink{%
+ \hyper@@anchor {#1}{\relax}%
+ }%
+ \def\@currentHref {#1}%
+ \let\@currentlabelname \@empty
+ #2%
+ \fi
+ }%
+}% \tabu@Hy@footnotetext
+%% No need for \arraybackslash ! ------------------------------------
+\def\tabu@latextwoe {%
+\def\tabu@temp##1##2##3{{\toks@\expandafter{##2##3}\xdef##1{\the\toks@}}}
+\tabu@temp \tabu@centering \centering \arraybackslash
+\tabu@temp \tabu@raggedleft \raggedleft \arraybackslash
+\tabu@temp \tabu@raggedright \raggedright \arraybackslash
+}% \tabu@latextwoe
+\def\tabu@raggedtwoe {%
+\def\tabu@temp ##1##2##3{{\toks@\expandafter{##2##3}\xdef##1{\the\toks@}}}
+\tabu@temp \tabu@Centering \Centering \arraybackslash
+\tabu@temp \tabu@RaggedLeft \RaggedLeft \arraybackslash
+\tabu@temp \tabu@RaggedRight \RaggedRight \arraybackslash
+\tabu@temp \tabu@justifying \justifying \arraybackslash
+}% \tabu@raggedtwoe
+\def\tabu@normalcrbackslash{\let\\\@normalcr}
+\def\tabu@trivlist{\expandafter\def\expandafter\@trivlist\expandafter{%
+ \expandafter\tabu@normalcrbackslash \@trivlist}}
+%% Utilities: \fbox \fcolorbox and \tabudecimal -------------------
+\def\tabu@fbox {\leavevmode\afterassignment\tabu@beginfbox \setbox\@tempboxa\hbox}
+\def\tabu@beginfbox {\bgroup \kern\fboxsep
+ \bgroup\aftergroup\tabu@endfbox}
+\def\tabu@endfbox {\kern\fboxsep\egroup\egroup
+ \@frameb@x\relax}
+\def\tabu@color@b@x #1#2{\leavevmode \bgroup
+ \def\tabu@docolor@b@x{#1{#2\color@block{\wd\z@}{\ht\z@}{\dp\z@}\box\z@}}%
+ \afterassignment\tabu@begincolor@b@x \setbox\z@ \hbox
+}% \tabu@color@b@x
+\def\tabu@begincolor@b@x {\kern\fboxsep \bgroup
+ \aftergroup\tabu@endcolor@b@x \set@color}
+\def\tabu@endcolor@b@x {\kern\fboxsep \egroup
+ \dimen@\ht\z@ \advance\dimen@ \fboxsep \ht\z@ \dimen@
+ \dimen@\dp\z@ \advance\dimen@ \fboxsep \dp\z@ \dimen@
+ \tabu@docolor@b@x \egroup
+}% \tabu@endcolor@b@x
+%% Corrections (arydshln, delarray, colortbl) -----------------------
+\def\tabu@fix@arrayright {%% \@arrayright is missing from \endarray
+ \iftabu@colortbl
+ \ifdefined\adl@array % <colortbl + arydshln>
+ \def\tabu@endarray{%
+ \adl@endarray \egroup \adl@arrayrestore \CT@end \egroup %<original>
+ \@arrayright % <FC>
+ \gdef\@preamble{}}% <FC>
+ \else % <colortbl / no arydshln>
+ \def\tabu@endarray{%
+ \crcr \egroup \egroup %<original>
+ \@arrayright % <FC>
+ \gdef\@preamble{}\CT@end}%
+ \fi
+ \else
+ \ifdefined\adl@array % <arydshln / no colortbl>
+ \def\tabu@endarray{%
+ \adl@endarray \egroup \adl@arrayrestore \egroup %<original>
+ \@arrayright % <FC>
+ \gdef\@preamble{}}% <FC>
+ \else % <no arydshln / no colotbl + \@arrayright missing>
+ \PackageWarning{tabu}
+ {\string\@arrayright\space is missing from the
+ \MessageBreak definition of \string\endarray.
+ \MessageBreak Comptability with delarray.sty is broken.}%
+ \fi\fi
+}% \tabu@fix@arrayright
+\def\tabu@adl@xarraydashrule #1#2#3{%
+ \ifnum\@lastchclass=\adl@class@start\else
+ \ifnum\@lastchclass=\@ne\else
+ \ifnum\@lastchclass=5 \else % <FC> @-arg (class 5) and !-arg (class 1)
+ \adl@leftrulefalse \fi\fi % must be treated the same
+ \fi
+ \ifadl@zwvrule\else \ifadl@inactive\else
+ \@addtopreamble{\vrule\@width\arrayrulewidth
+ \@height\z@ \@depth\z@}\fi \fi
+ \ifadl@leftrule
+ \@addtopreamble{\adl@vlineL{\CT@arc@}{\adl@dashgapcolor}%
+ {\number#1}#3}%
+ \else \@addtopreamble{\adl@vlineR{\CT@arc@}{\adl@dashgapcolor}%
+ {\number#2}#3}
+ \fi
+}% \tabu@adl@xarraydashrule
+\def\tabu@adl@act@endpbox {%
+ \unskip \ifhmode \nobreak \fi \@finalstrut \@arstrutbox
+ \egroup \egroup
+ \adl@colhtdp \box\adl@box \hfil
+}% \tabu@adl@act@endpbox
+\def\tabu@adl@fix {%
+ \let\adl@xarraydashrule \tabu@adl@xarraydashrule % <fix> arydshln
+ \let\adl@act@endpbox \tabu@adl@act@endpbox % <fix> arydshln
+ \let\adl@act@@endpbox \tabu@adl@act@endpbox % <fix> arydshln
+ \let\@preamerror \@preamerr % <fix> arydshln
+}% \tabu@adl@fix
+%% Correction for longtable' \@startbox definition ------------------
+%% => \everypar is ``missing'' : TeX should be in vertical mode
+\def\tabu@LT@startpbox #1{%
+ \bgroup
+ \let\@footnotetext\LT@p@ftntext
+ \setlength\hsize{#1}%
+ \@arrayparboxrestore
+ \everypar{%
+ \vrule \@height \ht\@arstrutbox \@width \z@
+ \everypar{}}%
+}% \tabu@LT@startpbox
+%% \tracingtabu and the package options ------------------
+\DeclareOption{delarray}{\AtEndOfPackage{\RequirePackage{delarray}}}
+\DeclareOption{linegoal}{%
+ \AtEndOfPackage{%
+ \RequirePackage{linegoal}[2010/12/07]%
+ \let\tabudefaulttarget \linegoal% \linegoal is \linewidth if not pdfTeX
+}}
+\DeclareOption{scantokens}{\tabuscantokenstrue}
+\DeclareOption{debugshow}{\AtEndOfPackage{\tracingtabu=\tw@}}
+\def\tracingtabu {\begingroup\@ifnextchar=%
+ {\afterassignment\tabu@tracing\count@}
+ {\afterassignment\tabu@tracing\count@1\relax}}
+\def\tabu@tracing{\expandafter\endgroup
+ \expandafter\tabu@tr@cing \the\count@ \relax
+}% \tabu@tracing
+\def\tabu@tr@cing #1\relax {%
+ \ifnum#1>\thr@@ \let\tabu@tracinglines\message
+ \else \let\tabu@tracinglines\@gobble
+ \fi
+ \ifnum#1>\tw@ \let\tabu@DBG \tabu@@DBG
+ \def\tabu@mkarstrut {\tabu@DBG@arstrut}%
+ \tabustrutrule 1.5\p@
+ \else \let\tabu@DBG \@gobble
+ \def\tabu@mkarstrut {\tabu@arstrut}%
+ \tabustrutrule \z@
+ \fi
+ \ifnum#1>\@ne \let\tabu@debug \message
+ \else \let\tabu@debug \@gobble
+ \fi
+ \ifnum#1>\z@
+ \let\tabu@message \message
+ \let\tabu@tracing@save \tabu@message@save
+ \let\tabu@starttimer \tabu@pdftimer
+ \else
+ \let\tabu@message \@gobble
+ \let\tabu@tracing@save \@gobble
+ \let\tabu@starttimer \relax
+ \fi
+}% \tabu@tr@cing
+%% Setup \AtBeginDocument
+\AtBeginDocument{\tabu@AtBeginDocument}
+\def\tabu@AtBeginDocument{\let\tabu@AtBeginDocument \@undefined
+ \ifdefined\arrayrulecolor \tabu@colortbltrue % <colortbl>
+ \tabu@colortblalignments % different glues are used
+ \else \tabu@colortblfalse \fi
+ \ifdefined\CT@arc@ \else \let\CT@arc@ \relax \fi
+ \ifdefined\CT@drsc@\else \let\CT@drsc@ \relax \fi
+ \let\tabu@arc@L \CT@arc@ \let\tabu@drsc@L \CT@drsc@
+ \ifodd 1\ifcsname siunitx_table_collect_begin:Nn\endcsname % <siunitx: ok>
+ \expandafter\ifx
+ \csname siunitx_table_collect_begin:Nn\endcsname\relax 0\fi\fi\relax
+ \tabu@siunitxtrue
+ \else \let\tabu@maybesiunitx \@firstofone % <not siunitx: setup>
+ \let\tabu@siunitx \tabu@nosiunitx
+ \tabu@siunitxfalse
+ \fi
+ \ifdefined\adl@array % <arydshln>
+ \else \let\tabu@adl@fix \relax
+ \let\tabu@adl@endtrial \@empty \fi
+ \ifdefined\longtable % <longtable>
+ \else \let\longtabu \tabu@nolongtabu \fi
+ \ifdefined\cellspacetoplimit \tabu@warn@cellspace\fi
+ \csname\ifcsname ifHy@hyperfootnotes\endcsname % <hyperfootnotes>
+ ifHy@hyperfootnotes\else iffalse\fi\endcsname
+ \let\tabu@footnotetext \tabu@Hy@ftntext
+ \let\tabu@xfootnote \tabu@Hy@xfootnote \fi
+ \ifdefined\FV@DefineCheckEnd% <fancyvrb>
+ \tabu@fancyvrb \fi
+ \ifdefined\color % <color / xcolor>
+ \let\tabu@color \color
+ \def\tabu@leavevmodecolor ##1{%
+ \def\tabu@leavevmodecolor {\leavevmode ##1}%
+ }\expandafter\tabu@leavevmodecolor\expandafter{\color}%
+ \else
+ \let\tabu@color \tabu@nocolor
+ \let\tabu@leavevmodecolor \@firstofone \fi
+ \tabu@latextwoe
+ \ifdefined\@raggedtwoe@everyselectfont % <ragged2e>
+ \tabu@raggedtwoe
+ \else
+ \let\tabu@cell@L \tabu@cell@l
+ \let\tabu@cell@R \tabu@cell@r
+ \let\tabu@cell@C \tabu@cell@c
+ \let\tabu@cell@J \tabu@cell@j \fi
+ \expandafter\in@ \expandafter\@arrayright \expandafter{\endarray}%
+ \ifin@ \let\tabu@endarray \endarray
+ \else \tabu@fix@arrayright \fi% <fix for colortbl & arydshln (delarray)>
+ \everyrow{}%
+}% \tabu@AtBeginDocument
+\def\tabu@warn@cellspace{%
+ \PackageWarning{tabu}{%
+ Package cellspace has some limitations
+ \MessageBreak And redefines some macros of array.sty.
+ \MessageBreak Please use \string\tabulinesep\space to control
+ \MessageBreak vertical spacing of lines inside tabu environnement}%
+}% \tabu@warn@cellspace
+%% tabu Package initialisation
+\tabuscantokensfalse
+\let\tabu@arc@G \relax
+\let\tabu@drsc@G \relax
+\let\tabu@evr@G \@empty
+\let\tabu@rc@G \@empty
+\def\tabu@ls@G {\tabu@linestyle@}%
+\let\tabu@@rowfontreset \@empty % <init>
+\let\tabu@@celllalign \@empty
+\let\tabu@@cellralign \@empty
+\let\tabu@@cellleft \@empty
+\let\tabu@@cellright \@empty
+\def\tabu@naturalXmin {\z@}
+\def\tabu@naturalXmax {\z@}
+\let\tabu@rowfontreset \@empty
+\def\tabulineon {4pt}\let\tabulineoff \tabulineon
+\tabu@everyrowtrue
+\ifdefined\pdfelapsedtime % <pdfTeX>
+ \def\tabu@pdftimer {\xdef\tabu@starttime{\the\pdfelapsedtime}}%
+\else \let\tabu@pdftimer \relax \let\tabu@message@etime \relax
+\fi
+\tracingtabu=\z@
+\newtabulinestyle {=\maxdimen}% creates the 'factory' settings \tabu@linestyle@
+\tabulinestyle{}
+\taburowcolors{}
+\let\tabudefaulttarget \linewidth
+\ProcessOptions* % \ProcessOptions* is quicker !
+\endinput
+%%
+%% End of file `tabu.sty'.
diff --git a/templates/xml/compound.xsd b/templates/xml/compound.xsd
index e4ca883..6eb7e0a 100644
--- a/templates/xml/compound.xsd
+++ b/templates/xml/compound.xsd
@@ -232,6 +232,7 @@
<xsd:complexType name="paramType">
<xsd:sequence>
+ <xsd:element name="attributes" minOccurs="0" />
<xsd:element name="type" type="linkedTextType" minOccurs="0" />
<xsd:element name="declname" minOccurs="0" />
<xsd:element name="defname" minOccurs="0" />
@@ -417,15 +418,17 @@
<xsd:element name="superscript" type="docMarkupType" />
<xsd:element name="center" type="docMarkupType" />
<xsd:element name="small" type="docMarkupType" />
+ <xsd:element name="del" type="docMarkupType" />
+ <xsd:element name="inc" type="docMarkupType" />
<xsd:element name="htmlonly" type="docHtmlOnlyType" />
<xsd:element name="manonly" type="xsd:string" />
<xsd:element name="xmlonly" type="xsd:string" />
<xsd:element name="rtfonly" type="xsd:string" />
<xsd:element name="latexonly" type="xsd:string" />
<xsd:element name="image" type="docImageType" />
- <xsd:element name="dot" type="xsd:string" />
- <xsd:element name="msc" type="xsd:string" />
- <xsd:element name="plantuml" type="xsd:string" />
+ <xsd:element name="dot" type="docImageType" />
+ <xsd:element name="msc" type="docImageType" />
+ <xsd:element name="plantuml" type="docImageType" />
<xsd:element name="anchor" type="docAnchorType" />
<xsd:element name="formula" type="docFormulaType" />
<xsd:element name="ref" type="docRefTextType" />
@@ -456,9 +459,9 @@
<xsd:element name="table" type="docTableType" />
<xsd:element name="heading" type="docHeadingType" />
<xsd:element name="image" type="docImageType" />
- <xsd:element name="dotfile" type="docFileType" />
- <xsd:element name="mscfile" type="docFileType" />
- <xsd:element name="diafile" type="docFileType" />
+ <xsd:element name="dotfile" type="docImageType" />
+ <xsd:element name="mscfile" type="docImageType" />
+ <xsd:element name="diafile" type="docImageType" />
<xsd:element name="toclist" type="docTocListType" />
<xsd:element name="language" type="docLanguageType" />
<xsd:element name="parameterlist" type="docParamListType" />
@@ -578,16 +581,12 @@
<xsd:complexType name="docImageType" mixed="true">
<xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
- <xsd:attribute name="type" type="DoxImageKind" />
- <xsd:attribute name="name" type="xsd:string" />
- <xsd:attribute name="width" type="xsd:string" />
- <xsd:attribute name="height" type="xsd:string" />
- <xsd:attribute name="inline" type="DoxBool" />
- </xsd:complexType>
-
- <xsd:complexType name="docFileType" mixed="true">
- <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
- <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="DoxImageKind" use="optional"/>
+ <xsd:attribute name="name" type="xsd:string" use="optional"/>
+ <xsd:attribute name="width" type="xsd:string" use="optional"/>
+ <xsd:attribute name="height" type="xsd:string" use="optional"/>
+ <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+ <xsd:attribute name="caption" type="xsd:string" use="optional"/>
</xsd:complexType>
<xsd:complexType name="docTocItemType" mixed="true">
diff --git a/testing/019/group__g1.xml b/testing/019/group__g1.xml
index d9ea16d..d6807ca 100644
--- a/testing/019/group__g1.xml
+++ b/testing/019/group__g1.xml
@@ -20,9 +20,9 @@
</memberdef>
</sectiondef>
<briefdescription>
+ <para>Text for first group. </para>
</briefdescription>
<detaileddescription>
- <para>Text for first group. </para>
</detaileddescription>
</compounddef>
</doxygen>
diff --git a/testing/019/group__g2.xml b/testing/019/group__g2.xml
index 9b1fc83..3514d89 100644
--- a/testing/019/group__g2.xml
+++ b/testing/019/group__g2.xml
@@ -21,9 +21,9 @@
</memberdef>
</sectiondef>
<briefdescription>
+ <para>Text for second group. </para>
</briefdescription>
<detaileddescription>
- <para>Text for second group. </para>
</detaileddescription>
</compounddef>
</doxygen>
diff --git a/testing/019/group__g3.xml b/testing/019/group__g3.xml
index d9137b0..0f21232 100644
--- a/testing/019/group__g3.xml
+++ b/testing/019/group__g3.xml
@@ -34,9 +34,9 @@
</memberdef>
</sectiondef>
<briefdescription>
+ <para>Text for third group. </para>
</briefdescription>
<detaileddescription>
- <para>Text for third group. </para>
</detaileddescription>
</compounddef>
</doxygen>
diff --git a/testing/021/indexpage.xml b/testing/021/indexpage.xml
index 7c93a78..3ecbd0a 100644
--- a/testing/021/indexpage.xml
+++ b/testing/021/indexpage.xml
@@ -6,7 +6,7 @@
<briefdescription>
</briefdescription>
<detaileddescription>
- <para> Our main function starts like this: <programlisting filename="example_test.cpp"><codeline><highlight class="normal">void<sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline></programlisting> First we create a object <computeroutput>t</computeroutput> of the <ref refid="class_test" kindref="compound">Test</ref> class. <programlisting filename="example_test.cpp"><codeline><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline></programlisting> Then we call the example member function <programlisting filename="example_test.cpp"><codeline><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline></programlisting> After that our little test routine ends. <programlisting filename="example_test.cpp"><codeline><highlight class="normal">}</highlight></codeline></programlisting> </para>
+ <para> Our main function starts like this: <programlisting filename="example_test.cpp"><codeline><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline></programlisting> First we create a object <computeroutput>t</computeroutput> of the <ref refid="class_test" kindref="compound">Test</ref> class. <programlisting filename="example_test.cpp"><codeline><highlight class="normal"><sp/><sp/><ref refid="class_test" kindref="compound">Test</ref><sp/>t;</highlight></codeline></programlisting> Then we call the example member function <programlisting filename="example_test.cpp"><codeline><highlight class="normal"><sp/><sp/>t.<ref refid="class_test_1a47b775f65718978f1ffcd96376f8ecfa" kindref="member">example</ref>();</highlight></codeline></programlisting> After that our little test routine ends. <programlisting filename="example_test.cpp"><codeline><highlight class="normal">}</highlight></codeline></programlisting> </para>
</detaileddescription>
</compounddef>
</doxygen>
diff --git a/testing/071/namespace_a_namespace_1_1_0D0.xml b/testing/071/namespace_a_namespace_1_1_0d0.xml
index 6e42714..14f5a51 100644
--- a/testing/071/namespace_a_namespace_1_1_0D0.xml
+++ b/testing/071/namespace_a_namespace_1_1_0d0.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="">
- <compounddef id="namespace_a_namespace_1_1_0D0" kind="namespace" language="C++">
+ <compounddef id="namespace_a_namespace_1_1_0d0" kind="namespace" language="C++">
<compoundname>ANamespace::@0</compoundname>
<sectiondef kind="enum">
<memberdef kind="enum" id="071__enum__in__anon__ns_8cpp_1a96ab6574751fdf6a53ceec8a3896c45d" prot="public" static="no" strong="yes">
diff --git a/testing/071_enum_in_anon_ns.cpp b/testing/071_enum_in_anon_ns.cpp
index a5b9ac8..8aab15f 100644
--- a/testing/071_enum_in_anon_ns.cpp
+++ b/testing/071_enum_in_anon_ns.cpp
@@ -1,5 +1,5 @@
// objective: test that enum values in anonymous namespaces produce no warning
-// check: namespace_a_namespace_1_1_0D0.xml
+// check: namespace_a_namespace_1_1_0d0.xml
namespace ANamespace { namespace {
diff --git a/testing/086/086__style__tags_8h.xml b/testing/086/086__style__tags_8h.xml
new file mode 100644
index 0000000..a1803da
--- /dev/null
+++ b/testing/086/086__style__tags_8h.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="">
+ <compounddef id="086__style__tags_8h" kind="file" language="C++">
+ <compoundname>086_style_tags.h</compoundname>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ <para>In the following the word tag has the style as indicated before it.<itemizedlist><listitem><para>This is a bold <bold>tag</bold>.</para></listitem><listitem><para>This is a <computeroutput>strong</computeroutput> bold <bold>tag</bold>.</para></listitem><listitem><para>This is an italic <emphasis>tag</emphasis>.</para></listitem><listitem><para>This is an <computeroutput>em</computeroutput> italic <emphasis>tag</emphasis>.</para></listitem><listitem><para>This is a strike through <strike>tag</strike>.</para></listitem><listitem><para>This is an underline <underline>tag</underline>.</para></listitem><listitem><para>This is an insterted <ins>tag</ins>.</para></listitem><listitem><para>This is a deleted <del>tag</del>.</para></listitem><listitem><para>This is a typewriter <computeroutput>tag</computeroutput>. </para></listitem></itemizedlist>
+</para>
+ </detaileddescription>
+ <location file="086_style_tags.h"/>
+ </compounddef>
+</doxygen>
diff --git a/testing/086_style_tags.h b/testing/086_style_tags.h
new file mode 100644
index 0000000..105adca
--- /dev/null
+++ b/testing/086_style_tags.h
@@ -0,0 +1,17 @@
+// objective: test different HTML style tags
+// check: 086__style__tags_8h.xml
+/**
+\file
+
+In the following the word tag has the style as indicated before it.
+- This is a bold <b>tag</b>.
+- This is a `strong` bold <strong>tag</strong>.
+- This is an italic <i>tag</i>.
+- This is an `em` italic <em>tag</em>.
+- This is a strike through <strike>tag</strike>.
+- This is an underline <u>tag</u>.
+- This is an insterted <ins>tag</ins>.
+- This is a deleted <del>tag</del>.
+- This is a typewriter <tt>tag</tt>.
+*/
+
diff --git a/testing/runtests.py b/testing/runtests.py
index fa3c186..fa3c186 100644..100755
--- a/testing/runtests.py
+++ b/testing/runtests.py