Merge branch 'Issue-1632'

* Issue-1632:
  Minor workaround in doxygen_basic_translate_style3 test
  Add new test doxygen_basic_translate_style3.i
  Fix for newline handling in doxygen "///" style comments
diff --git a/.travis.yml b/.travis.yml
index 72ede27..32c6656 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -54,7 +54,12 @@
       dist: xenial
     - compiler: gcc
       os: linux
-      env: SWIGLANG=d
+      env: SWIGLANG=d VER=2.066.0
+      sudo: required
+      dist: xenial
+    - compiler: gcc
+      os: linux
+      env: SWIGLANG=d VER=2.086.1
       sudo: required
       dist: xenial
     - compiler: gcc
@@ -204,6 +209,11 @@
       dist: xenial
     - compiler: gcc
       os: linux
+      env: SWIGLANG=python PY3=3 VER=3.8
+      sudo: required
+      dist: xenial
+    - compiler: gcc
+      os: linux
       env: SWIGLANG=python SWIG_FEATURES=-builtin
       sudo: required
       dist: xenial
@@ -217,7 +227,7 @@
       sudo: required
       dist: xenial
     - os: linux
-      env: SWIGLANG=python SWIG_FEATURES=-builtin GCC=6 CPP11=1 PY3=3 VER=3.7
+      env: SWIGLANG=python SWIG_FEATURES=-builtin GCC=6 CPP11=1 PY3=3 VER=3.8
       sudo: required
       dist: xenial
     - compiler: gcc
@@ -237,12 +247,17 @@
       dist: xenial
     - compiler: gcc
       os: linux
-      env: SWIGLANG=python SWIG_FEATURES="-builtin -O" PY3=3 VER=3.7
+      env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.8
       sudo: required
       dist: xenial
     - compiler: gcc
       os: linux
-      env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.7 SWIGOPTPY3=
+      env: SWIGLANG=python SWIG_FEATURES="-builtin -O" PY3=3 VER=3.8
+      sudo: required
+      dist: xenial
+    - compiler: gcc
+      os: linux
+      env: SWIGLANG=python SWIG_FEATURES=-builtin PY3=3 VER=3.8 SWIGOPTPY3=
       sudo: required
       dist: xenial
     - compiler: gcc
@@ -252,7 +267,7 @@
       dist: xenial
     - compiler: gcc
       os: linux
-      env: SWIGLANG=python SWIG_FEATURES=-O PY3=3 VER=3.7
+      env: SWIGLANG=python SWIG_FEATURES=-O PY3=3 VER=3.8
       sudo: required
       dist: xenial
     - compiler: gcc
@@ -302,6 +317,11 @@
       dist: xenial
     - compiler: gcc
       os: linux
+      env: SWIGLANG=ruby VER=2.7
+      sudo: required
+      dist: xenial
+    - compiler: gcc
+      os: linux
       env: SWIGLANG=scilab
       sudo: required
       dist: xenial
@@ -379,7 +399,7 @@
       sudo: required
       dist: xenial
     - os: linux
-      env: SWIGLANG=python GCC=8 CPP17=1 PY3=3 VER=3.7
+      env: SWIGLANG=python GCC=8 CPP17=1 PY3=3 VER=3.8
       sudo: required
       dist: xenial
     - os: linux
@@ -391,7 +411,7 @@
       sudo: required
       dist: xenial
     - os: linux
-      env: SWIGLANG=python GCC=9 CPP17=1 PY3=3 VER=3.7
+      env: SWIGLANG=python GCC=9 CPP17=1 PY3=3 VER=3.8
       sudo: required
       dist: xenial
     - compiler: gcc
@@ -443,6 +463,12 @@
       osx_image: xcode10.2
 
   allow_failures:
+    # Newer version of D not yet working/supported
+    - compiler: gcc
+      os: linux
+      env: SWIGLANG=d VER=2.086.1
+      sudo: required
+      dist: xenial
     # seg fault in director_basic testcase
     - compiler: gcc
       os: linux
diff --git a/CHANGES.current b/CHANGES.current
index 3e65091..06f214c 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -7,3 +7,48 @@
 Version 4.0.2 (in progress)
 ===========================
 
+
+2020-01-14: mcfarljm
+            #1608 Improve doxygen support.
+            - Add support for \param[] commands such as: \param[in].
+            - Optional arguments are marked as 'optional' in pydoc.
+            - Improve support for \code commands so that other languages are supported as code blocks.
+              Support added for java, c and py.  For example Python: \code{.py} ... \endcode
+            - Fix doxygen handling of \em and \p tags for Python.
+
+2020-01-13: wsfulton
+            [Python] #1595 Python -builtin constructors silently ignored keyword arguments.
+            Instead of silenty ignoring them, now a "TypeError: f() takes no keyword arguments"
+            exception is thrown if keyword arguments are used. Hence constructors and normal methods/
+            functions behave in the same way. Note, -keyword should be used with -builtin to obtain
+            keyword argument support.
+
+2020-01-05: jschueller shadchin
+            [Python] #1670 #1696 Add missing field initializers introduced in python 3.8:
+            tp_vectorcall and tp_print.
+
+2020-01-05: friedrichatgc
+            [Octave] #1688 Change swig_this() to use size_t instead of long for compatibility
+            with Windows 64 bit.
+
+2020-01-05: treitmayr
+            [Ruby] #1692 #1689 Add support for Ruby 2.7
+
+2019-12-30: treitmayr
+            [Ruby] #1653 #1668 Fix code generated when using -globalmodule option.
+
+2019-12-29: ZackerySpytz
+            [OCaml] #1686 Fix compilation errors with OCaml 4.09.0.
+
+2019-12-10: wsfulton
+            #1679 Fix parsing of C++11 identifiers with special meaning (final and override) when
+            they are used as part of the scope name of an identifier, such as a namespace name.
+
+2019-11-26: wsfulton
+            [C#] #1628 'out' or 'ref' used in a cstype typemap was not always stripped out in parts
+            of director code generation.
+
+2019-11-01: wsfulton
+            [Python] #1595 Fix bug in support for keyword arguments (kwargs feature or -keyword)
+            when using -builtin. The fix is in the argument error checking when wrapping zero
+            argument constructors only.
diff --git a/Doc/Manual/CSharp.html b/Doc/Manual/CSharp.html
index 1fc2d21..d041bf5 100644
--- a/Doc/Manual/CSharp.html
+++ b/Doc/Manual/CSharp.html
@@ -66,7 +66,16 @@
 It is also better suited for robust production environments due to the Managed C++ flaw called the
 <a href="https://msdn.microsoft.com/en-us/ie/aa290048(v=vs.94)">Mixed DLL Loading Problem</a>.
 SWIG C# works equally well on non-Microsoft operating systems such as Linux, Solaris and Apple Mac using
-<a href="https://www.mono-project.com/Main_Page/">Mono</a> and <a href="http://www.dotgnu.org/pnet.html">Portable.NET</a>.
+<a href="https://www.mono-project.com/Main_Page/">Mono</a>.
+</p>
+
+<p>
+SWIG 3 and later requires .NET 2.0 at a minimum.
+There are some minor exceptions, where the minimum required is .NET 4.0.
+This is when using the <tt>std::complex</tt> and <tt>std::list</tt> STL containers.
+</p>
+
+<p>
 </p>
 
 <p>
diff --git a/Doc/Manual/Doxygen.html b/Doc/Manual/Doxygen.html
index ff025c0..93e1153 100644
--- a/Doc/Manual/Doxygen.html
+++ b/Doc/Manual/Doxygen.html
@@ -117,14 +117,15 @@
 </pre></div>
 
 <p>
-Also any of the above with '&lt;' added after comment-starting symbol,
-like <i>/**&lt;, /*!&lt;, ///&lt;, </i> or <i> //!&lt;</i> will be
+Also any of the above with '<tt>&lt;</tt>' added after comment-starting symbol,
+like <tt>/**&lt;, /*!&lt;, ///&lt;, </tt> or <tt> //!&lt;</tt> will be
 treated as a post-comment and will be assigned to the code before the
 comment.
 
-Any number of '*' or '/' within a Doxygen comment is considered to be a
-separator and is not included in the final comment, so you may safely use
-comments like <i>/*********/</i> or <i>//////////</i>.
+Any number of '<tt>*</tt>' or '<tt>/</tt>' within a Doxygen comment is
+considered to be a separator and is not included in the final comment,
+so you may safely use comments like <tt>/*********/</tt>
+or <tt>//////////</tt>.
 </p>
 
 <p>
@@ -606,6 +607,10 @@
 <td>translated to {@code ...}</td>
 </tr>
 <tr>
+<td>\code{&lt;ext&gt;}</td>
+<td>translated to {@code ...}; code language extension is ignored</td>
+</tr>
+<tr>
 <td>\cond</td>
 <td>translated to 'Conditional comment: &lt;condition&gt;'</td>
 </tr>
@@ -683,7 +688,7 @@
 </tr>
 <tr>
 <td>\n</td>
-<td>replaced with new line char</td>
+<td>replaced with newline char</td>
 </tr>
 <tr>
 <td>\note</td>
@@ -706,6 +711,10 @@
 <td>translated to @param</td>
 </tr>
 <tr>
+<td>\param[&lt;dir&gt;]</td>
+<td>translated to @param; parameter direction ('in'; 'out'; or 'in,out') is ignored</td>
+</tr>
+<tr>
 <td>\remark</td>
 <td>replaced with 'Remarks:'</td>
 </tr>
@@ -829,155 +838,107 @@
 sense, typically text content).
 Here is the list of these tags:
 </p>
+
 <div class="diagram">
-<table border="0" summary="Unsupported Java Doxygen Tags">
-<tr>
-  <th align="left">Unsupported Doxygen tags</th>
-</tr>
-<tr>
-<td>\addindex</td>
-<td>\addtogroup</td>
-<td>\anchor</td>
-<td>\attention</td>
-</tr>
-<tr>
-<td>\brief</td>
-<td>\bug</td>
-<td>\callgraph</td>
-<td>\callergraph</td>
-</tr>
-<tr>
-<td>\class</td>
-<td>\copybrief</td>
-<td>\copydetails</td>
-<td>\copydoc</td>
-</tr>
-<tr>
-<td>\date</td>
-<td>\def</td>
-<td>\defgroup</td>
-<td>\details</td>
-</tr>
-<tr>
-<td>\dir</td>
-<td>\dontinclude</td>
-<td>\dot</td>
-<td>\dotfile</td>
-</tr>
-<tr>
-<td>\enddot</td>
-<td>\endhtmlonly</td>
-<td>\endinternal</td>
-<td>\endlatexonly</td>
-</tr>
-<tr>
-<td>\endmanonly</td>
-<td>\endmsc</td>
-<td>\endrtfonly</td>
-<td>\endxmlonly</td>
-</tr>
-<tr>
-<td>\enum</td>
-<td>\example</td>
-<td>\extends</td>
-</tr>
-<tr>
-<td>\file</td>
-<td>\fn</td>
-<td>\headerfile</td>
-<td>\hideinitializer</td>
-</tr>
-<tr>
-<td>\htmlinclude</td>
-<td>\htmlonly</td>
-<td>\implements</td>
-<td>\include</td>
-</tr>
-<tr>
-<td>\includelineno</td>
-<td>\ingroup</td>
-<td>\internal</td>
-<td>\invariant</td>
-</tr>
-<tr>
-<td>\interface</td>
-<td>\latexonly</td>
-<td>\line</td>
-<td>\mainpage</td>
-</tr>
-<tr>
-<td>\manonly</td>
-<td>\memberof</td>
-<td>\msc</td>
-<td>\mscfile</td>
-</tr>
-<tr>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-<td>\package</td>
-</tr>
-<tr>
-<td>\page</td>
-<td>\paragraph</td>
-<td>\post</td>
-<td>\pre</td>
-</tr>
-<tr>
-<td>\private</td>
-<td>\privatesection</td>
-<td>\property</td>
-<td>\protected</td>
-</tr>
-<tr>
-<td>\protectedsection</td>
-<td>\protocol</td>
-<td>\public</td>
-<td>\publicsection</td>
-</tr>
-<tr>
-<td>\ref</td>
-<td>\related</td>
-<td>\relates</td>
-<td>\relatedalso</td>
-</tr>
-<tr>
-<td>\relatesalso</td>
-<td>\retval</td>
-<td>\rtfonly</td>
-<td>\section</td>
-</tr>
-<tr>
-<td>\short</td>
-<td>\showinitializer</td>
-<td>\skip</td>
-<td>\skipline</td>
-</tr>
-<tr>
-<td>\snippet</td>
-<td>\struct</td>
-<td>\subpage</td>
-<td>\subsection</td>
-</tr>
-<tr>
-<td>\subsubsection</td>
-<td>\tableofcontents</td>
-<td>\test</td>
-<td>\typedef</td>
-</tr>
-<tr>
-<td>\union</td>
-<td>\until</td>
-<td>\var</td>
-<td>\verbinclude</td>
-</tr>
-<tr>
-<td>\weakgroup</td>
-<td>\xmlonly</td>
-<td>\xrefitem</td>
-<td>\category</td>
-</tr>
-</table>
+  <b>Unsupported Doxygen tags</b>
+
+  <ul style="list-style-type:none;column-count:4;">
+    <li>\addindex</li>
+    <li>\addtogroup</li>
+    <li>\anchor</li>
+    <li>\attention</li>
+    <li>\brief</li>
+    <li>\bug</li>
+    <li>\callergraph</li>
+    <li>\callgraph</li>
+    <li>\category</li>
+    <li>\class</li>
+    <li>\copybrief</li>
+    <li>\copydetails</li>
+    <li>\copydoc</li>
+    <li>\date</li>
+    <li>\def</li>
+    <li>\defgroup</li>
+    <li>\details</li>
+    <li>\dir</li>
+    <li>\dontinclude</li>
+    <li>\dot</li>
+    <li>\dotfile</li>
+    <li>\enddot</li>
+    <li>\endhtmlonly</li>
+    <li>\endinternal</li>
+    <li>\endlatexonly</li>
+    <li>\endmanonly</li>
+    <li>\endmsc</li>
+    <li>\endrtfonly</li>
+    <li>\endxmlonly</li>
+    <li>\enum</li>
+    <li>\example</li>
+    <li>\extends</li>
+    <li>\file</li>
+    <li>\fn</li>
+    <li>\headerfile</li>
+    <li>\hideinitializer</li>
+    <li>\htmlinclude</li>
+    <li>\htmlonly</li>
+    <li>\implements</li>
+    <li>\include</li>
+    <li>\includelineno</li>
+    <li>\ingroup</li>
+    <li>\interface</li>
+    <li>\internal</li>
+    <li>\invariant</li>
+    <li>\latexonly</li>
+    <li>\line</li>
+    <li>\mainpage</li>
+    <li>\manonly</li>
+    <li>\memberof</li>
+    <li>\msc</li>
+    <li>\mscfile</li>
+    <li>\name</li>
+    <li>\namespace</li>
+    <li>\nosubgrouping</li>
+    <li>\package</li>
+    <li>\page</li>
+    <li>\paragraph</li>
+    <li>\post</li>
+    <li>\pre</li>
+    <li>\private</li>
+    <li>\privatesection</li>
+    <li>\property</li>
+    <li>\protected</li>
+    <li>\protectedsection</li>
+    <li>\protocol</li>
+    <li>\public</li>
+    <li>\publicsection</li>
+    <li>\ref</li>
+    <li>\related</li>
+    <li>\relatedalso</li>
+    <li>\relates</li>
+    <li>\relatesalso</li>
+    <li>\retval</li>
+    <li>\rtfonly</li>
+    <li>\section</li>
+    <li>\short</li>
+    <li>\showinitializer</li>
+    <li>\skip</li>
+    <li>\skipline</li>
+    <li>\snippet</li>
+    <li>\struct</li>
+    <li>\subpage</li>
+    <li>\subsection</li>
+    <li>\subsubsection</li>
+    <li>\tableofcontents</li>
+    <li>\test</li>
+    <li>\typedef</li>
+    <li>\union</li>
+    <li>\until</li>
+    <li>\var</li>
+    <li>\verbinclude</li>
+    <li>\weakgroup</li>
+    <li>\xmlonly</li>
+    <li>\xrefitem</li>
+  </ul>
 </div>
 
 <p>
@@ -987,68 +948,47 @@
 <!-- see parser.y, function isStructuralDoxygen() -->
 
 </p>
-<div class="diagram">
-<table border="0" summary="Ignored Java Doxygen Tags">
-<tr>
-  <th align="left">Ignored Doxygen tags</th>
-</tr>
-<tr>
-<td>\addtogroup</td>
-<td>\callgraph</td>
-<td>\callergraph</td>
-<td>\category</td>
-</tr>
-<tr>
-<td>\class</td>
-<td>\def</td>
-<td>\defgroup</td>
-<td>\dir</td>
-</tr>
-<tr>
-<td>\enum</td>
-<td>\example</td>
-<td>\file</td>
-<td>\fn</td>
-</tr>
-<tr>
-<td>\headerfile</td>
-<td>\hideinitializer</td>
-<td>\interface</td>
-<td>\internal</td>
-</tr>
-<tr>
-<td>\mainpage</td>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-</tr>
-<tr>
-<td>\overload</td>
-<td>\package</td>
-<td>\page</td>
-<td>\property</td>
-</tr>
-<tr>
-<td>\protocol</td>
-<td>\relates</td>
-<td>\relatesalso</td>
-<td>\showinitializer</td>
-</tr>
-<tr>
-<td>\struct</td>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-</tr>
-<tr>
-<td>\typedef</td>
-<td>\union</td>
-<td>\var</td>
-<td>\weakgroup</td>
-</tr>
 
-</table>
+<div class="diagram">
+  <b>Ignored Doxygen tags</b>
+
+  <ul style="list-style-type:none;column-count:4;">
+    <li>\addtogroup</li>
+    <li>\callergraph</li>
+    <li>\callgraph</li>
+    <li>\category</li>
+    <li>\class</li>
+    <li>\def</li>
+    <li>\defgroup</li>
+    <li>\dir</li>
+    <li>\enum</li>
+    <li>\example</li>
+    <li>\file</li>
+    <li>\fn</li>
+    <li>\headerfile</li>
+    <li>\hideinitializer</li>
+    <li>\interface</li>
+    <li>\internal</li>
+    <li>\mainpage</li>
+    <li>\name</li>
+    <li>\namespace</li>
+    <li>\nosubgrouping</li>
+    <li>\overload</li>
+    <li>\package</li>
+    <li>\page</li>
+    <li>\property</li>
+    <li>\protocol</li>
+    <li>\relates</li>
+    <li>\relatesalso</li>
+    <li>\showinitializer</li>
+    <li>\struct</li>
+    <li>\typedef</li>
+    <li>\union</li>
+    <li>\var</li>
+    <li>\weakgroup</li>
+  </ul>
 </div>
+  
 
 
 
@@ -1246,11 +1186,11 @@
 </tr>
 <tr>
 <td>\a</td>
-<td>wrapped with '_'</td>
+<td>wrapped with '*'</td>
 </tr>
 <tr>
 <td>\arg</td>
-<td>prepended with ' --'</td>
+<td>prepended with '* '</td>
 </tr>
 <tr>
 <td>\author</td>
@@ -1258,17 +1198,28 @@
 </tr>
 <tr>
 <td>\authors</td>
-<td>prints 'Author:'</td>
+<td>prints 'Authors:'</td>
 </tr>
 <tr>
 <td>\b</td>
-<td>wrapped with '__'</td>
+<td>wrapped with '**'</td>
+</tr>
+<td>\c</td>
+<td>wrapped with '``'</td>
 </tr>
 <tr>
 <td>\cite</td>
 <td>wrapped with single quotes</td>
 </tr>
 <tr>
+<td>\code</td>
+<td>replaced with '.. code-block:: c++'</td>
+</tr>
+<tr>
+<td>\code{&lt;ext&gt;}</td>
+<td>replaced with '.. code-block:: &lt;lang&gt;', where the following doxygen code languages are recognized: .c -&gt; C, .py -&gt; python, .java &gt; java</td>
+</tr>
+<tr>
 <td>\cond</td>
 <td>translated to 'Conditional comment: &lt;condition&gt;'</td>
 </tr>
@@ -1282,7 +1233,7 @@
 </tr>
 <tr>
 <td>\e</td>
-<td>wrapped with '_'</td>
+<td>wrapped with '*'</td>
 </tr>
 <tr>
 <td>\else</td>
@@ -1294,7 +1245,7 @@
 </tr>
 <tr>
 <td>\em</td>
-<td>wrapped with '_'</td>
+<td>wrapped with '*'</td>
 </tr>
 <tr>
 <td>\endcond</td>
@@ -1305,8 +1256,24 @@
 <td>replaced with '}'</td>
 </tr>
 <tr>
+<td>\example</td>
+<td>replaced with 'Example:'</td>
+</tr>
+<tr>
 <td>\exception</td>
-<td>replaced with 'Throws:'</td>
+<td>replaced with ':raises:'</td>
+</tr>
+<tr>
+<td>\f$</td>
+<td>rendered using ':math:``'</td>
+</tr>
+<tr>
+<td>\f[</td>
+<td>rendered using '.. math::'</td>
+</tr>
+<tr>
+<td>\f{</td>
+<td>rendered using '.. math::'</td>
 </tr>
 <tr>
 <td>\if</td>
@@ -1318,11 +1285,11 @@
 </tr>
 <tr>
 <td>\li</td>
-<td>prepended with ' --'</td>
+<td>prepended with '* '</td>
 </tr>
 <tr>
 <td>\n</td>
-<td>replaced with new line char</td>
+<td>replaced with newline char</td>
 </tr>
 <tr>
 <td>\note</td>
@@ -1332,13 +1299,21 @@
 <td>\overload</td>
 <td>prints 'This is an overloaded ...' according to Doxygen docs</td>
 </tr>
+</tr>
+<td>\p</td>
+<td>wrapped with '``'</td>
+</tr>
 <tr>
 <td>\par</td>
 <td>replaced with 'Title: ...'</td>
 </tr>
 <tr>
 <td>\param</td>
-<td>translated to 'Arguments:\n param(type) --description'</td>
+<td>add ':type:' and ':param:' directives</td>
+</tr>
+<tr>
+<td>\param[&lt;dir&gt;]</td>
+<td>same as \param, but direction ('in'; 'out'; 'in,out') is included in ':type:' directive</td>
 </tr>
 <tr>
 <td>\remark</td>
@@ -1350,15 +1325,15 @@
 </tr>
 <tr>
 <td>\result</td>
-<td>replaced with 'Result:'</td>
+<td>add ':rtype:' and ':return:' directives</td>
 </tr>
 <tr>
 <td>\return</td>
-<td>replaced with 'Result:'</td>
+<td>add ':rtype:' and ':return:' directives</td>
 </tr>
 <tr>
 <td>\returns</td>
-<td>replaced with 'Result:'</td>
+<td>add ':rtype:' and ':return:' directives</td>
 </tr>
 <tr>
 <td>\sa</td>
@@ -1374,11 +1349,11 @@
 </tr>
 <tr>
 <td>\throw</td>
-<td>replaced with 'Throws:'</td>
+<td>replaced with ':raises:'</td>
 </tr>
 <tr>
 <td>\throws</td>
-<td>replaced wih 'Throws:'</td>
+<td>replaced wih ':raises:'</td>
 </tr>
 <tr>
 <td>\todo</td>
@@ -1386,7 +1361,11 @@
 </tr>
 <tr>
 <td>\tparam</td>
-<td>translated to 'Arguments:\n param(type) --description'</td>
+<td>add ':type:' and ':param:' directives</td>
+</tr>
+<tr>
+<td>\verbatim</td>
+<td>content copied verbatim</td>
 </tr>
 <tr>
 <td>\version</td>
@@ -1458,177 +1437,109 @@
 sense, typically text content).
 Here is the list of these tags:
 </p>
+
 <div class="diagram">
-<table border="0" summary="Unsupported Python Doxygen Tags">
-<tr>
-  <th align="left">Unsupported Doxygen tags</th>
-</tr>
-<tr>
-<td>\addindex</td>
-<td>\addtogroup</td>
-<td>\anchor</td>
-<td>\attention</td>
-</tr>
-<tr>
-<td>\brief</td>
-<td>\bug</td>
-<td>\callgraph</td>
-<td>\callergraph</td>
-</tr>
-<tr>
-<td>\class</td>
-<td>\copybrief</td>
-<td>\copydetails</td>
-<td>\copydoc</td>
-</tr>
-<tr>
-<td>\date</td>
-<td>\def</td>
-<td>\defgroup</td>
-<td>\details</td>
-</tr>
-<tr>
-<td>\dir</td>
-<td>\dontinclude</td>
-<td>\dot</td>
-<td>\dotfile</td>
-</tr>
-<tr>
-<td>\code</td>
-<td>\endcode</td>
-<td>\endverbatim</td>
-<td>\endlink</td>
-</tr>
-<tr>
-<td>\enddot</td>
-<td>\endhtmlonly</td>
-<td>\endinternal</td>
-<td>\endlatexonly</td>
-</tr>
-<tr>
-<td>\endmanonly</td>
-<td>\endmsc</td>
-<td>\endrtfonly</td>
-<td>\endxmlonly</td>
-</tr>
-<tr>
-<td>\enum</td>
-<td>\example</td>
-<td>\extends</td>
-<td>\f$</td>
-</tr>
-<tr>
-<td>\f[</td>
-<td>\f]</td>
-<td>\f{</td>
-<td>\f}</td>
-</tr>
-<tr>
-<td>\file</td>
-<td>\fn</td>
-<td>\headerfile</td>
-<td>\hideinitializer</td>
-</tr>
-<tr>
-<td>\htmlinclude</td>
-<td>\htmlonly</td>
-<td>\implements</td>
-<td>\include</td>
-</tr>
-<tr>
-<td>\image</td>
-<td>\link</td>
-<td>\verbatim</td>
-<td>\p</td>
-</tr>
-<tr>
-<td>\includelineno</td>
-<td>\ingroup</td>
-<td>\internal</td>
-<td>\invariant</td>
-</tr>
-<tr>
-<td>\interface</td>
-<td>\latexonly</td>
-<td>\line</td>
-<td>\mainpage</td>
-</tr>
-<tr>
-<td>\manonly</td>
-<td>\memberof</td>
-<td>\msc</td>
-<td>\mscfile</td>
-</tr>
-<tr>
-<td>\name</td>
-<td>\namespace</td>
-<td>\nosubgrouping</td>
-<td>\package</td>
-</tr>
-<tr>
-<td>\page</td>
-<td>\paragraph</td>
-<td>\post</td>
-<td>\pre</td>
-</tr>
-<tr>
-<td>\private</td>
-<td>\privatesection</td>
-<td>\property</td>
-<td>\protected</td>
-</tr>
-<tr>
-<td>\protectedsection</td>
-<td>\protocol</td>
-<td>\public</td>
-<td>\publicsection</td>
-</tr>
-<tr>
-<td>\ref</td>
-<td>\related</td>
-<td>\relates</td>
-<td>\relatedalso</td>
-</tr>
-<tr>
-<td>\relatesalso</td>
-<td>\retval</td>
-<td>\rtfonly</td>
-<td>\section</td>
-</tr>
-<tr>
-<td>\short</td>
-<td>\showinitializer</td>
-<td>\skip</td>
-<td>\skipline</td>
-</tr>
-<tr>
-<td>\snippet</td>
-<td>\struct</td>
-<td>\subpage</td>
-<td>\subsection</td>
-</tr>
-<tr>
-<td>\subsubsection</td>
-<td>\tableofcontents</td>
-<td>\test</td>
-<td>\typedef</td>
-</tr>
-<tr>
-<td>\union</td>
-<td>\until</td>
-<td>\var</td>
-<td>\verbinclude</td>
-</tr>
-<tr>
-<td>\weakgroup</td>
-<td>\xmlonly</td>
-<td>\xrefitem</td>
-<td>\category</td>
-</tr>
-<tr>
-<td>\c</td>
-</tr>
-</table>
+  <b>Unsupported Python Doxygen tags</b>
+
+  <ul style="list-style-type:none;column-count:4;">
+    <li>\addindex</li>
+    <li>\addtogroup</li>
+    <li>\anchor</li>
+    <li>\attention</li>
+    <li>\brief</li>
+    <li>\bug</li>
+    <li>\callergraph</li>
+    <li>\callgraph</li>
+    <li>\category</li>
+    <li>\class</li>
+    <li>\copybrief</li>
+    <li>\copydetails</li>
+    <li>\copydoc</li>
+    <li>\date</li>
+    <li>\def</li>
+    <li>\defgroup</li>
+    <li>\details</li>
+    <li>\dir</li>
+    <li>\dontinclude</li>
+    <li>\dot</li>
+    <li>\dotfile</li>
+    <li>\enddot</li>
+    <li>\endhtmlonly</li>
+    <li>\endinternal</li>
+    <li>\endlatexonly</li>
+    <li>\endlink</li>
+    <li>\endmanonly</li>
+    <li>\endmsc</li>
+    <li>\endrtfonly</li>
+    <li>\endxmlonly</li>
+    <li>\enum</li>
+    <li>\extends</li>
+    <li>\file</li>
+    <li>\fn</li>
+    <li>\headerfile</li>
+    <li>\hideinitializer</li>
+    <li>\htmlinclude</li>
+    <li>\htmlonly</li>
+    <li>\image</li>
+    <li>\implements</li>
+    <li>\include</li>
+    <li>\includelineno</li>
+    <li>\ingroup</li>
+    <li>\interface</li>
+    <li>\internal</li>
+    <li>\invariant</li>
+    <li>\latexonly</li>
+    <li>\line</li>
+    <li>\link</li>
+    <li>\mainpage</li>
+    <li>\manonly</li>
+    <li>\memberof</li>
+    <li>\msc</li>
+    <li>\mscfile</li>
+    <li>\name</li>
+    <li>\namespace</li>
+    <li>\nosubgrouping</li>
+    <li>\package</li>
+    <li>\page</li>
+    <li>\paragraph</li>
+    <li>\post</li>
+    <li>\pre</li>
+    <li>\private</li>
+    <li>\privatesection</li>
+    <li>\property</li>
+    <li>\protected</li>
+    <li>\protectedsection</li>
+    <li>\protocol</li>
+    <li>\public</li>
+    <li>\publicsection</li>
+    <li>\ref</li>
+    <li>\related</li>
+    <li>\relatedalso</li>
+    <li>\relates</li>
+    <li>\relatesalso</li>
+    <li>\retval</li>
+    <li>\rtfonly</li>
+    <li>\section</li>
+    <li>\short</li>
+    <li>\showinitializer</li>
+    <li>\skip</li>
+    <li>\skipline</li>
+    <li>\snippet</li>
+    <li>\struct</li>
+    <li>\subpage</li>
+    <li>\subsection</li>
+    <li>\subsubsection</li>
+    <li>\tableofcontents</li>
+    <li>\test</li>
+    <li>\typedef</li>
+    <li>\union</li>
+    <li>\until</li>
+    <li>\var</li>
+    <li>\verbinclude</li>
+    <li>\weakgroup</li>
+    <li>\xmlonly</li>
+    <li>\xrefitem</li>
+  </ul>
 </div>
 
 <H3><a name="Doxygen_python_further_details">17.4.4 Further details</a></H3>
diff --git a/Doc/Manual/Ruby.html b/Doc/Manual/Ruby.html
index 3cfd129..6939a8a 100644
--- a/Doc/Manual/Ruby.html
+++ b/Doc/Manual/Ruby.html
@@ -615,6 +615,24 @@
 effect until it is explicitly disabled using <tt>%mutable</tt>.
 </p>
 
+<p>Note: When SWIG is invoked with the <tt>-globalmodule</tt> option in
+effect, the C/C++ global variables will be translated into Ruby global
+variables. Type-checking and the optional read-only characteristic are
+available in the same way as described above. However the example would
+then have to be modified and executed in the following way:
+
+<div class="code targetlang">
+<pre>$ <b>irb</b>
+irb(main):001:0&gt; <b>require 'Example'</b>
+true
+irb(main):002:0&gt; <b>$variable1 = 2</b>
+2
+irb(main):003:0&gt; <b>$Variable2 = 4 * 10.3</b>
+41.2
+irb(main):004:0&gt; <b>$Variable2</b>
+41.2</pre>
+</div>
+
 <H3><a name="Ruby_nn15">34.3.4 Constants</a></H3>
 
 
diff --git a/Doc/Manual/style.css b/Doc/Manual/style.css
index 45e51e3..ffadb87 100644
--- a/Doc/Manual/style.css
+++ b/Doc/Manual/style.css
@@ -65,6 +65,10 @@
   font-family: "Courier New", Courier, "Courier 10 Pitch", monospace;
 }
 
+div.diagram li {
+    margin-left: 0;
+}
+
 ul li p {
   margin-left: 0;
   margin-right: 0;
diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
index 25a0d8e..43fb45b 100644
--- a/Examples/test-suite/common.mk
+++ b/Examples/test-suite/common.mk
@@ -159,6 +159,7 @@
 	cpp_enum \
 	cpp_namespace \
 	cpp_nodefault \
+	cpp_parameters \
 	cpp_static \
 	cpp_typedef \
 	cpp14_binary_integer_literals \
@@ -250,6 +251,7 @@
 	funcptr_cpp \
 	functors \
 	fvirtual \
+	global_immutable_vars_cpp \
 	global_namespace \
 	global_ns_arg \
 	global_scope_types \
@@ -610,11 +612,14 @@
 #	cpp11_reference_wrapper \     # No typemaps
 
 # Doxygen support test cases: can only be used with languages supporting
-# Doxygen comment translation, currently only Python and Java.
+# Doxygen comment translation (currently Python and Java) and only if not
+# disabled by configure via SKIP_DOXYGEN_TEST_CASES.
+ifneq ($(SKIP_DOXYGEN_TEST_CASES),1)
 python_HAS_DOXYGEN := 1
 java_HAS_DOXYGEN := 1
 
 $(eval HAS_DOXYGEN := $($(LANGUAGE)_HAS_DOXYGEN))
+endif
 
 ifdef HAS_DOXYGEN
 DOXYGEN_TEST_CASES += \
@@ -631,6 +636,7 @@
 	doxygen_translate \
 	doxygen_translate_all_tags \
 	doxygen_translate_links \
+	doxygen_code_blocks \
 
 $(DOXYGEN_TEST_CASES:=.cpptest): SWIGOPT += -doxygen
 
@@ -690,6 +696,7 @@
 	funcptr \
 	function_typedef \
 	global_functions \
+	global_immutable_vars \
 	immutable_values \
 	inctest \
 	infinity \
diff --git a/Examples/test-suite/cpp11_final_override.i b/Examples/test-suite/cpp11_final_override.i
index 8d275b3..c31ae73 100644
--- a/Examples/test-suite/cpp11_final_override.i
+++ b/Examples/test-suite/cpp11_final_override.i
@@ -138,3 +138,31 @@
 DerivedNoVirtualStruct::~DerivedNoVirtualStruct() {}
 %}
 
+%inline %{
+namespace Outer {
+  namespace final {
+    template <typename T> struct smart_ptr {
+      typedef T type;
+    };
+  }
+  namespace override {
+    template <typename T> struct dumb_ptr {
+      typedef T type;
+    };
+  }
+}
+%}
+
+%template(SmartPtrBaseStruct) Outer::final::smart_ptr<DerivedStruct>;
+
+%inline %{
+class ObjectDB
+{
+public:
+  static void smart1(typename Outer::final::smart_ptr<DerivedStruct>::type *objectT) {}
+  static void smart2(Outer::final::smart_ptr<DerivedStruct>::type *objectT) {}
+  static void dumb1(typename Outer::override::dumb_ptr<DerivedStruct>::type *objectT) {}
+  static void dumb2(Outer::override::dumb_ptr<DerivedStruct>::type *objectT) {}
+  static Outer::final::smart_ptr<DerivedStruct>::type get() { return DerivedStruct(); }
+};
+%}
diff --git a/Examples/test-suite/cpp_parameters.i b/Examples/test-suite/cpp_parameters.i
new file mode 100644
index 0000000..e8a4c94
--- /dev/null
+++ b/Examples/test-suite/cpp_parameters.i
@@ -0,0 +1,46 @@
+%module cpp_parameters
+
+%{
+// For Perl
+#ifdef Zero
+#undef Zero
+#endif
+%}
+%inline %{
+
+// Zero arguments
+struct Zero {
+  Zero() {}
+  int zero() { return 0; }
+  static int stat_zero() { return 0; }
+};
+// One mandatory argument
+struct One {
+  One(int a) {}
+  int one(int a) { return a; }
+  static int stat_one(int a) { return a; }
+};
+// Two mandatory arguments
+struct Two {
+  Two(int a, int b) {}
+  int two(int a, int b) { return a + b; }
+  static int stat_two(int a, int b) { return a + b; }
+};
+// Single optional argument
+struct Single {
+  Single(int a=0) {}
+  int single(int a=0) { return a; }
+  static int stat_single(int a=0) { return a; }
+};
+
+int global_zero() { return 0; }
+int global_one(int a) { return a; }
+int global_two(int a, int b) { return a + b; }
+int global_single(int a=0) { return a; }
+
+#ifdef SWIGPYTHON_BUILTIN
+bool is_python_builtin() { return true; }
+#else
+bool is_python_builtin() { return false; }
+#endif
+%}
diff --git a/Examples/test-suite/csharp/Makefile.in b/Examples/test-suite/csharp/Makefile.in
index 8272864..57a81e3 100644
--- a/Examples/test-suite/csharp/Makefile.in
+++ b/Examples/test-suite/csharp/Makefile.in
@@ -16,6 +16,7 @@
 	complextest \
 	csharp_attributes \
 	csharp_swig2_compatibility \
+	csharp_director_typemaps \
 	csharp_exceptions \
 	csharp_features \
 	csharp_lib_arrays \
diff --git a/Examples/test-suite/csharp/csharp_director_typemaps_runme.cs b/Examples/test-suite/csharp/csharp_director_typemaps_runme.cs
new file mode 100644
index 0000000..6143332
--- /dev/null
+++ b/Examples/test-suite/csharp/csharp_director_typemaps_runme.cs
@@ -0,0 +1,53 @@
+
+using System;
+using System.Reflection;
+using csharp_director_typemapsNamespace;
+
+public class csharp_director_typemaps_runme {
+
+  class CSharpDirectorTypemaps_InStreamDerived : InStream
+  {
+    private int constant;
+    public CSharpDirectorTypemaps_InStreamDerived(int constant) { this.constant = constant; }
+    public override int Read(global::System.IntPtr buf, int len, out int readLen) {
+      readLen = (buf == global::System.IntPtr.Zero) ? -len - constant : len + constant;
+      return readLen;
+    }
+    public override int Write(global::System.IntPtr buf, int len, out int writeLen) {
+      writeLen = (buf == global::System.IntPtr.Zero) ? -len - constant : len + constant;
+      return writeLen;
+    }
+  }
+  public static void Main() {
+    int outLen = -1;
+    int k = 100;
+    int j = 23;
+    InStream instream = new CSharpDirectorTypemaps_InStreamDerived(k);
+
+    {
+      int ret = csharp_director_typemaps.callRead(instream, InStream.getCPtr(instream).Handle, j, out outLen);
+      Assert(outLen, j + k);
+      Assert(ret, j + k);
+    }
+    {
+      int ret = csharp_director_typemaps.callRead(instream, global::System.IntPtr.Zero, j, out outLen);
+      Assert(outLen, -j - k);
+      Assert(ret, -j - k);
+    }
+
+    {
+      int ret = csharp_director_typemaps.callWrite(instream, InStream.getCPtr(instream).Handle, j, out outLen);
+      Assert(outLen, j + k);
+      Assert(ret, j + k);
+    }
+    {
+      int ret = csharp_director_typemaps.callWrite(instream, global::System.IntPtr.Zero, j, out outLen);
+      Assert(outLen, -j - k);
+      Assert(ret, -j - k);
+    }
+  }
+  private static void Assert(int i1, int i2) {
+    if (i1 != i2)
+      throw new Exception("assertion failure. " + i1 + " != " + i2);
+  }
+}
diff --git a/Examples/test-suite/csharp_director_typemaps.i b/Examples/test-suite/csharp_director_typemaps.i
new file mode 100644
index 0000000..614bdbf
--- /dev/null
+++ b/Examples/test-suite/csharp_director_typemaps.i
@@ -0,0 +1,37 @@
+%module (directors="1") csharp_director_typemaps
+
+// This tests that the csout typemap is handled correctly in the director code.
+// The 'out' needs stripping in some parts of the generated director code.
+
+%feature("director") InStream;
+
+%apply void *VOID_INT_PTR { void * }
+
+%typemap(ctype)         int* readLen, int* writeLen "/*ctype*/ int*"
+%typemap(imtype)        int* readLen, int* writeLen "/*imtype*/ out int"
+%typemap(cstype)        int* readLen                "/*cstype*/ out int"
+// Note for below: 'out' used in typemap comment
+%typemap(cstype)                      int* writeLen "/*out cstype out*/ out int"
+%typemap(csin)          int* readLen, int* writeLen "/*csin*/ out $csinput"
+%typemap(in)            int* readLen, int* writeLen %{/*in*/  $1 = ($1_ltype)$input; %}
+%typemap(out)           int* readLen, int* writeLen %{/*out*/ $result = (void *)$1; %}
+%typemap(csdirectorin)  int* readLen, int* writeLen "/*csdirectorin*/ out $iminput"
+%typemap(csdirectorout) int* readLen, int* writeLen "/*csdirectorout*/ $cscall"
+%typemap(directorin)    int* readLen, int* writeLen "/*directorin*/ $input = $1;"
+%typemap(directorout)   int* readLen, int* writeLen %{/*directorout*/  $result = ($1_ltype)$input; %}
+
+%inline %{
+class InStream
+{
+public:
+    virtual int Read(void* buf, int len, int* readLen) = 0;
+    virtual int Write(void* buf, int len, int* writeLen) = 0;
+    virtual ~InStream() {}
+};
+int callRead(InStream* stream, void* buf, int len, int* readLen) {
+  return stream->Read(buf, len, readLen);
+}
+int callWrite(InStream* stream, void* buf, int len, int* writeLen) {
+  return stream->Write(buf, len, writeLen);
+}
+%}
diff --git a/Examples/test-suite/doxygen_basic_translate.i b/Examples/test-suite/doxygen_basic_translate.i
index da4d809..232633f 100644
--- a/Examples/test-suite/doxygen_basic_translate.i
+++ b/Examples/test-suite/doxygen_basic_translate.i
@@ -107,6 +107,9 @@
     return 0;
 }
 
+/* Regression test for crash with empty comment: */
+/**/ 
+
 /**
  * Comment at the end of file should be ignored.
  */
diff --git a/Examples/test-suite/doxygen_code_blocks.i b/Examples/test-suite/doxygen_code_blocks.i
new file mode 100644
index 0000000..900e8f9
--- /dev/null
+++ b/Examples/test-suite/doxygen_code_blocks.i
@@ -0,0 +1,62 @@
+%module doxygen_code_blocks
+
+// This test is only used with Python
+
+%inline %{
+
+/**
+ * \brief Test for code blocks
+ *
+ * \code
+ * simple code block
+ * \endcode
+ *
+ * More advanced usage with C++ characters:
+ * \code
+ * std::vector<int> first;                                // empty vector of ints
+ * std::vector<int> second (4,100);                       // four ints with value 100
+ * std::vector<int> third (second.begin(),second.end());  // iterating through second
+ * std::vector<int> fourth (third);                       // a copy of third
+ *  // the iterator constructor can also be used to construct from arrays:
+ * int myints[] = {16,2,77,29};
+ * std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
+ *
+ * std::cout << "The contents of fifth are:";
+ * for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
+ *   std::cout << ' ' << *it;
+ * std::cout << '\n'; 
+ * \endcode
+ *
+ * A code block for C:
+ * \code{.c}
+ * printf("hello world");
+ * \endcode
+ *
+ * A code block for Java:
+ * \code{.java}
+ * public class HelloWorld {
+ *     public static void main(String[] args) {
+ *         // Prints "Hello, World" to the terminal window.
+ *         System.out.println("Hello, World");
+ *     }
+ * }
+ * \endcode
+ * 
+ * A code block for python:
+ * \code{.py}
+ * print('hello world')
+ * \endcode
+ *
+ * A python doctest example:
+ * \code{.py}
+ * >>> 1 + 1
+ * 2
+ * \endcode
+ */
+int function()
+{
+    return 0;
+}  
+
+
+%}
diff --git a/Examples/test-suite/doxygen_translate_all_tags.i b/Examples/test-suite/doxygen_translate_all_tags.i
index 8da683d..6cefd8d 100644
--- a/Examples/test-suite/doxygen_translate_all_tags.i
+++ b/Examples/test-suite/doxygen_translate_all_tags.i
@@ -262,6 +262,9 @@
  * \paragraph someParagraph Paragraph title
  *
  * \param a the first param
+ * \param[in] b parameter with intent(in)
+ * \param[out] c parameter with intent(out)
+ * \param[in,out] d parameter with intent(in,out)
  * 
  * \post Some description
  *
@@ -273,7 +276,7 @@
  *
  * \property someVar
  */
-void func07(int a)
+void func07(int a, int b, int c, int d)
 {
 }
 
diff --git a/Examples/test-suite/global_immutable_vars.i b/Examples/test-suite/global_immutable_vars.i
new file mode 100644
index 0000000..ab0d4f7
--- /dev/null
+++ b/Examples/test-suite/global_immutable_vars.i
@@ -0,0 +1,33 @@
+%module global_immutable_vars
+
+// Test immutable and mutable global variables,
+// see http://www.swig.org/Doc4.0/SWIGDocumentation.html#SWIG_readonly_variables
+
+%inline %{
+  int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+  int global_immutable_var = 41;
+  int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+  int global_mutable_var = 43;
+  int specific_immutable_var = 44;
+
+  int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+    return
+      default_mutable    == default_mutable_var &&
+      global_immutable   == global_immutable_var &&
+      specific_mutable   == specific_mutable_var &&
+      global_mutable     == global_mutable_var &&
+      specific_immutable == specific_immutable_var;
+  }
+%}
+
diff --git a/Examples/test-suite/global_immutable_vars_cpp.i b/Examples/test-suite/global_immutable_vars_cpp.i
new file mode 100644
index 0000000..40cc08e
--- /dev/null
+++ b/Examples/test-suite/global_immutable_vars_cpp.i
@@ -0,0 +1,33 @@
+%module global_immutable_vars_cpp
+
+// Test immutable and mutable global variables,
+// see http://www.swig.org/Doc4.0/SWIGDocumentation.html#SWIG_readonly_variables
+
+%inline %{
+  int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+  int global_immutable_var = 41;
+  int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+  int global_mutable_var = 43;
+  int specific_immutable_var = 44;
+
+  int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+    return
+      default_mutable    == default_mutable_var &&
+      global_immutable   == global_immutable_var &&
+      specific_mutable   == specific_mutable_var &&
+      global_mutable     == global_mutable_var &&
+      specific_immutable == specific_immutable_var;
+  }
+%}
+
diff --git a/Examples/test-suite/java/CommentParser.java b/Examples/test-suite/java/CommentParser.java
index 7dc6d59..1fc6f64 100644
--- a/Examples/test-suite/java/CommentParser.java
+++ b/Examples/test-suite/java/CommentParser.java
@@ -1,5 +1,6 @@
 
-import com.sun.javadoc.*;
+import com.sun.source.doctree.*;
+import com.sun.source.util.DocTrees;
 import java.util.HashMap;
 import java.util.Map.Entry;
 import java.util.Map;
@@ -9,45 +10,120 @@
 import java.io.OutputStreamWriter;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.*;
+import java.util.spi.ToolProvider;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import jdk.javadoc.doclet.*;
 
 
-public class CommentParser {
+public class CommentParser implements Doclet {
     private static Map<String, String> m_parsedComments = new HashMap<String, String>();
 
-    public static boolean start(RootDoc root) {
+    // We need to implement these base class pure virtual methods.
 
+    @Override
+    public void init(Locale locale, Reporter reporter) {
+    }
+
+    @Override
+    public Set<? extends Option> getSupportedOptions() {
+        return new HashSet<>();
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
+    public String getName() {
+        return "CommentParser";
+    }
+
+    // Element name must be the fully qualified name of the element.
+    //
+    // If there is no comment associated with this element, simply do nothing.
+    private void storeCommentFor(DocTrees docTrees, String fullName, Element e) {
+        DocCommentTree docCommentTree = docTrees.getDocCommentTree(e);
+        if (docCommentTree == null)
+            return;
+
+        StringBuilder name = new StringBuilder(fullName);
+
+        // We must use signature in the key for methods for compatibility with
+        // the existing tests and to allow distinguishing between overloaded
+        // methods.
+        if (e instanceof ExecutableElement) {
+            ExecutableElement ex = (ExecutableElement)e;
+            name.append("(");
+
+            boolean firstParam = true;
+            for (VariableElement p : ex.getParameters()) {
+                if (firstParam) {
+                    firstParam = false;
+                } else {
+                    name.append(", ");
+                }
+
+                name.append(p.asType().toString());
+            }
+
+            name.append(")");
+        }
+
+        // For some reason the comment in the source is split into "body" and
+        // "block tags" parts, so we need to concatenate them back together.
+        StringBuilder comment = new StringBuilder();
+        for (DocTree d : docCommentTree.getFullBody()) {
+            comment.append(d.toString());
+            comment.append("\n");
+        }
+
+        boolean firstBlockTag = true;
+        for (DocTree d : docCommentTree.getBlockTags()) {
+            if (firstBlockTag) {
+                firstBlockTag = false;
+                comment.append("\n");
+            }
+
+            comment.append(d.toString());
+            comment.append("\n");
+        }
+
+        m_parsedComments.put(name.toString(), comment.toString());
+    }
+
+    @Override
+    public boolean run(DocletEnvironment docEnv) {
         /*
          * This method is called by 'javadoc' and gets the whole parsed java
          * file, we get comments and store them
          */
+        DocTrees docTrees = docEnv.getDocTrees();
+        for (TypeElement t : ElementFilter.typesIn(docEnv.getIncludedElements())) {
+            String typeName = t.getQualifiedName().toString();
 
-        for (ClassDoc classDoc : root.classes()) {
+            storeCommentFor(docTrees, typeName, t);
 
-            if (classDoc.getRawCommentText().length() > 0)
-                m_parsedComments.put(classDoc.qualifiedName(), classDoc.getRawCommentText());
+            for (Element e : t.getEnclosedElements()) {
+                // Omit the method name for ctors: this is a bit weird, but
+                // this is what the existing tests expect.
+                String fullName = typeName;
+                if (e.getKind() != ElementKind.CONSTRUCTOR) {
+                    fullName = fullName + "." + e.getSimpleName();
+                }
 
-            for (FieldDoc f : classDoc.enumConstants()) {
-                if (f.getRawCommentText().length() > 0)
-                    m_parsedComments.put(f.qualifiedName(), f.getRawCommentText());
-            }
-            for (FieldDoc f : classDoc.fields()) {
-                if (f.getRawCommentText().length() > 0)
-                    m_parsedComments.put(f.qualifiedName(), f.getRawCommentText());
-            }
-            for (ConstructorDoc c : classDoc.constructors()) {
-                if (c.getRawCommentText().length() > 0)
-                    m_parsedComments.put(c.toString(), c.getRawCommentText());
-            }
-            for (MethodDoc m : classDoc.methods()) {
-                if (m.getRawCommentText().length() > 0)
-                    m_parsedComments.put(m.toString(), m.getRawCommentText());
+                storeCommentFor(docTrees, fullName, e);
             }
         }
+
         return true;
     }
 
     
-    public int check(Map<String, String> wantedComments) {
+    public static int check(Map<String, String> wantedComments) {
         int errorCount=0;
         Iterator<Entry<String, String>> it = m_parsedComments.entrySet().iterator();
 
@@ -93,13 +169,14 @@
                 System.out.println("Output is also saved to files '" + expectedFileName +
                                    "' and '" + gotFileName + "'");
                 // here we print original strings, for nicer output
-                System.out.println("\n\n---\nexpected:\n" + wantedComments.get(e.getKey()));
+                System.out.println("\n\n---\nexpected:\n" + wantedStr);
                 System.out.println("\n\n---\ngot:\n" + e.getValue());
 
                 try {
                     // write expected string to file
                     BufferedWriter expectedFile = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(expectedFileName)));
-                    expectedFile.write(wantedComments.get(e.getKey()));
+                    if (wantedStr != null)
+                        expectedFile.write(wantedStr);
                     expectedFile.close();
 
                     // write translated string to file
@@ -130,7 +207,7 @@
     }
 
     
-    private void printKeys(Map<String, String> map) {
+    private static void printKeys(Map<String, String> map) {
         
         Set<String> keys = map.keySet();
         for (String key : keys) {
@@ -154,6 +231,15 @@
         }
     }
 
+    public static void parse(String sourcefile) {
+        ToolProvider javadoc = ToolProvider.findFirst("javadoc").orElseThrow();
+        int result = javadoc.run(System.out, System.err, new String[]{"-quiet", "-doclet", "CommentParser", sourcefile});
+        if (result != 0) {
+          System.err.println("Executing javadoc failed.");
+          System.exit(result);
+        }
+    }
+
     
     public static void main(String argv[]) {
 		
@@ -162,8 +248,7 @@
             System.exit(1);
         }
 		
-        com.sun.tools.javadoc.Main.execute("The comment parser program",
-                                           "CommentParser", new String[]{"-quiet", argv[0]});
+        parse(argv[0]);
 		
         // if we are run as standalone app, print the list of found comments as it would appear in java source
 		
diff --git a/Examples/test-suite/java/Makefile.in b/Examples/test-suite/java/Makefile.in
index 2e788fa..f8e290e 100644
--- a/Examples/test-suite/java/Makefile.in
+++ b/Examples/test-suite/java/Makefile.in
@@ -9,6 +9,7 @@
 JAVA_CLASSPATH_SEP = @JAVA_CLASSPATH_SEP@
 JAVA_TOOLS_JAR     = @JAVA_TOOLS_JAR@
 SCRIPTSUFFIX = _runme.java
+SKIP_DOXYGEN_TEST_CASES = @JAVA_SKIP_DOXYGEN_TEST_CASES@
 
 srcdir       = @srcdir@
 top_srcdir   = ../@top_srcdir@
@@ -108,13 +109,11 @@
 	  mkdir $(JAVA_PACKAGE);							  \
 	fi
 
-# Doxygen test cases need to be compiled together with the CommentParser class
-# which depends on com.sun.javadoc package which is located in this JAR.
+# Doxygen test cases need to be compiled together with the CommentParser class.
 CommentParser.class:
 	$(COMPILETOOL) $(JAVAC) -classpath $(JAVA_CLASSPATH) -d . $(srcdir)/CommentParser.java
 
 JAVA_CLASSPATH := .
-$(DOXYGEN_TEST_CASES:=.cpptest): JAVA_CLASSPATH := "$(JAVA_TOOLS_JAR)$(JAVA_CLASSPATH_SEP)."
 $(DOXYGEN_TEST_CASES:=.cpptest): CommentParser.class
 
 # Compiles java files then runs the testcase. A testcase is only run if
diff --git a/Examples/test-suite/java/director_string_runme.java b/Examples/test-suite/java/director_string_runme.java
index a6ed671..67cb0fe 100644
--- a/Examples/test-suite/java/director_string_runme.java
+++ b/Examples/test-suite/java/director_string_runme.java
@@ -19,7 +19,7 @@
     director_string_A c = new director_string_A("hi");
     for (int i=0; i<3; i++) {
       s = c.call_get(i);
-      if (!s.equals(new Integer(i).toString())) throw new RuntimeException("director_string_A.get(" + i + ") failed. Got:" + s);
+      if (!s.equals(Integer.valueOf(i).toString())) throw new RuntimeException("director_string_A.get(" + i + ") failed. Got:" + s);
     }
 
     director_string_B b = new director_string_B("hello");
@@ -50,7 +50,7 @@
       super(first);
     }
     public String get(int n) {
-      return new Integer(n).toString();
+      return Integer.valueOf(n).toString();
     }
 }
 
diff --git a/Examples/test-suite/java/doxygen_alias_runme.java b/Examples/test-suite/java/doxygen_alias_runme.java
index e21ed6d..98cd977 100644
--- a/Examples/test-suite/java/doxygen_alias_runme.java
+++ b/Examples/test-suite/java/doxygen_alias_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_alias.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_alias_runme {
@@ -15,10 +14,7 @@
 
   public static void main(String argv[])
   {
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_alias runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_alias"});
+    CommentParser.parse("doxygen_alias");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     wantedComments.put("doxygen_alias.doxygen_alias.make_something()",
@@ -27,6 +23,6 @@
       "     @return A new object which may be null.\n" +
       "");
 
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_basic_notranslate_runme.java b/Examples/test-suite/java/doxygen_basic_notranslate_runme.java
index e3d9b02..621cc9e 100644
--- a/Examples/test-suite/java/doxygen_basic_notranslate_runme.java
+++ b/Examples/test-suite/java/doxygen_basic_notranslate_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_basic_notranslate.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_basic_notranslate_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_basic_notranslate runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_basic_notranslate"});
+    CommentParser.parse("doxygen_basic_notranslate");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     wantedComments.put("doxygen_basic_notranslate.doxygen_basic_notranslate.function3(int)",
@@ -97,6 +89,6 @@
     		"");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_basic_translate_runme.java b/Examples/test-suite/java/doxygen_basic_translate_runme.java
index ab343b5..f0b1efb 100644
--- a/Examples/test-suite/java/doxygen_basic_translate_runme.java
+++ b/Examples/test-suite/java/doxygen_basic_translate_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_basic_translate.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_basic_translate_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_basic_translate runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_basic_translate"});
+    CommentParser.parse("doxygen_basic_translate");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -96,6 +88,6 @@
     		"");
 
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java b/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java
index 05e51cf..28cf2da 100644
--- a/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java
+++ b/Examples/test-suite/java/doxygen_basic_translate_style2_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_basic_translate_style2.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_basic_translate_style2_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_basic_translate_style2 runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_basic_translate_style2"});
+    CommentParser.parse("doxygen_basic_translate_style2");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -96,6 +88,6 @@
     		"");
 
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_code_blocks_runme.java b/Examples/test-suite/java/doxygen_code_blocks_runme.java
new file mode 100644
index 0000000..8e8373b
--- /dev/null
+++ b/Examples/test-suite/java/doxygen_code_blocks_runme.java
@@ -0,0 +1,75 @@
+
+import doxygen_code_blocks.*;
+import java.util.HashMap;
+
+public class doxygen_code_blocks_runme {
+  static {
+    try {
+      System.loadLibrary("doxygen_code_blocks");
+    } catch (UnsatisfiedLinkError e) {
+      System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e);
+      System.exit(1);
+    }
+  }
+  
+  public static void main(String argv[]) 
+  {
+    CommentParser.parse("doxygen_code_blocks");
+
+    HashMap<String, String> wantedComments = new HashMap<String, String>();
+    
+    wantedComments.put("doxygen_code_blocks.doxygen_code_blocks.function()",
+		       " Test for code blocks\n \n" +
+		       " \n \n" +
+		       " {@code  \n" +
+		       " simple code block \n" +
+		       " }\n \n" +
+		       " \n \n" +
+		       " More advanced usage with C++ characters:\n \n" +
+		       " {@code  \n" +
+		       " std::vector<int> first;                                // empty vector of ints \n" +
+		       " std::vector<int> second (4,100);                       // four ints with value 100 \n" +
+		       " std::vector<int> third (second.begin(),second.end());  // iterating through second \n" +
+		       " std::vector<int> fourth (third);                       // a copy of third \n" +
+		       " // the iterator constructor can also be used to construct from arrays: \n" +
+		       " int myints[] = {16,2,77,29}; \n" +
+		       " std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) ); \n" +
+		       "  \n" +
+		       " std::cout << \"The contents of fifth are:\"; \n" +
+		       " for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it) \n" +
+		       " std::cout << \' \' << *it; \n" +
+		       " std::cout << \'\\n\';  \n" +
+		       " }\n \n" +
+		       " \n \n" +
+		       " A code block for C:\n \n" +
+		       " {@code  \n" +
+		       " printf(\"hello world\"); \n" +
+		       " }\n \n" +
+		       " \n \n" +
+		       " A code block for Java:\n \n" +
+		       " {@code  \n" +
+		       " public class HelloWorld { \n" +
+		       " public static void main(String[] args) { \n" +
+		       " // Prints \"Hello, World\" to the terminal window. \n" +
+		       " System.out.println(\"Hello, World\"); \n" +
+		       " } \n" +
+		       " } \n" +
+		       " }\n \n" +
+		       " \n \n" +
+		       " A code block for python:\n \n" +
+		       " {@code  \n" +
+		       " print(\'hello world\') \n" +
+		       " }\n \n" +
+		       " \n \n" +
+		       " A python doctest example:\n \n" +
+		       " {@code  \n" +
+		       " >>> 1 + 1 \n" +
+		       " 2 \n" +
+		       " } \n" +
+		       " \n" +
+		       "");
+
+    // and ask the parser to check comments for us
+    System.exit(CommentParser.check(wantedComments));
+  }
+}
diff --git a/Examples/test-suite/java/doxygen_ignore_runme.java b/Examples/test-suite/java/doxygen_ignore_runme.java
index 6250ce5..29b6e06 100644
--- a/Examples/test-suite/java/doxygen_ignore_runme.java
+++ b/Examples/test-suite/java/doxygen_ignore_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_ignore.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_ignore_runme {
@@ -15,10 +14,7 @@
 
   public static void main(String argv[]) 
   {
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_ignore runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_ignore"});
+    CommentParser.parse("doxygen_ignore");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     wantedComments.put("doxygen_ignore.doxygen_ignore.func()",
@@ -39,6 +35,6 @@
       "\n" +
       "");
 
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_misc_constructs_runme.java b/Examples/test-suite/java/doxygen_misc_constructs_runme.java
index 5d95bd5..b1f4e2e 100644
--- a/Examples/test-suite/java/doxygen_misc_constructs_runme.java
+++ b/Examples/test-suite/java/doxygen_misc_constructs_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_misc_constructs.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_misc_constructs_runme {
@@ -15,14 +14,7 @@
 
   public static void main(String argv[])
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_misc_constructs runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_misc_constructs"});
+    CommentParser.parse("doxygen_misc_constructs");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
 
@@ -195,6 +187,6 @@
 
 
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_nested_class_runme.java b/Examples/test-suite/java/doxygen_nested_class_runme.java
index 3ffa796..e9d1a06 100644
--- a/Examples/test-suite/java/doxygen_nested_class_runme.java
+++ b/Examples/test-suite/java/doxygen_nested_class_runme.java
@@ -1,5 +1,4 @@
 import doxygen_nested_class.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_nested_class_runme {
@@ -14,14 +13,7 @@
 
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_nested_class runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_nested_class"});
+    CommentParser.parse("doxygen_nested_class");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -43,6 +35,6 @@
     		" doxShort const variable ");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java
index ef1f06a..6b1e2b0 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_proper_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_parsing_enums_proper.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_parsing_enums_proper_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_proper runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_parsing_enums_proper"});
+    CommentParser.parse("doxygen_parsing_enums_proper");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -61,6 +53,6 @@
     		"Post comment after last comma.");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java
index 85ec0cb..1e0dd74 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_simple_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_parsing_enums_simple.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_parsing_enums_simple_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_simple runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_parsing_enums_simple"});
+    CommentParser.parse("doxygen_parsing_enums_simple");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -53,6 +45,6 @@
     		"Post comment after last comma.");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java
index 4e5f4b4..7cf3b17 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_typesafe_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_parsing_enums_typesafe.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_parsing_enums_typesafe_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_typesafe runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_parsing_enums_typesafe"});
+    CommentParser.parse("doxygen_parsing_enums_typesafe");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -62,6 +54,6 @@
 
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java b/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java
index 4286491..3a41fe5 100644
--- a/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_enums_typeunsafe_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_parsing_enums_typeunsafe.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_parsing_enums_typeunsafe_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_parsing_enums_typeunsafe runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_parsing_enums_typeunsafe"});
+    CommentParser.parse("doxygen_parsing_enums_typeunsafe");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -61,6 +53,6 @@
     		"Post comment after last comma.");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_parsing_runme.java b/Examples/test-suite/java/doxygen_parsing_runme.java
index d58b1f4..10d65fc 100644
--- a/Examples/test-suite/java/doxygen_parsing_runme.java
+++ b/Examples/test-suite/java/doxygen_parsing_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_parsing.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_parsing_runme {
@@ -15,14 +14,7 @@
 
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_parsing runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_parsing"});
+    CommentParser.parse("doxygen_parsing");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -136,6 +128,6 @@
     		"");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_translate_all_tags_runme.java b/Examples/test-suite/java/doxygen_translate_all_tags_runme.java
index d5c533f..fda1fc3 100644
--- a/Examples/test-suite/java/doxygen_translate_all_tags_runme.java
+++ b/Examples/test-suite/java/doxygen_translate_all_tags_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_translate_all_tags.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_translate_all_tags_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_translate_all_tags runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_translate_all_tags"});
+    CommentParser.parse("doxygen_translate_all_tags");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -104,7 +96,7 @@
     		" {@link someMember Some description follows }\n" +
     		" This will only appear in man\n");
     
-    wantedComments.put("doxygen_translate_all_tags.doxygen_translate_all_tags.func07(int)",
+    wantedComments.put("doxygen_translate_all_tags.doxygen_translate_all_tags.func07(int, int, int, int)",
                        " Comment for <b>func07()</b>.\n" +
                        " Note: Here \n" +
     		" is the note! \n" +
@@ -115,7 +107,10 @@
     		" The paragraph text. \n" +
     		" Maybe even multiline \n" +
     		" </p>\n" +
-                " @param a the first param\n");
+                " @param a the first param\n" +
+                " @param b parameter with intent(in)\n" +
+                " @param c parameter with intent(out)\n" +
+		" @param d parameter with intent(in,out)\n");
     
     wantedComments.put("doxygen_translate_all_tags.doxygen_translate_all_tags.func08(int)",
                        "<a id=\"someAnchor\"></a>\n" +
@@ -154,6 +149,6 @@
     		" And here goes simple text \n" +
     		"");
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/java/doxygen_translate_links_runme.java b/Examples/test-suite/java/doxygen_translate_links_runme.java
index 6d74e16..afee4ea 100644
--- a/Examples/test-suite/java/doxygen_translate_links_runme.java
+++ b/Examples/test-suite/java/doxygen_translate_links_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_translate_links.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 
 public class doxygen_translate_links_runme {
@@ -15,14 +14,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_translate_links runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_translate_links"});
+    CommentParser.parse("doxygen_translate_links");
 
     HashMap<String, String> wantedComments = new HashMap<String, String>();
     
@@ -64,6 +56,6 @@
     		"");
     
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
\ No newline at end of file
diff --git a/Examples/test-suite/java/doxygen_translate_runme.java b/Examples/test-suite/java/doxygen_translate_runme.java
index 55e5d23..b049a64 100644
--- a/Examples/test-suite/java/doxygen_translate_runme.java
+++ b/Examples/test-suite/java/doxygen_translate_runme.java
@@ -1,6 +1,5 @@
 
 import doxygen_translate.*;
-import com.sun.javadoc.*;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -16,14 +15,7 @@
   
   public static void main(String argv[]) 
   {
-    /*
-      Here we are using internal javadoc tool, it accepts the name of the class as paramterer,
-      and calls the start() method of that class with parsed information.
-    */
-    CommentParser parser = new CommentParser();
-    com.sun.tools.javadoc.Main.execute("doxygen_translate runtime test",
-                                       "CommentParser",
-                                       new String[]{"-quiet", "doxygen_translate"});
+    CommentParser.parse("doxygen_translate");
 
     Map<String, String> wantedComments = new HashMap<String, String>();
     
@@ -274,6 +266,6 @@
                 "");
         
     // and ask the parser to check comments for us
-    System.exit(parser.check(wantedComments));
+    System.exit(CommentParser.check(wantedComments));
   }
 }
diff --git a/Examples/test-suite/kwargs_feature.i b/Examples/test-suite/kwargs_feature.i
index a8d1c38..2b662ca 100644
--- a/Examples/test-suite/kwargs_feature.i
+++ b/Examples/test-suite/kwargs_feature.i
@@ -100,3 +100,29 @@
 
   int foo_mm(int min = 1, int max = 2) {return min + max; }
 %}
+
+
+// Extended constructors
+%extend Extending0 {
+  Extending0() { return new Extending0(); }
+}
+%extend Extending1 {
+  Extending1(int one) { return new Extending1(); }
+}
+%extend Extending2 {
+  Extending2(int one, const char *two) { return new Extending2(); }
+}
+%extend ExtendingOptArgs1 {
+  ExtendingOptArgs1(int one = 0) { return new ExtendingOptArgs1(); }
+}
+%extend ExtendingOptArgs2 {
+  ExtendingOptArgs2(int one = 0, const char* two = NULL) { return new ExtendingOptArgs2(); }
+}
+
+%inline %{
+struct Extending0 {};
+struct Extending1 {};
+struct Extending2 {};
+struct ExtendingOptArgs1 {};
+struct ExtendingOptArgs2 {};
+%}
diff --git a/Examples/test-suite/python/cpp_parameters_runme.py b/Examples/test-suite/python/cpp_parameters_runme.py
new file mode 100644
index 0000000..99d14ad
--- /dev/null
+++ b/Examples/test-suite/python/cpp_parameters_runme.py
@@ -0,0 +1,296 @@
+from cpp_parameters import *
+
+# Testing correct and incorrect parameter counts being passed (kwargs and non-kwargs)
+# Note that the implementation depends a lot on whether zero, one, two or more args are being wrapped
+
+def is_python_fastproxy():
+    """Return True if SWIG is generating Python code using -fastproxy."""
+    import cpp_parameters
+    # Note: _swig_new_instance_method is only generated when using -fastproxy
+    return hasattr(cpp_parameters, "_swig_new_instance_method")
+
+# Zero parameters expected
+x = Zero()
+try:
+    x = Zero(z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x = Zero(0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    x.zero(z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x.zero(0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    Zero.stat_zero(z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    Zero.stat_zero(0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    global_zero(z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    global_zero(0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+# One mandatory parameter expected
+x = One(1)
+try:
+    x = One(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x = One(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    x.one(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x.one(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    One.stat_one(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    One.stat_one(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    global_one(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    global_one(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+# Two mandatory parameters expected
+x = Two(1, 2)
+try:
+    x = Two(a=1, b=2, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x = Two(1, 2, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    x.two(a=1, b=2, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x.two(1, 2, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    Two.stat_two(a=1, b=2, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    Two.stat_two(1, 2, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    global_two(a=1, b=2, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    global_two(1, 2, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+# Single optional parameter expected
+x = Single(1)
+try:
+    x = Single(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x = Single(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    x.single(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    x.single(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    Single.stat_single(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    Single.stat_single(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+try:
+    global_single(a=1, z=0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+try:
+    global_single(1, 0)
+    raise RuntimeError("Missed throw")
+except TypeError:
+    pass
+
+# Test that -builtin option throws TypeError if kwargs are used even when they look like they should work, kwargs are not supported unless using -keyword.
+# Also same for -fastproxy option except that kwargs are supported by default for constructors. TODO: Fix inconsistency.
+
+if is_python_builtin() or is_python_fastproxy():
+    # One mandatory parameter in API
+    x = One(1)
+    if is_python_fastproxy():
+        x = One(a=1)
+    else:
+        try:
+            x = One(a=1)
+            raise RuntimeError("Missed throw")
+        except TypeError:
+            pass
+    try:
+        x.one(a=1)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+    try:
+        One.stat_one(a=1)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+    try:
+        global_one(a=1)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+
+    # Two mandatory parameters in API
+    x = Two(1, 2)
+    if is_python_fastproxy():
+        x = Two(a=1, b=2)
+    else:
+        try:
+            x = Two(a=1, b=2)
+            raise RuntimeError("Missed throw")
+        except TypeError:
+            pass
+    try:
+        x.two(a=1, b=2)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+    try:
+        Two.stat_two(a=1, b=2)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+    try:
+        global_two(a=1, b=2)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+
+    # Single optional parameter in API
+    x = Single(1)
+    if is_python_fastproxy():
+        x = Single(a=1)
+    else:
+        try:
+            x = Single(a=1)
+            raise RuntimeError("Missed throw")
+        except TypeError:
+            pass
+    try:
+        x.single(a=1)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+    try:
+        Single.stat_single(a=1)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+    try:
+        global_single(a=1)
+        raise RuntimeError("Missed throw")
+    except TypeError:
+        pass
+
+else:
+    # Non-builtin should work as expected
+    # One mandatory parameter in API
+    x = One(a=1)
+    x.one(a=1)
+    One.stat_one(a=1)
+    global_one(a=1)
+
+    # Two mandatory parameters in API
+    x = Two(a=1, b=2)
+    x.two(a=1, b=2)
+    Two.stat_two(a=1, b=2)
+    global_two(a=1, b=2)
+
+    # Single optional parameter in API
+    x = Single(a=1)
+    x.single(a=1)
+    Single.stat_single(a=1)
+    global_single(a=1)
diff --git a/Examples/test-suite/python/doxygen_basic_translate_runme.py b/Examples/test-suite/python/doxygen_basic_translate_runme.py
index 9ef8dbd..90edda1 100644
--- a/Examples/test-suite/python/doxygen_basic_translate_runme.py
+++ b/Examples/test-suite/python/doxygen_basic_translate_runme.py
@@ -60,7 +60,7 @@
 comment_verifier.check(inspect.getdoc(doxygen_basic_translate.function6),
     """\
 Test for default args
-:type a: int
+:type a: int, optional
 :param a: Some parameter, default is 42"""
 )
 comment_verifier.check(inspect.getdoc(doxygen_basic_translate.function7),
diff --git a/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py b/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py
index b75045d..a24f5de 100644
--- a/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py
+++ b/Examples/test-suite/python/doxygen_basic_translate_style2_runme.py
@@ -58,7 +58,7 @@
 comment_verifier.check(inspect.getdoc(doxygen_basic_translate_style2.function6),
     """\
 Test for default args
-:type a: int
+:type a: int, optional
 :param a: Some parameter, default is 42"""
 )
 comment_verifier.check(inspect.getdoc(doxygen_basic_translate_style2.function7),
diff --git a/Examples/test-suite/python/doxygen_code_blocks_runme.py b/Examples/test-suite/python/doxygen_code_blocks_runme.py
new file mode 100644
index 0000000..46a0a3d
--- /dev/null
+++ b/Examples/test-suite/python/doxygen_code_blocks_runme.py
@@ -0,0 +1,58 @@
+import doxygen_code_blocks
+import inspect
+import string
+import sys
+import comment_verifier
+
+comment_verifier.check(inspect.getdoc(doxygen_code_blocks.function),
+    """\
+Test for code blocks
+
+.. code-block:: c++
+
+    simple code block
+
+More advanced usage with C++ characters:
+
+.. code-block:: c++
+
+    std::vector<int> first;                                // empty vector of ints
+    std::vector<int> second (4,100);                       // four ints with value 100
+    std::vector<int> third (second.begin(),second.end());  // iterating through second
+    std::vector<int> fourth (third);                       // a copy of third
+     // the iterator constructor can also be used to construct from arrays:
+    int myints[] = {16,2,77,29};
+    std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
+
+    std::cout << "The contents of fifth are:";
+    for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
+      std::cout << ' ' << *it;
+    std::cout << '\\n';
+
+A code block for C:
+
+.. code-block:: c
+
+    printf("hello world");
+
+A code block for Java:
+
+.. code-block:: java
+
+    public class HelloWorld {
+        public static void main(String[] args) {
+            // Prints "Hello, World" to the terminal window.
+            System.out.println("Hello, World");
+        }
+    }
+
+A code block for python:
+
+.. code-block:: python
+
+    print('hello world')
+
+A python doctest example:
+
+>>> 1 + 1
+2""")
diff --git a/Examples/test-suite/python/doxygen_misc_constructs_runme.py b/Examples/test-suite/python/doxygen_misc_constructs_runme.py
index 11aa53b..c0b5c16 100644
--- a/Examples/test-suite/python/doxygen_misc_constructs_runme.py
+++ b/Examples/test-suite/python/doxygen_misc_constructs_runme.py
@@ -12,7 +12,7 @@
 :param fileName: name of the file, where the source line is located
 :type line: int
 :param line: line number
-:type isGetSize: boolean
+:type isGetSize: boolean, optional
 :param isGetSize: if set, for every object location both address and size are returned
 
 Connection::getId() """)
diff --git a/Examples/test-suite/python/doxygen_translate_all_tags_runme.py b/Examples/test-suite/python/doxygen_translate_all_tags_runme.py
index df1c0eb..2b5b3b8 100644
--- a/Examples/test-suite/python/doxygen_translate_all_tags_runme.py
+++ b/Examples/test-suite/python/doxygen_translate_all_tags_runme.py
@@ -82,7 +82,7 @@
 
 *italicword*
 
-emphazedWord
+*emphazedWord*
 
 
 
@@ -196,7 +196,7 @@
 This is an overloaded member function, provided for convenience.
 It differs from the above function only in what argument(s) it accepts.
 
-someword
+``someword``
 
 
 
@@ -209,7 +209,13 @@
 
 
 :type a: int
-:param a: the first param""")
+:param a: the first param
+:type b: int, in
+:param b: parameter with intent(in)
+:type c: int, out
+:param c: parameter with intent(out)
+:type d: int, in/out
+:param d: parameter with intent(in,out)""")
 
 comment_verifier.check(inspect.getdoc(doxygen_translate_all_tags.func08),
 r"""Text after anchor.
diff --git a/Examples/test-suite/python/doxygen_translate_runme.py b/Examples/test-suite/python/doxygen_translate_runme.py
index d698ba8..38dca2e 100644
--- a/Examples/test-suite/python/doxygen_translate_runme.py
+++ b/Examples/test-suite/python/doxygen_translate_runme.py
@@ -80,7 +80,7 @@
 This is an overloaded member function, provided for convenience.
 It differs from the above function only in what argument(s) it accepts.
 
-someword
+``someword``
 
 
 
diff --git a/Examples/test-suite/python/kwargs_feature_runme.py b/Examples/test-suite/python/kwargs_feature_runme.py
index a2d4731..31d49d2 100644
--- a/Examples/test-suite/python/kwargs_feature_runme.py
+++ b/Examples/test-suite/python/kwargs_feature_runme.py
@@ -79,3 +79,46 @@
 
 if rfoo(x=11, n=22) != 11:
     raise RuntimeError
+
+# Extended constructors
+e = Extending0()
+e = Extending1(one=1)
+e = Extending1(1)
+e = Extending2(1, "two")
+e = Extending2(1, two="two")
+e = Extending2(two="two", one=1)
+e = ExtendingOptArgs1()
+e = ExtendingOptArgs1(1)
+e = ExtendingOptArgs2(one=1)
+e = ExtendingOptArgs2()
+e = ExtendingOptArgs2(one=1)
+e = ExtendingOptArgs2(two="two")
+e = ExtendingOptArgs2(two="two", one=1)
+
+# Invalid kwargs test
+h = Hello()
+try:
+    h = Hello(nonexistent=10)
+    raise RuntimeError("missed exception")
+except TypeError as e:
+    pass
+
+f = Foo(1)
+f = Foo(a=1)
+try:
+    f = Foo(nonexistent=10)
+    raise RuntimeError("missed exception")
+except TypeError as e:
+    pass
+
+try:
+    f = Foo(a=1, nonexistent=10)
+    raise RuntimeError("missed exception")
+except TypeError as e:
+    pass
+
+try:
+    f = Foo(1, nonexistent=10)
+    raise RuntimeError("missed exception")
+except TypeError as e:
+    pass
diff --git a/Examples/test-suite/ruby/Makefile.in b/Examples/test-suite/ruby/Makefile.in
index d75cdb0..2c59029 100644
--- a/Examples/test-suite/ruby/Makefile.in
+++ b/Examples/test-suite/ruby/Makefile.in
@@ -23,6 +23,7 @@
 	li_std_wstring_inherit \
 	primitive_types \
 	ruby_alias_method \
+	ruby_global_immutable_vars_cpp \
 	ruby_keywords \
 	ruby_minherit_shared_ptr \
 	ruby_naming \
@@ -48,6 +49,7 @@
 	li_cstring \
 	ruby_alias_global_function \
 	ruby_alias_module_function \
+	ruby_global_immutable_vars \
 	ruby_manual_proxy \
 
 include $(srcdir)/../common.mk
@@ -57,6 +59,8 @@
 
 # Custom tests - tests with additional commandline options
 ruby_alias_global_function.ctest: SWIGOPT += -globalmodule
+ruby_global_immutable_vars.ctest: SWIGOPT += -globalmodule
+ruby_global_immutable_vars_cpp.cpptest: SWIGOPT += -globalmodule
 ruby_naming.cpptest: SWIGOPT += -autorename
 
 # Rules for the different types of tests
diff --git a/Examples/test-suite/ruby/global_immutable_vars_cpp_runme.rb b/Examples/test-suite/ruby/global_immutable_vars_cpp_runme.rb
new file mode 100644
index 0000000..7897f7d
--- /dev/null
+++ b/Examples/test-suite/ruby/global_immutable_vars_cpp_runme.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/env ruby
+#
+# C++ version of global_immutable_vars_runme.rb
+#
+
+require 'swig_assert'
+
+require 'global_immutable_vars_cpp'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+Global_immutable_vars_cpp::default_mutable_var == 40
+Global_immutable_vars_cpp::global_immutable_var == 41
+Global_immutable_vars_cpp::specific_mutable_var == 42
+Global_immutable_vars_cpp::global_mutable_var == 43
+Global_immutable_vars_cpp::specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+Global_immutable_vars_cpp::default_mutable_var = 80
+Global_immutable_vars_cpp::default_mutable_var == 80
+Global_immutable_vars_cpp::specific_mutable_var = 82
+Global_immutable_vars_cpp::specific_mutable_var == 82
+Global_immutable_vars_cpp::global_mutable_var = 83
+Global_immutable_vars_cpp::global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+  Global_immutable_vars_cpp::global_immutable_var = 81
+rescue NoMethodError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "Global_immutable_vars_cpp::global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+  Global_immutable_vars_cpp::specific_immutable_var = 81
+rescue NoMethodError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "Global_immutable_vars_cpp::specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(Global_immutable_vars_cpp::check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby/global_immutable_vars_runme.rb b/Examples/test-suite/ruby/global_immutable_vars_runme.rb
new file mode 100644
index 0000000..ffbea27
--- /dev/null
+++ b/Examples/test-suite/ruby/global_immutable_vars_runme.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+#
+# Here the proper generation of mutable and immutable variables is tested
+# in the target language.
+# Immutable variables do not have "<var>=" methods generated by SWIG,
+# therefore trying to assign these variables shall throw a NoMethodError
+# exception.
+#
+
+require 'swig_assert'
+
+require 'global_immutable_vars'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+Global_immutable_vars::default_mutable_var == 40
+Global_immutable_vars::global_immutable_var == 41
+Global_immutable_vars::specific_mutable_var == 42
+Global_immutable_vars::global_mutable_var == 43
+Global_immutable_vars::specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+Global_immutable_vars::default_mutable_var = 80
+Global_immutable_vars::default_mutable_var == 80
+Global_immutable_vars::specific_mutable_var = 82
+Global_immutable_vars::specific_mutable_var == 82
+Global_immutable_vars::global_mutable_var = 83
+Global_immutable_vars::global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+  Global_immutable_vars::global_immutable_var = 81
+rescue NoMethodError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "Global_immutable_vars::global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+  Global_immutable_vars::specific_immutable_var = 81
+rescue NoMethodError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "Global_immutable_vars::specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(Global_immutable_vars::check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby/ruby_global_immutable_vars_cpp_runme.rb b/Examples/test-suite/ruby/ruby_global_immutable_vars_cpp_runme.rb
new file mode 100644
index 0000000..5523b59
--- /dev/null
+++ b/Examples/test-suite/ruby/ruby_global_immutable_vars_cpp_runme.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/env ruby
+#
+# C++ version of ruby_global_immutable_vars_runme.rb.
+#
+
+require 'swig_assert'
+
+require 'ruby_global_immutable_vars_cpp'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+$default_mutable_var == 40
+$global_immutable_var == 41
+$specific_mutable_var == 42
+$global_mutable_var == 43
+$specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+$default_mutable_var = 80
+$default_mutable_var == 80
+$specific_mutable_var = 82
+$specific_mutable_var == 82
+$global_mutable_var = 83
+$global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+  $global_immutable_var = 81
+rescue NameError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "$global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+  $specific_immutable_var = 81
+rescue NameError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "$specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby/ruby_global_immutable_vars_runme.rb b/Examples/test-suite/ruby/ruby_global_immutable_vars_runme.rb
new file mode 100644
index 0000000..45a8506
--- /dev/null
+++ b/Examples/test-suite/ruby/ruby_global_immutable_vars_runme.rb
@@ -0,0 +1,52 @@
+#!/usr/bin/env ruby
+#
+# This test program is similar to global_immutable_vars_runme.rb
+# with the difference that the global variables to check are also
+# Ruby global variables (SWIG Ruby option "-globalmodule").
+#
+# Immutable global variables shall throw a NameError exception.
+#
+
+require 'swig_assert'
+
+require 'ruby_global_immutable_vars'
+
+# first check if all variables can be read
+swig_assert_each_line( <<EOF )
+$default_mutable_var == 40
+$global_immutable_var == 41
+$specific_mutable_var == 42
+$global_mutable_var == 43
+$specific_immutable_var == 44
+EOF
+
+# check that all mutable variables can be modified
+swig_assert_each_line( <<EOF )
+$default_mutable_var = 80
+$default_mutable_var == 80
+$specific_mutable_var = 82
+$specific_mutable_var == 82
+$global_mutable_var = 83
+$global_mutable_var == 83
+EOF
+
+# now check that immutable variables cannot be modified
+had_exception = false
+begin
+  $global_immutable_var = 81
+rescue NameError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "$global_immutable_var is writable (expected to be immutable)")
+
+had_exception = false
+begin
+  $specific_immutable_var = 81
+rescue NameError => e
+  had_exception = true
+end
+swig_assert(had_exception, nil,
+            "$specific_immutable_var is writable (expected to be immutable)")
+
+swig_assert(check_values(80, 41, 82, 83, 44) == 1, nil, "Check values failed")
diff --git a/Examples/test-suite/ruby_global_immutable_vars.i b/Examples/test-suite/ruby_global_immutable_vars.i
new file mode 100644
index 0000000..6f067d2
--- /dev/null
+++ b/Examples/test-suite/ruby_global_immutable_vars.i
@@ -0,0 +1,34 @@
+%module ruby_global_immutable_vars
+
+// This copy of global_immutable_vars.i shall be compiled with the
+// SWIG Ruby option "-globalmodule" in order to check the code path
+// for registering global methods (in contrast to module methods).
+
+%inline %{
+  int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+  int global_immutable_var = 41;
+  int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+  int global_mutable_var = 43;
+  int specific_immutable_var = 44;
+
+  int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+    return
+      default_mutable    == default_mutable_var &&
+      global_immutable   == global_immutable_var &&
+      specific_mutable   == specific_mutable_var &&
+      global_mutable     == global_mutable_var &&
+      specific_immutable == specific_immutable_var;
+  }
+%}
+
diff --git a/Examples/test-suite/ruby_global_immutable_vars_cpp.i b/Examples/test-suite/ruby_global_immutable_vars_cpp.i
new file mode 100644
index 0000000..511390e
--- /dev/null
+++ b/Examples/test-suite/ruby_global_immutable_vars_cpp.i
@@ -0,0 +1,32 @@
+%module ruby_global_immutable_vars_cpp
+
+// C++ version of ruby_global_immutable_vars.i
+
+%inline %{
+  int default_mutable_var = 40;
+%}
+
+%immutable;
+%feature("immutable", "0") specific_mutable_var;
+
+%inline %{
+  int global_immutable_var = 41;
+  int specific_mutable_var = 42;
+%}
+
+%mutable;
+%immutable specific_immutable_var;
+%inline %{
+  int global_mutable_var = 43;
+  int specific_immutable_var = 44;
+
+  int check_values(int default_mutable, int global_immutable, int specific_mutable, int global_mutable, int specific_immutable) {
+    return
+      default_mutable    == default_mutable_var &&
+      global_immutable   == global_immutable_var &&
+      specific_mutable   == specific_mutable_var &&
+      global_mutable     == global_mutable_var &&
+      specific_immutable == specific_immutable_var;
+  }
+%}
+
diff --git a/Lib/ocaml/carray.i b/Lib/ocaml/carray.i
index 5e74c3d..4378f73 100644
--- a/Lib/ocaml/carray.i
+++ b/Lib/ocaml/carray.i
@@ -77,7 +77,7 @@
 
 %typemap(out) SWIGTYPE [] {
     int i;
-    CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
+    const CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
     $result = caml_array_new($1_dim0);
 
     for( i = 0; i < $1_dim0; i++ ) {
diff --git a/Lib/ocaml/ocaml.swg b/Lib/ocaml/ocaml.swg
index ac496bd..afb01da 100644
--- a/Lib/ocaml/ocaml.swg
+++ b/Lib/ocaml/ocaml.swg
@@ -62,7 +62,7 @@
 
 #if 0
 %typemap(argout) SWIGTYPE & {
-    CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
+    const CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
     if( fromval ) {
 	swig_result =
 	    caml_list_append(swig_result,
@@ -75,7 +75,7 @@
     }
 }
 %typemap(argout) SWIGTYPE && {
-    CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
+    const CAML_VALUE *fromval = caml_named_value("create_$ntype_from_ptr");
     if( fromval ) {
 	swig_result =
 	    caml_list_append(swig_result,
diff --git a/Lib/ocaml/ocamlrun.swg b/Lib/ocaml/ocamlrun.swg
index 3d552cc..5a923c5 100644
--- a/Lib/ocaml/ocamlrun.swg
+++ b/Lib/ocaml/ocamlrun.swg
@@ -407,7 +407,7 @@
 	    CAMLreturn((long)SWIG_Int64_val(SWIG_Field(SWIG_Field(v,0),0)));
 	case C_enum: {
 	    SWIG_CAMLlocal1(ret);
-	    CAML_VALUE *enum_to_int = caml_named_value(SWIG_MODULE "_enum_to_int");
+	    const CAML_VALUE *enum_to_int = caml_named_value(SWIG_MODULE "_enum_to_int");
 	    if( !name ) caml_failwith( "Not an enum conversion" );
 	    ret = caml_callback2(*enum_to_int,*caml_named_value(name),v);
 	    CAMLreturn(caml_long_val(ret));
@@ -451,7 +451,7 @@
 	CAMLparam1(v);
 	void *outptr = NULL;
         swig_type_info *outdescr = NULL;
-        static CAML_VALUE *func_val = NULL;
+        static const CAML_VALUE *func_val = NULL;
 
 	if( v == Val_unit ) {
 	    *out = 0;
@@ -574,7 +574,7 @@
         CAMLparam0();
         SWIG_CAMLlocal1(result);
 
-        CAML_VALUE *fromval = caml_named_value(name);
+        const CAML_VALUE *fromval = caml_named_value(name);
         if (fromval) {
             result = caml_callback(*fromval, caml_val_ptr(ptr, descriptor));
         } else {
diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg
index ff614e6..325a4cc 100644
--- a/Lib/octave/octrun.swg
+++ b/Lib/octave/octrun.swg
@@ -507,10 +507,10 @@
 	delete this;
     }
 
-    long swig_this() const {
+    size_t swig_this() const {
       if (!types.size())
-	return (long) this;
-      return (long) types[0].second.ptr;
+	return (size_t) this;
+      return (size_t) types[0].second.ptr;
     }
     const char* help_text() const {
       if (!types.size())
diff --git a/Lib/python/builtin.swg b/Lib/python/builtin.swg
index 28051e6..5308748 100644
--- a/Lib/python/builtin.swg
+++ b/Lib/python/builtin.swg
@@ -256,6 +256,12 @@
 #if PY_VERSION_HEX >= 0x03040000
       0,                                        /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                        /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                        /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                        /* tp_allocs */
       0,                                        /* tp_frees */
@@ -334,6 +340,12 @@
 #if PY_VERSION_HEX >= 0x03040000
       0,                                        /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                        /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                        /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                        /* tp_allocs */
       0,                                        /* tp_frees */
diff --git a/Lib/python/pyinit.swg b/Lib/python/pyinit.swg
index dfbf40b..a6d609d 100644
--- a/Lib/python/pyinit.swg
+++ b/Lib/python/pyinit.swg
@@ -186,6 +186,12 @@
 #if PY_VERSION_HEX >= 0x03040000
       0,                                  /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                  /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                  /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                  /* tp_allocs */
       0,                                  /* tp_frees */
diff --git a/Lib/python/pyrun.swg b/Lib/python/pyrun.swg
index 82859b8..d6eeda9 100644
--- a/Lib/python/pyrun.swg
+++ b/Lib/python/pyrun.swg
@@ -183,6 +183,19 @@
   }
 }
 
+SWIGINTERN int
+SWIG_Python_CheckNoKeywords(PyObject *kwargs, const char *name) {
+  int no_kwargs = 1;
+  if (kwargs) {
+    assert(PyDict_Check(kwargs));
+    if (PyDict_Size(kwargs) > 0) {
+      PyErr_Format(PyExc_TypeError, "%s() does not take keyword arguments", name);
+      no_kwargs = 0;
+    }
+  }
+  return no_kwargs;
+}
+
 /* A functor is a function object with one single object argument */
 #define SWIG_Python_CallFunctor(functor, obj)	        PyObject_CallFunctionObjArgs(functor, obj, NULL);
 
@@ -696,6 +709,12 @@
 #if PY_VERSION_HEX >= 0x03040000
       0,                                    /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                    /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                    /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                    /* tp_allocs */
       0,                                    /* tp_frees */
@@ -857,6 +876,12 @@
 #if PY_VERSION_HEX >= 0x03040000
       0,                                    /* tp_finalize */
 #endif
+#if PY_VERSION_HEX >= 0x03080000
+      0,                                    /* tp_vectorcall */
+#endif
+#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)
+      0,                                    /* tp_print */
+#endif
 #ifdef COUNT_ALLOCS
       0,                                    /* tp_allocs */
       0,                                    /* tp_frees */
diff --git a/Lib/ruby/rubyclasses.swg b/Lib/ruby/rubyclasses.swg
index f7b51bd..b345fce 100644
--- a/Lib/ruby/rubyclasses.swg
+++ b/Lib/ruby/rubyclasses.swg
@@ -174,7 +174,7 @@
       return rb_inspect(_obj);
     }
 
-    static VALUE swig_rescue_swallow(VALUE)
+    static VALUE swig_rescue_swallow(VALUE, VALUE)
     {
       /*
       VALUE errstr = rb_obj_as_string(rb_errinfo());
@@ -203,8 +203,8 @@
         args.id     = op_id;
         args.nargs  = 1;
         args.target = VALUE(other);
-        ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
-                       (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
+        ret = rb_rescue(VALUEFUNC(swig_rescue_funcall), VALUE(&args),
+                       (VALUEFUNC(swig_rescue_swallow)), Qnil);
       }
       if (ret == Qnil) {
         VALUE a = rb_funcall(         _obj, hash_id, 0 );
@@ -243,8 +243,8 @@
       args.id     = op_id;
       args.nargs  = 0;
       args.target = Qnil;
-      ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
-                     (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
+      ret = rb_rescue(VALUEFUNC(swig_rescue_funcall), VALUE(&args),
+                     (VALUEFUNC(swig_rescue_swallow)), Qnil);
       SWIG_RUBY_THREAD_END_BLOCK;
       return ret;
     }
@@ -262,8 +262,8 @@
       args.id     = op_id;
       args.nargs  = 1;
       args.target = VALUE(other);
-      ret = rb_rescue(RUBY_METHOD_FUNC(swig_rescue_funcall), VALUE(&args),
-                     (RUBY_METHOD_FUNC(swig_rescue_swallow)), Qnil);
+      ret = rb_rescue(VALUEFUNC(swig_rescue_funcall), VALUE(&args),
+                     (VALUEFUNC(swig_rescue_swallow)), Qnil);
       SWIG_RUBY_THREAD_END_BLOCK;
       return GC_VALUE(ret);
     }
diff --git a/Lib/ruby/rubyhead.swg b/Lib/ruby/rubyhead.swg
index 90f07cf..bf4e362 100644
--- a/Lib/ruby/rubyhead.swg
+++ b/Lib/ruby/rubyhead.swg
@@ -98,38 +98,46 @@
 
 
 /*
- * Need to be very careful about how these macros are defined, especially
- * when compiling C++ code or C code with an ANSI C compiler.
+ * The following macros are used for providing the correct type of a
+ * function pointer to the Ruby C API.
+ * Starting with Ruby 2.7 (corresponding to RB_METHOD_DEFINITION_DECL being
+ * defined) these macros act transparently due to Ruby's moving away from
+ * ANYARGS and instead employing strict function signatures.
  *
- * VALUEFUNC(f) is a macro used to typecast a C function that implements
- * a Ruby method so that it can be passed as an argument to API functions
- * like rb_define_method() and rb_define_singleton_method().
+ * Note: In case of C (not C++) the macros are transparent even before
+ * Ruby 2.7 due to the fact that the Ruby C API used function declarators
+ * with empty parentheses, which allows for an unspecified number of
+ * arguments.
  *
- * VOIDFUNC(f) is a macro used to typecast a C function that implements
- * either the "mark" or "free" stuff for a Ruby Data object, so that it
- * can be passed as an argument to API functions like Data_Wrap_Struct()
+ * PROTECTFUNC(f) is used for the function pointer argument of the Ruby
+ * C API function rb_protect().
+ *
+ * VALUEFUNC(f) is used for the function pointer argument(s) of Ruby C API
+ * functions like rb_define_method() and rb_define_singleton_method().
+ *
+ * VOIDFUNC(f) is used to typecast a C function that implements either
+ * the "mark" or "free" stuff for a Ruby Data object, so that it can be
+ * passed as an argument to Ruby C API functions like Data_Wrap_Struct()
  * and Data_Make_Struct().
+ *
+ * SWIG_RUBY_VOID_ANYARGS_FUNC(f) is used for the function pointer
+ * argument(s) of Ruby C API functions like rb_define_virtual_variable().
+ *
+ * SWIG_RUBY_INT_ANYARGS_FUNC(f) is used for the function pointer
+ * argument(s) of Ruby C API functions like st_foreach().
  */
- 
-#ifdef __cplusplus
-#  ifndef RUBY_METHOD_FUNC /* These definitions should work for Ruby 1.4.6 */
-#    define PROTECTFUNC(f) ((VALUE (*)()) f)
-#    define VALUEFUNC(f) ((VALUE (*)()) f)
-#    define VOIDFUNC(f)  ((void (*)()) f)
-#  else
-#    ifndef ANYARGS /* These definitions should work for Ruby 1.6 */
-#      define PROTECTFUNC(f) ((VALUE (*)()) f)
-#      define VALUEFUNC(f) ((VALUE (*)()) f)
-#      define VOIDFUNC(f)  ((RUBY_DATA_FUNC) f)
-#    else /* These definitions should work for Ruby 1.7+ */
-#      define PROTECTFUNC(f) ((VALUE (*)(VALUE)) f)
-#      define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
-#      define VOIDFUNC(f)  ((RUBY_DATA_FUNC) f)
-#    endif
-#  endif
+#if defined(__cplusplus) && !defined(RB_METHOD_DEFINITION_DECL)
+#  define PROTECTFUNC(f) ((VALUE (*)(VALUE)) f)
+#  define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
+#  define VOIDFUNC(f) ((RUBY_DATA_FUNC) f)
+#  define SWIG_RUBY_VOID_ANYARGS_FUNC(f) ((void (*)(ANYARGS))(f))
+#  define SWIG_RUBY_INT_ANYARGS_FUNC(f) ((int (*)(ANYARGS))(f))
 #else
+#  define PROTECTFUNC(f) (f)
 #  define VALUEFUNC(f) (f)
 #  define VOIDFUNC(f) (f)
+#  define SWIG_RUBY_VOID_ANYARGS_FUNC(f) (f)
+#  define SWIG_RUBY_INT_ANYARGS_FUNC(f) (f)
 #endif
 
 /* Don't use for expressions have side effect */
diff --git a/Lib/ruby/rubyprimtypes.swg b/Lib/ruby/rubyprimtypes.swg
index 3a84819..4b078de 100644
--- a/Lib/ruby/rubyprimtypes.swg
+++ b/Lib/ruby/rubyprimtypes.swg
@@ -10,15 +10,16 @@
 %fragment("SWIG_ruby_failed","header")
 {
 SWIGINTERN VALUE
-SWIG_ruby_failed(void)
+SWIG_ruby_failed(VALUE SWIGUNUSEDPARM(arg1), VALUE SWIGUNUSEDPARM(arg2))
 {
   return Qnil;
 } 
 }
 
 %define %ruby_aux_method(Type, Method, Action)
-SWIGINTERN VALUE SWIG_AUX_##Method##(VALUE *args)
+SWIGINTERN VALUE SWIG_AUX_##Method##(VALUE arg)
 {
+  VALUE *args = (VALUE *)arg;
   VALUE obj = args[0];
   VALUE type = TYPE(obj);
   Type *res = (Type *)(args[1]);
@@ -79,7 +80,7 @@
     VALUE a[2];
     a[0] = obj;
     a[1] = (VALUE)(&v);
-    if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2LONG), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+    if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2LONG), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
       if (val) *val = v;
       return SWIG_OK;
     }
@@ -111,7 +112,7 @@
     VALUE a[2];
     a[0] = obj;
     a[1] = (VALUE)(&v);
-    if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2ULONG), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+    if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2ULONG), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
       if (val) *val = v;
       return SWIG_OK;
     }
@@ -149,7 +150,7 @@
     VALUE a[2];
     a[0] = obj;
     a[1] = (VALUE)(&v);
-    if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2LL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+    if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2LL), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
       if (val) *val = v;
       return SWIG_OK;
     }
@@ -187,7 +188,7 @@
     VALUE a[2];
     a[0] = obj;
     a[1] = (VALUE)(&v);
-    if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2ULL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+    if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2ULL), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
       if (val) *val = v;
       return SWIG_OK;
     }
@@ -215,7 +216,7 @@
     VALUE a[2];
     a[0] = obj;
     a[1] = (VALUE)(&v);
-    if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2DBL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
+    if (rb_rescue(VALUEFUNC(SWIG_AUX_NUM2DBL), (VALUE)a, VALUEFUNC(SWIG_ruby_failed), 0) != Qnil) {
       if (val) *val = v;
       return SWIG_OK;
     }
diff --git a/Lib/ruby/rubytracking.swg b/Lib/ruby/rubytracking.swg
index b9fb249..1edcc56 100644
--- a/Lib/ruby/rubytracking.swg
+++ b/Lib/ruby/rubytracking.swg
@@ -32,7 +32,7 @@
 */
 static st_table* swig_ruby_trackings = NULL;
 
-static VALUE swig_ruby_trackings_count(ANYARGS) {
+static VALUE swig_ruby_trackings_count(ID id, VALUE *var) {
   return SWIG2NUM(swig_ruby_trackings->num_entries);
 }
 
@@ -69,7 +69,9 @@
     swig_ruby_trackings = (st_table*)NUM2SWIG(trackings_value);
   }
 
-  rb_define_virtual_variable("SWIG_TRACKINGS_COUNT", swig_ruby_trackings_count, NULL);
+  rb_define_virtual_variable("SWIG_TRACKINGS_COUNT",
+                             VALUEFUNC(swig_ruby_trackings_count),
+                             SWIG_RUBY_VOID_ANYARGS_FUNC((rb_gvar_setter_t*)NULL));
 }
 
 /* Add a Tracking from a C/C++ struct to a Ruby object */
@@ -118,13 +120,15 @@
    to the passed callback function. */
 
 /* Proxy method to abstract the internal trackings datatype */
-static int swig_ruby_internal_iterate_callback(void* ptr, VALUE obj, void(*meth)(void* ptr, VALUE obj)) {
-  (*meth)(ptr, obj);
+static int swig_ruby_internal_iterate_callback(st_data_t ptr, st_data_t obj, st_data_t meth) {
+  ((void (*) (void *, VALUE))meth)((void *)ptr, (VALUE)obj);
   return ST_CONTINUE;
 }
 
 SWIGRUNTIME void SWIG_RubyIterateTrackings( void(*meth)(void* ptr, VALUE obj) ) {
-  st_foreach(swig_ruby_trackings, (int (*)(ANYARGS))&swig_ruby_internal_iterate_callback, (st_data_t)meth);
+  st_foreach(swig_ruby_trackings,
+             SWIG_RUBY_INT_ANYARGS_FUNC(swig_ruby_internal_iterate_callback),
+             (st_data_t)meth);
 }
 
 #ifdef __cplusplus
diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c
index ee3270b..4c1a038 100644
--- a/Source/CParse/cscanner.c
+++ b/Source/CParse/cscanner.c
@@ -448,10 +448,11 @@
 	    
 	    /* Check for all possible Doxygen comment start markers while ignoring
 	       comments starting with a row of asterisks or slashes just as
-	       Doxygen itself does. */
+	       Doxygen itself does.  Also skip empty comment (slash-star-star-slash), 
+	       which causes a crash due to begin > end. */
 	    if (Len(cmt) > 3 && loc[0] == '/' &&
 		((loc[1] == '/' && ((loc[2] == '/' && loc[3] != '/') || loc[2] == '!')) ||
-		 (loc[1] == '*' && ((loc[2] == '*' && loc[3] != '*') || loc[2] == '!')))) {
+		 (loc[1] == '*' && ((loc[2] == '*' && loc[3] != '*' && loc[3] != '/') || loc[2] == '!')))) {
 	      comment_kind_t this_comment = loc[3] == '<' ? DOX_COMMENT_POST : DOX_COMMENT_PRE;
 	      if (existing_comment != DOX_COMMENT_NONE && this_comment != existing_comment) {
 		/* We can't concatenate together Doxygen pre- and post-comments. */
@@ -893,10 +894,14 @@
 	  return (USING);
 	if (strcmp(yytext, "namespace") == 0)
 	  return (NAMESPACE);
-	if (strcmp(yytext, "override") == 0)
+	if (strcmp(yytext, "override") == 0) {
+	  last_id = 1;
 	  return (OVERRIDE);
-	if (strcmp(yytext, "final") == 0)
+	}
+	if (strcmp(yytext, "final") == 0) {
+	  last_id = 1;
 	  return (FINAL);
+	}
       } else {
 	if (strcmp(yytext, "class") == 0) {
 	  Swig_warning(WARN_PARSE_CLASS_KEYWORD, cparse_file, cparse_line, "class keyword used, but not in C++ mode.\n");
diff --git a/Source/DOH/README b/Source/DOH/README
index 8be5f65..be90f25 100644
--- a/Source/DOH/README
+++ b/Source/DOH/README
@@ -73,11 +73,17 @@
 Chop(obj)                       Remove trailing whitespace
 
 flags is one of the following:
-     DOH_REPLACE_ANY
-     DOH_REPLACE_NOQUOTE
-     DOH_REPLACE_ID
-     DOH_REPLACE_FIRST
-             
+    DOH_REPLACE_ID
+    DOH_REPLACE_ID_BEGIN
+    DOH_REPLACE_ID_END
+    DOH_REPLACE_NUMBER_END
+
+and can be combined with one or more of the following:
+    DOH_REPLACE_ANY
+    DOH_REPLACE_NOQUOTE
+    DOH_REPLACE_NOCOMMENT
+    DOH_REPLACE_FIRST
+
 Callable Operations
 -------------------
 Call(obj, args)                 Perform a function call with arguments args.
diff --git a/Source/DOH/doh.h b/Source/DOH/doh.h
index 7fb64c0..fd0530e 100644
--- a/Source/DOH/doh.h
+++ b/Source/DOH/doh.h
@@ -289,11 +289,12 @@
 
 #define   DOH_REPLACE_ANY         0x01
 #define   DOH_REPLACE_NOQUOTE     0x02
-#define   DOH_REPLACE_ID          0x04
-#define   DOH_REPLACE_FIRST       0x08
-#define   DOH_REPLACE_ID_BEGIN    0x10
-#define   DOH_REPLACE_ID_END      0x20
-#define   DOH_REPLACE_NUMBER_END  0x40
+#define   DOH_REPLACE_NOCOMMENT   0x04
+#define   DOH_REPLACE_ID          0x08
+#define   DOH_REPLACE_FIRST       0x10
+#define   DOH_REPLACE_ID_BEGIN    0x20
+#define   DOH_REPLACE_ID_END      0x40
+#define   DOH_REPLACE_NUMBER_END  0x80
 
 #define Replaceall(s,t,r)  DohReplace(s,t,r,DOH_REPLACE_ANY)
 #define Replaceid(s,t,r)   DohReplace(s,t,r,DOH_REPLACE_ID)
diff --git a/Source/DOH/string.c b/Source/DOH/string.c
index 6c67285..3689f4f 100644
--- a/Source/DOH/string.c
+++ b/Source/DOH/string.c
@@ -595,6 +595,13 @@
   }
 }
 
+static char *end_comment(char *s) {
+  char *substring = strstr(s, "*/");
+  if (substring)
+    ++substring;
+  return substring;
+}
+
 static char *match_simple(char *base, char *s, char *token, int tokenlen) {
   (void) base;
   (void) tokenlen;
@@ -677,6 +684,7 @@
   int ic;
   int rcount = 0;
   int noquote = 0;
+  int nocomment = 0;
   char *c, *s, *t, *first;
   char *q, *q2;
   char *base;
@@ -698,6 +706,11 @@
   if (flags & DOH_REPLACE_NOQUOTE)
     noquote = 1;
 
+  if (flags & DOH_REPLACE_NOCOMMENT)
+    nocomment = 1;
+
+  assert(!(noquote && nocomment)); /* quote and comment combination not implemented */
+
   /* If we are not replacing inside quotes, we need to do a little extra work */
   if (noquote) {
     q = strpbrk(base, "\"\'");
@@ -723,6 +736,31 @@
     }
   }
 
+  /* If we are not replacing inside comments, we need to do a little extra work */
+  if (nocomment) {
+    q = strstr(base, "/*");
+    if (!q) {
+      nocomment = 0;		/* Well, no comments to worry about. Oh well */
+    } else {
+      while (q && (q < s)) {
+	/* First match was found inside a comment.  Try to find another match */
+	q2 = end_comment(q);
+	if (!q2) {
+	  return 0;
+	}
+	if (q2 > s) {
+	  /* Find next match */
+	  s = (*match) (base, q2 + 1, token, tokenlen);
+	}
+	if (!s)
+	  return 0;		/* Oh well, no matches */
+	q = strstr(q2 + 1, "/*");
+	if (!q)
+	  nocomment = 0;		/* No more comments */
+      }
+    }
+  }
+
   first = s;
   replen = (int)strlen(rep);
 
@@ -768,6 +806,28 @@
 	  }
 	}
       }
+      if (nocomment) {
+	q = strstr(s, "/*");
+	if (!q) {
+	  nocomment = 0;
+	} else {
+	  while (q && (q < c)) {
+	    /* First match was found inside a comment.  Try to find another match */
+	    q2 = end_comment(q);
+	    if (!q2) {
+	      c = 0;
+	      break;
+	    }
+	    if (q2 > c)
+	      c = (*match) (base, q2 + 1, token, tokenlen);
+	    if (!c)
+	      break;
+	    q = strstr(q2 + 1, "/*");
+	    if (!q)
+	      nocomment = 0;	/* No more comments */
+	  }
+	}
+      }
       if (delta) {
 	if (c) {
 	  memmove(t, s, c - s);
@@ -823,6 +883,29 @@
 	  }
 	}
       }
+      if (nocomment) {
+	q = strstr(s, "/*");
+	if (!q) {
+	  break;
+	} else {
+	  while (q && (q < c)) {
+	    /* First match was found inside a comment.  Try to find another match */
+	    q2 = end_comment(q);
+	    if (!q2) {
+	      c = 0;
+	      break;
+	    }
+	    if (q2 > c) {
+	      c = (*match) (base, q2 + 1, token, tokenlen);
+	      if (!c)
+		break;
+	    }
+	    q = strstr(q2 + 1, "/*");
+	    if (!q)
+	      nocomment = 0;
+	  }
+	}
+      }
       if (c) {
 	rcount++;
 	ic--;
@@ -875,6 +958,29 @@
 	  }
 	}
       }
+      if (nocomment) {
+	q = strstr(s, "/*");
+	if (!q) {
+	  nocomment = 0;
+	} else {
+	  while (q && (q < c)) {
+	    /* First match was found inside a comment.  Try to find another match */
+	    q2 = end_comment(q);
+	    if (!q2) {
+	      c = 0;
+	      break;
+	    }
+	    if (q2 > c) {
+	      c = (*match) (base, q2 + 1, token, tokenlen);
+	      if (!c)
+		break;
+	    }
+	    q = strstr(q2 + 1, "/*");
+	    if (!q)
+	      nocomment = 0;	/* No more comments */
+	  }
+	}
+      }
       if (i < (rcount - 1)) {
 	memcpy(t, s, c - s);
 	t += (c - s);
diff --git a/Source/Doxygen/doxycommands.h b/Source/Doxygen/doxycommands.h
index 1f7b5fa..b5d65af 100644
--- a/Source/Doxygen/doxycommands.h
+++ b/Source/Doxygen/doxycommands.h
@@ -18,11 +18,13 @@
 const char *CMD_HTML_ONLY = "htmlonly";
 // doxy commands are not processed inside this block
 const char *CMD_VERBATIM = "verbatim";
+const char *CMD_CODE = "code";
 const char *CMD_LATEX_1 = "f$";
 const char *CMD_LATEX_2 = "f{";
 const char *CMD_LATEX_3 = "f[";
 const char *CMD_END_HTML_ONLY = "endhtmlonly";
 const char *CMD_END_VERBATIM = "endverbatim";
+const char *CMD_END_CODE = "endcode";
 const char *CMD_END_LATEX_1 = "f$";
 const char *CMD_END_LATEX_2 = "f}";
 const char *CMD_END_LATEX_3 = "f]";
diff --git a/Source/Doxygen/doxyparser.cxx b/Source/Doxygen/doxyparser.cxx
index 2e826b2..6bda9d2 100644
--- a/Source/Doxygen/doxyparser.cxx
+++ b/Source/Doxygen/doxyparser.cxx
@@ -34,6 +34,30 @@
 const int TOKENSPERLINE = 8; //change this to change the printing behaviour of the token list
 const std::string END_HTML_TAG_MARK("/");
 
+std::string getBaseCommand(const std::string &cmd) {
+  if (cmd.substr(0,5) == "param")
+    return "param";
+  else if (cmd.substr(0,4) == "code")
+    return "code";
+  else
+    return cmd;
+}
+
+// Find the first position beyond the word command.  Extra logic is
+// used to avoid putting the characters "," and "." in
+// DOXYGEN_WORD_CHARS.
+static size_t getEndOfWordCommand(const std::string &line, size_t pos) {
+  size_t endOfWordPos = line.find_first_not_of(DOXYGEN_WORD_CHARS, pos);
+  if (line.substr(pos, 6) == "param[")
+    // include ",", which can appear in param[in,out]
+    endOfWordPos = line.find_first_not_of(string(DOXYGEN_WORD_CHARS)+ ",", pos);  
+  else if (line.substr(pos, 5) == "code{")
+    // include ".", which can appear in e.g. code{.py}
+    endOfWordPos = line.find_first_not_of(string(DOXYGEN_WORD_CHARS)+ ".", pos);
+  return endOfWordPos;
+}
+
+
 DoxygenParser::DoxygenParser(bool noisy) : noisy(noisy) {
   fillTables();
 }
@@ -118,7 +142,7 @@
 }
 
 DoxygenParser::DoxyCommandEnum DoxygenParser::commandBelongs(const std::string &theCommand) {
-  DoxyCommandsMapIt it = doxygenCommands.find(stringToLower(theCommand));
+  DoxyCommandsMapIt it = doxygenCommands.find(stringToLower(getBaseCommand(theCommand)));
 
   if (it != doxygenCommands.end()) {
     return it->second;
@@ -312,7 +336,7 @@
 
     } else if (endOfParagraph->m_tokenType == COMMAND) {
 
-      if (isSectionIndicator(endOfParagraph->m_tokenString)) {
+      if (isSectionIndicator(getBaseCommand(endOfParagraph->m_tokenString))) {
         return endOfParagraph;
       } else {
         endOfParagraph++;
@@ -666,7 +690,7 @@
   // \f{ ... \f}
   // \f{env}{ ... \f}
   // \f$ ... \f$
-  else if (theCommand == "code" || theCommand == "verbatim"
+  else if (getBaseCommand(theCommand) == "code" || theCommand == "verbatim"
            || theCommand == "dot" || theCommand == "msc" || theCommand == "f[" || theCommand == "f{" || theCommand == "f$") {
     if (!endCommands.size()) {
       // fill in static table of end commands
@@ -683,7 +707,7 @@
     if (it != endCommands.end())
       endCommand = it->second;
     else
-      endCommand = "end" + theCommand;
+      endCommand = "end" + getBaseCommand(theCommand);
 
     std::string content = getStringTilEndCommand(endCommand, tokList);
     aNewList.push_back(DoxygenEntity("plainstd::string", content));
@@ -1090,7 +1114,7 @@
     size_t endOfWordPos = line.find_first_not_of(DOXYGEN_WORD_CHARS, pos);
     string cmd = line.substr(pos, endOfWordPos - pos);
 
-    if (cmd == CMD_END_HTML_ONLY || cmd == CMD_END_VERBATIM || cmd == CMD_END_LATEX_1 || cmd == CMD_END_LATEX_2 || cmd == CMD_END_LATEX_3) {
+    if (cmd == CMD_END_HTML_ONLY || cmd == CMD_END_VERBATIM || cmd == CMD_END_LATEX_1 || cmd == CMD_END_LATEX_2 || cmd == CMD_END_LATEX_3 || cmd == CMD_END_CODE) {
 
       m_isVerbatimText = false;
       addDoxyCommand(m_tokenList, cmd);
@@ -1154,22 +1178,34 @@
  */
 void DoxygenParser::processWordCommands(size_t &pos, const std::string &line) {
   pos++;
-  size_t endOfWordPos = line.find_first_not_of(DOXYGEN_WORD_CHARS, pos);
+  size_t endOfWordPos = getEndOfWordCommand(line, pos);
 
   string cmd = line.substr(pos, endOfWordPos - pos);
   addDoxyCommand(m_tokenList, cmd);
 
-  if (cmd == CMD_HTML_ONLY || cmd == CMD_VERBATIM || cmd == CMD_LATEX_1 || cmd == CMD_LATEX_2 || cmd == CMD_LATEX_3) {
+  // A flag for whether we want to skip leading spaces after the command
+  bool skipLeadingSpace = true;
+
+  if (cmd == CMD_HTML_ONLY || cmd == CMD_VERBATIM || cmd == CMD_LATEX_1 || cmd == CMD_LATEX_2 || cmd == CMD_LATEX_3 || getBaseCommand(cmd) == CMD_CODE) {
 
     m_isVerbatimText = true;
 
-  } else {
+    // Skipping leading space is necessary with inline \code command,
+    // and it won't hurt anything for block \code (TODO: are the other
+    // commands also compatible with skip leading space?  If so, just
+    // do it every time.)
+    if (getBaseCommand(cmd) == CMD_CODE) skipLeadingSpace = true;
+    else skipLeadingSpace = false;
+  }
+
+  if (skipLeadingSpace) {
     // skip any possible spaces after command, because some commands have parameters,
     // and spaces between command and parameter must be ignored.
     if (endOfWordPos != string::npos) {
       endOfWordPos = line.find_first_not_of(" \t", endOfWordPos);
     }
   }
+  
   pos = endOfWordPos;
 }
 
diff --git a/Source/Doxygen/doxyparser.h b/Source/Doxygen/doxyparser.h
index 96c71d2..e692729 100644
--- a/Source/Doxygen/doxyparser.h
+++ b/Source/Doxygen/doxyparser.h
@@ -21,6 +21,11 @@
 
 #include "doxyentity.h"
 
+// Utility function to return the base part of a command that may
+// include options, e.g. param[in] -> param
+std::string getBaseCommand(const std::string &cmd);
+
+
 class DoxygenParser {
 private:
 
diff --git a/Source/Doxygen/javadoc.cxx b/Source/Doxygen/javadoc.cxx
index 72f84ab..d9313f9 100644
--- a/Source/Doxygen/javadoc.cxx
+++ b/Source/Doxygen/javadoc.cxx
@@ -334,7 +334,7 @@
 void JavaDocConverter::translateEntity(DoxygenEntity &tag, std::string &translatedComment) {
 
   std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
-  it = tagHandlers.find(tag.typeOfEntity);
+  it = tagHandlers.find(getBaseCommand(tag.typeOfEntity));
 
   if (it != tagHandlers.end()) {
     (this->*(it->second.first))(tag, translatedComment, it->second.second);
diff --git a/Source/Doxygen/pydoc.cxx b/Source/Doxygen/pydoc.cxx
index eb48993..f2031f4 100644
--- a/Source/Doxygen/pydoc.cxx
+++ b/Source/Doxygen/pydoc.cxx
@@ -174,7 +174,8 @@
     } else {
       if (lastLineWasNonBlank &&
 	  (line.compare(pos, 13, ".. code-block") == 0 ||
-	  line.compare(pos, 7, ".. math") == 0)) {
+	   line.compare(pos, 7, ".. math") == 0 ||
+	   line.compare(pos, 3, ">>>") == 0)) {
 	// Must separate code or math blocks from the previous line
 	result += '\n';
       }
@@ -184,6 +185,21 @@
   return result;
 }
 
+// Helper function to extract the option value from a command,
+// e.g. param[in] -> in
+static std::string getCommandOption(const std::string &command, char openChar, char closeChar) {
+  string option;
+
+  size_t opt_begin, opt_end;
+  opt_begin = command.find(openChar);
+  opt_end = command.find(closeChar);
+  if (opt_begin != string::npos && opt_end != string::npos)
+    option = command.substr(opt_begin+1, opt_end-opt_begin-1);
+
+  return option;
+}
+
+
 /* static */
 PyDocConverter::TagHandlersMap::mapped_type PyDocConverter::make_handler(tagHandler handler) {
   return make_pair(handler, std::string());
@@ -245,7 +261,7 @@
   tagHandlers["date"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["deprecated"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["details"] = make_handler(&PyDocConverter::handleParagraph);
-  tagHandlers["em"] = make_handler(&PyDocConverter::handleParagraph, " ");
+  tagHandlers["em"] = make_handler(&PyDocConverter::handleTagWrap, "*");
   tagHandlers["example"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["exception"] = tagHandlers["throw"] = tagHandlers["throws"] = make_handler(&PyDocConverter::handleTagException);
   tagHandlers["htmlonly"] = make_handler(&PyDocConverter::handleParagraph);
@@ -254,7 +270,7 @@
   tagHandlers["link"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["manonly"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["note"] = make_handler(&PyDocConverter::handleParagraph);
-  tagHandlers["p"] = make_handler(&PyDocConverter::handleParagraph);
+  tagHandlers["p"] = make_handler(&PyDocConverter::handleTagWrap, "``");
   tagHandlers["partofdescription"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["rtfonly"] = make_handler(&PyDocConverter::handleParagraph);
   tagHandlers["remark"] = make_handler(&PyDocConverter::handleParagraph);
@@ -428,6 +444,23 @@
   return type;
 }
 
+std::string PyDocConverter::getParamValue(std::string param) {
+  std::string value;
+
+  ParmList *plist = CopyParmList(Getattr(currentNode, "parms"));
+  for (Parm *p = plist; p; p = nextSibling(p)) {
+    String *pname = Getattr(p, "name");
+    if (Char(pname) != param)
+      continue;
+
+    String *pval = Getattr(p, "value");
+    if (pval) value = Char(pval);
+    break;
+  }
+  Delete(plist);
+  return value;
+}
+
 std::string PyDocConverter::translateSubtree(DoxygenEntity &doxygenEntity) {
   std::string translatedComment;
 
@@ -456,7 +489,7 @@
 void PyDocConverter::translateEntity(DoxygenEntity &doxyEntity, std::string &translatedComment) {
   // check if we have needed handler and call it
   std::map<std::string, std::pair<tagHandler, std::string> >::iterator it;
-  it = tagHandlers.find(doxyEntity.typeOfEntity);
+  it = tagHandlers.find(getBaseCommand(doxyEntity.typeOfEntity));
   if (it != tagHandlers.end())
     (this->*(it->second.first)) (doxyEntity, translatedComment, it->second.second);
 }
@@ -531,19 +564,29 @@
 
   trimWhitespace(translatedComment);
 
-  // Use the current indent for the code-block line itself.
-  translatedComment += indent.getFirstLineIndent();
-
-  // Go out on a limb and assume that examples in the C or C++ sources use C++.
-  // In the worst case, we'll highlight C code using C++ syntax which is not a
-  // big deal (TODO: handle Doxygen code command language argument).
-  translatedComment += ".. code-block:: c++\n\n";
-
-  // Specify the level of extra indentation that will be used for
-  // subsequent lines within the code block.  Note that the correct
-  // "starting indentation" is already present in the input, so we
-  // only need to add the desired code block indentation.
-  string codeIndent = m_indent;
+  // Check for an option given to the code command (e.g. code{.py}),
+  // and try to set the code-block language accordingly.
+  string option = getCommandOption(tag.typeOfEntity, '{', '}');
+  // Set up the language option to the code-block command, which can
+  // be any language supported by pygments:
+  string codeLanguage;
+  if (option == ".py")
+    // Other possibilities here are "default" or "python3".  In Sphinx
+    // 2.1.2, basic syntax doesn't render quite the same in these as
+    // with "python", which for basic keywords seems to provide
+    // slightly richer formatting.  Another option would be to leave
+    // the language empty, but testing with Sphinx 1.8.5 has produced
+    // an error "1 argument required".
+    codeLanguage = "python";
+  else if (option == ".java")
+    codeLanguage = "java";
+  else if (option == ".c")
+    codeLanguage = "c";
+  else
+    // If there is not a match, or if no option was given, go out on a
+    // limb and assume that the examples in the C or C++ sources use
+    // C++.
+    codeLanguage = "c++";
 
   std::string code;
   handleTagVerbatim(tag, code, arg);
@@ -552,6 +595,27 @@
   // command:
   eraseLeadingNewLine(code);
 
+  // Check for python doctest blocks, and treat them specially:
+  bool isDocTestBlock = false;
+  size_t startPos;
+  // ">>>" would normally appear at the beginning, but doxygen comment
+  // style may have space in front, so skip leading whitespace
+  if ((startPos=code.find_first_not_of(" \t")) != string::npos && code.substr(startPos,3) == ">>>")
+    isDocTestBlock = true;
+
+  string codeIndent;
+  if (! isDocTestBlock) {
+    // Use the current indent for the code-block line itself.
+    translatedComment += indent.getFirstLineIndent();
+    translatedComment += ".. code-block:: " + codeLanguage + "\n\n";
+
+    // Specify the level of extra indentation that will be used for
+    // subsequent lines within the code block.  Note that the correct
+    // "starting indentation" is already present in the input, so we
+    // only need to add the desired code block indentation.
+    codeIndent = m_indent;
+  }
+
   translatedComment += codeIndent;
   for (size_t n = 0; n < code.length(); n++) {
     if (code[n] == '\n') {
@@ -636,8 +700,26 @@
   const std::string &paramName = paramNameEntity.data;
 
   const std::string paramType = getParamType(paramName);
+  const std::string paramValue = getParamValue(paramName);
+
+  // Get command option, e.g. "in", "out", or "in,out"
+  string commandOpt = getCommandOption(tag.typeOfEntity, '[', ']');
+  if (commandOpt == "in,out") commandOpt = "in/out";
+
+  // If provided, append the parameter direction to the type
+  // information via a suffix:
+  std::string suffix;
+  if (commandOpt.size() > 0)
+    suffix = ", " + commandOpt;
+  
+  // If the parameter has a default value, flag it as optional in the
+  // generated type definition.  Particularly helpful when the python
+  // call is generated with *args, **kwargs.
+  if (paramValue.size() > 0)
+    suffix += ", optional";  
+
   if (!paramType.empty()) {
-    translatedComment += ":type " + paramName + ": " + paramType + "\n";
+    translatedComment += ":type " + paramName + ": " + paramType + suffix + "\n";
     translatedComment += indent.getFirstLineIndent();
   }
 
@@ -909,3 +991,4 @@
 
   return NewString(pyDocString.c_str());
 }
+
diff --git a/Source/Doxygen/pydoc.h b/Source/Doxygen/pydoc.h
index df8997d..07c5ce5 100644
--- a/Source/Doxygen/pydoc.h
+++ b/Source/Doxygen/pydoc.h
@@ -178,6 +178,11 @@
    */
   std::string getParamType(std::string name);
 
+  /*
+   * Simple helper function to retrieve the parameter value
+   */
+  std::string getParamValue(std::string name);
+
 private:
   // temporary thing, should be refactored somehow
   Node *currentNode;
diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx
index 17100b3..d08884b 100644
--- a/Source/Modules/csharp.cxx
+++ b/Source/Modules/csharp.cxx
@@ -4064,11 +4064,10 @@
 	      /* Get the C# parameter type */
 	      if ((tm = Getattr(p, "tmap:cstype"))) {
 		substituteClassname(pt, tm);
-		if (Strncmp(tm, "ref ", 4) == 0) {
-		  Replace(tm, "ref ", "", DOH_REPLACE_FIRST);
+		int flags = DOH_REPLACE_FIRST | DOH_REPLACE_ID_BEGIN | DOH_REPLACE_NOCOMMENT;
+		if (Replace(tm, "ref ", "", flags) || Replace(tm, "ref\t", "", flags)) {
 		  Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm);
-		} else if (Strncmp(tm, "out ", 4) == 0) {
-		  Replace(tm, "out ", "", DOH_REPLACE_FIRST);
+		} else if (Replace(tm, "out ", "", flags) || Replace(tm, "out\t", "", flags)) {
 		  Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm);
 		} else {
 		  Printf(proxy_method_types, "typeof(%s)", tm);
diff --git a/Source/Modules/ocaml.cxx b/Source/Modules/ocaml.cxx
index 6f2a349..9f7504b 100644
--- a/Source/Modules/ocaml.cxx
+++ b/Source/Modules/ocaml.cxx
@@ -1619,7 +1619,7 @@
       /* pass the method call on to the OCaml object */
       Printv(w->code,
 	     "swig_result = caml_swig_alloc(1,C_list);\n" "SWIG_Store_field(swig_result,0,args);\n" "args = swig_result;\n" "swig_result = Val_unit;\n", 0);
-      Printf(w->code, "static CAML_VALUE *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n");
+      Printf(w->code, "static const CAML_VALUE *swig_ocaml_func_val = NULL;\n" "if (!swig_ocaml_func_val) {\n");
       Printf(w->code, "  swig_ocaml_func_val = caml_named_value(\"swig_runmethod\");\n  }\n");
       Printf(w->code, "swig_result = caml_callback3(*swig_ocaml_func_val,swig_get_self(),caml_copy_string(\"%s\"),args);\n", Getattr(n, "name"));
       /* exception handling */
diff --git a/Source/Modules/python.cxx b/Source/Modules/python.cxx
index ea31af0..1dbedad 100644
--- a/Source/Modules/python.cxx
+++ b/Source/Modules/python.cxx
@@ -2493,7 +2493,7 @@
     String *symname = Getattr(n, "sym:name");
     String *wname = Swig_name_wrapper(symname);
 
-    const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : "";
+    const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : "";
     Printv(f->def, linkage, builtin_ctor ? "int " : "PyObject *", wname, "(PyObject *self, PyObject *args", builtin_kwargs, ") {", NIL);
 
     Wrapper_add_local(f, "argc", "Py_ssize_t argc");
@@ -2503,6 +2503,9 @@
     if (!fastunpack) {
       Wrapper_add_local(f, "ii", "Py_ssize_t ii");
 
+      if (builtin_ctor)
+	Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname);
+
       if (maxargs - (add_self ? 1 : 0) > 0) {
         Append(f->code, "if (!PyTuple_Check(args)) SWIG_fail;\n");
         Append(f->code, "argc = PyObject_Length(args);\n");
@@ -2518,8 +2521,9 @@
       if (add_self)
 	Append(f->code, "argc++;\n");
     } else {
-      String *iname = Getattr(n, "sym:name");
-      Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", iname, maxargs, add_self ? "+1" : "");
+      if (builtin_ctor)
+	Printf(f->code, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", symname);
+      Printf(f->code, "if (!(argc = SWIG_Python_UnpackTuple(args, \"%s\", 0, %d, argv%s))) SWIG_fail;\n", symname, maxargs, add_self ? "+1" : "");
       if (add_self)
 	Append(f->code, "argv[0] = self;\n");
       else
@@ -2700,8 +2704,12 @@
       --tuple_required;
     }
     num_fixed_arguments = tuple_required;
+
+    // builtin handles/checks kwargs by default except in constructor wrappers so we need to explicitly handle them in the C constructor wrapper
+    // The check below is for zero arguments. Sometimes (eg directors) self is the first argument for a method with zero arguments.
     if (((num_arguments == 0) && (num_required == 0)) || ((num_arguments == 1) && (num_required == 1) && Getattr(l, "self")))
-      allow_kwargs = 0;
+      if (!builtin_ctor)
+	allow_kwargs = 0;
     varargs = emit_isvarargs(l);
 
     String *wname = Copy(wrapper_name);
@@ -2709,7 +2717,7 @@
       Append(wname, overname);
     }
 
-    const char *builtin_kwargs = builtin_ctor ? ", PyObject *SWIGUNUSEDPARM(kwargs)" : "";
+    const char *builtin_kwargs = builtin_ctor ? ", PyObject *kwargs" : "";
     if (!allow_kwargs || overname) {
       if (!varargs) {
 	Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL);
@@ -2727,7 +2735,7 @@
       }
       Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args, PyObject *kwargs) {", NIL);
     }
-    if (!builtin || !in_class || tuple_arguments > 0) {
+    if (!builtin || !in_class || tuple_arguments > 0 || builtin_ctor) {
       if (!allow_kwargs) {
 	Append(parse_args, "    if (!PyArg_ParseTuple(args, \"");
       } else {
@@ -2876,14 +2884,13 @@
       Printv(f->locals, "  char * kwnames[] = ", kwargs, ";\n", NIL);
     }
 
-    if (builtin && !funpack && in_class && tuple_arguments == 0) {
-      Printf(parse_args, "    if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname);
-    } else if (use_parse || allow_kwargs) {
+    if (use_parse || allow_kwargs) {
       Printf(parse_args, ":%s\"", iname);
       Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
       funpack = 0;
     } else {
       Clear(parse_args);
+
       if (funpack) {
 	Clear(f->def);
 	if (overname) {
@@ -2896,6 +2903,8 @@
 	} else {
 	  int is_tp_call = Equal(Getattr(n, "feature:python:slot"), "tp_call");
 	  Printv(f->def, linkage, wrap_return, wname, "(PyObject *", self_param, ", PyObject *args", builtin_kwargs, ") {", NIL);
+	  if (builtin_ctor)
+	    Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname);
 	  if (onearg && !builtin_ctor && !is_tp_call) {
 	    Printf(parse_args, "if (!args) SWIG_fail;\n");
 	    Append(parse_args, "swig_obj[0] = args;\n");
@@ -2906,8 +2915,14 @@
 	  }
 	}
       } else {
-	Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments);
-	Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
+	if (builtin_ctor)
+	  Printf(parse_args, "if (!SWIG_Python_CheckNoKeywords(kwargs, \"%s\")) SWIG_fail;\n", iname);
+	if (builtin && in_class && tuple_arguments == 0) {
+	  Printf(parse_args, "    if (args && PyTuple_Check(args) && PyTuple_GET_SIZE(args) > 0) SWIG_exception_fail(SWIG_TypeError, \"%s takes no arguments\");\n", iname);
+	} else {
+	  Printf(parse_args, "if (!PyArg_UnpackTuple(args, \"%s\", %d, %d", iname, num_fixed_arguments, tuple_arguments);
+	  Printv(parse_args, arglist, ")) SWIG_fail;\n", NIL);
+	}
       }
     }
 
@@ -4128,6 +4143,13 @@
     Printv(f, "#if PY_VERSION_HEX >= 0x03040000\n", NIL);
     printSlot(f, getSlot(n, "feature:python:tp_finalize"), "tp_finalize", "destructor");
     Printv(f, "#endif\n", NIL);
+    Printv(f, "#if PY_VERSION_HEX >= 0x03080000\n", NIL);
+    printSlot(f, getSlot(n, "feature:python:tp_vectorcall"), "tp_vectorcall", "vectorcallfunc");
+    Printv(f, "#endif\n", NIL);
+    Printv(f, "#if (PY_VERSION_HEX >= 0x03080000) && (PY_VERSION_HEX < 0x03090000)\n", NIL);
+    printSlot(f, getSlot(), "tp_print");
+    Printv(f, "#endif\n", NIL);
+
     Printv(f, "#ifdef COUNT_ALLOCS\n", NIL);
     printSlot(f, getSlot(n, "feature:python:tp_allocs"), "tp_allocs", "Py_ssize_t");
     printSlot(f, getSlot(n, "feature:python:tp_frees"), "tp_frees", "Py_ssize_t");
diff --git a/Source/Modules/ruby.cxx b/Source/Modules/ruby.cxx
index 6a1e16d..48b0efa 100644
--- a/Source/Modules/ruby.cxx
+++ b/Source/Modules/ruby.cxx
@@ -2191,6 +2191,12 @@
     String *tm;
     String *getfname, *setfname;
     Wrapper *getf, *setf;
+    const int assignable = is_assignable(n);
+
+    // Determine whether virtual global variables shall be used
+    // which have different getter and setter signatures,
+    // see https://docs.ruby-lang.org/en/2.6.0/extension_rdoc.html#label-Global+Variables+Shared+Between+C+and+Ruby
+    const bool use_virtual_var = (current == NO_CPP && useGlobalModule);
 
     getf = NewWrapper();
     setf = NewWrapper();
@@ -2201,7 +2207,7 @@
     getfname = Swig_name_wrapper(getname);
     Setattr(n, "wrap:name", getfname);
     Printv(getf->def, "SWIGINTERN VALUE\n", getfname, "(", NIL);
-    Printf(getf->def, "VALUE self");
+    Printf(getf->def, (use_virtual_var) ? "ID id, VALUE *data" : "VALUE self");
     Printf(getf->def, ") {");
     Wrapper_add_local(getf, "_val", "VALUE _val");
 
@@ -2224,8 +2230,8 @@
 
     Wrapper_print(getf, f_wrappers);
 
-    if (!is_assignable(n)) {
-      setfname = NewString("NULL");
+    if (!assignable) {
+      setfname = NewString("(rb_gvar_setter_t *)NULL");
     } else {
       /* create setter */
       String* docs = docstring(n, AUTODOC_SETTER);
@@ -2235,8 +2241,12 @@
       String *setname = Swig_name_set(NSPACE_TODO, iname);
       setfname = Swig_name_wrapper(setname);
       Setattr(n, "wrap:name", setfname);
-      Printv(setf->def, "SWIGINTERN VALUE\n", setfname, "(VALUE self, ", NIL);
-      Printf(setf->def, "VALUE _val) {");
+      Printf(setf->def, "SWIGINTERN ");
+      if (use_virtual_var) {
+        Printv(setf->def, "void\n", setfname, "(VALUE _val, ID id, VALUE *data) {", NIL);
+      } else {
+        Printv(setf->def, "VALUE\n", setfname, "(VALUE self, VALUE _val) {", NIL);
+      }
       tm = Swig_typemap_lookup("varin", n, name, 0);
       if (tm) {
 	Replaceall(tm, "$input", "_val");
@@ -2247,28 +2257,31 @@
       } else {
 	Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s\n", SwigType_str(t, 0));
       }
-      Printv(setf->code, tab4, "return _val;\n", NIL);
-      Printf(setf->code, "fail:\n");
-      Printv(setf->code, tab4, "return Qnil;\n", NIL);
+      if (use_virtual_var) {
+        Printf(setf->code, "fail:\n");
+        Printv(setf->code, tab4, "return;\n", NIL);
+      } else {
+        Printv(setf->code, tab4, "return _val;\n", NIL);
+        Printf(setf->code, "fail:\n");
+        Printv(setf->code, tab4, "return Qnil;\n", NIL);
+      }
       Printf(setf->code, "}\n");
       Wrapper_print(setf, f_wrappers);
       Delete(setname);
     }
 
-    /* define accessor method */
-    if (CPlusPlus) {
-      Insert(getfname, 0, "VALUEFUNC(");
-      Append(getfname, ")");
-      Insert(setfname, 0, "VALUEFUNC(");
-      Append(setfname, ")");
-    }
+    /* define accessor methods */
+    Insert(getfname, 0, "VALUEFUNC(");
+    Append(getfname, ")");
+    Insert(setfname, 0, (use_virtual_var) ? "SWIG_RUBY_VOID_ANYARGS_FUNC(" : "VALUEFUNC(");
+    Append(setfname, ")");
 
     String *s = NewString("");
     switch (current) {
     case STATIC_VAR:
       /* C++ class variable */
       Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "\", ", getfname, ", 0);\n", NIL);
-      if (!GetFlag(n, "feature:immutable")) {
+      if (assignable) {
 	Printv(s, tab4, "rb_define_singleton_method(", klass->vname, ", \"", klass->strip(iname), "=\", ", setfname, ", 1);\n", NIL);
       }
       Printv(klass->init, s, NIL);
@@ -2279,14 +2292,11 @@
       assert(current == NO_CPP);
       if (!useGlobalModule) {
 	Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "\", ", getfname, ", 0);\n", NIL);
-	if (!GetFlag(n, "feature:immutable")) {
+	if (assignable) {
 	  Printv(s, tab4, "rb_define_singleton_method(", modvar, ", \"", iname, "=\", ", setfname, ", 1);\n", NIL);
 	}
       } else {
-	Printv(s, tab4, "rb_define_global_method(\"", iname, "\", ", getfname, ", 0);\n", NIL);
-	if (!GetFlag(n, "feature:immutable")) {
-	  Printv(s, tab4, "rb_define_global_method(\"", iname, "=\", ", setfname, ", 1);\n", NIL);
-	}
+	Printv(s, tab4, "rb_define_virtual_variable(\"$", iname, "\", ", getfname, ", ", setfname, ");\n", NIL);
       }
       Printv(f_init, s, NIL);
       Delete(s);
diff --git a/Tools/travis-linux-install.sh b/Tools/travis-linux-install.sh
index e902137..c8347d2 100755
--- a/Tools/travis-linux-install.sh
+++ b/Tools/travis-linux-install.sh
@@ -23,8 +23,8 @@
 		travis_retry sudo apt-get -qq install mono-devel
 		;;
 	"d")
-		travis_retry wget http://downloads.dlang.org/releases/2014/dmd_2.066.0-0_amd64.deb
-		travis_retry sudo dpkg -i dmd_2.066.0-0_amd64.deb
+		travis_retry wget http://downloads.dlang.org/releases/2.x/${VER}/dmd_${VER}-0_amd64.deb
+		travis_retry sudo dpkg -i dmd_${VER}-0_amd64.deb
 		;;
 	"go")
 		if [[ "$VER" ]]; then
@@ -95,6 +95,12 @@
 		travis_retry sudo apt-get -qq install r-base
 		;;
 	"ruby")
+		if [[ "$VER" == "2.7" ]]; then
+			# Ruby 2.7 support is currently only rvm master (30 Dec 2019)
+			travis_retry rvm get master
+			rvm reload
+			rvm list known
+		fi
 		if [[ "$VER" ]]; then
 			travis_retry rvm install $VER
 		fi
diff --git a/appveyor.yml b/appveyor.yml
index 42eaa36..f87cefd 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -16,10 +16,10 @@
   - SWIGLANG: python
     VSVER: 14
     VER: 27
-  - SWIGLANG: python
-    VSVER: 14
-    VER: 36
-    PY3: 3
+# - SWIGLANG: python
+#   VSVER: 14
+#   VER: 36
+#   PY3: 3
   - SWIGLANG: python
     OSVARIANT: cygwin
   - SWIGLANG: python
diff --git a/configure.ac b/configure.ac
index ea469c2..b4cadef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1348,6 +1348,33 @@
   JAVAC="$JAVACBIN"
 fi
 
+# Check Java version: we require Java 9 or later for Doxygen tests.
+if test -n "$JAVAC"; then
+    AC_MSG_CHECKING(if java version is 9 or greater)
+    javac_version=`"$JAVAC" -version 2>&1`
+    java_version_num=`echo $javac_version | sed -n 's/^javac //p'`
+    if test -z "$java_version_num"; then
+        AC_MSG_WARN([unknown format for Java version returned by "$JAVAC" ($javac_version)])
+        JAVA_SKIP_DOXYGEN_TEST_CASES=1
+        AC_MSG_RESULT(unknown)
+    else
+        dnl Until Java 8 version number was in format "1.x", starting from
+        dnl Java 9 it's just "x".
+        case $java_version_num in
+            1.*)
+                JAVA_SKIP_DOXYGEN_TEST_CASES=1
+                AC_MSG_RESULT([no, disabling Doxygen tests])
+                ;;
+
+            *)
+                AC_MSG_RESULT(yes)
+                ;;
+        esac
+    fi
+
+    AC_SUBST(JAVA_SKIP_DOXYGEN_TEST_CASES)
+fi
+
 AC_MSG_CHECKING(for java include file jni.h)
 AC_ARG_WITH(javaincl, [  --with-javaincl=path    Set location of Java include directory], [JAVAINCDIR="$withval"], [JAVAINCDIR=])
 
@@ -1408,15 +1435,6 @@
   fi
 fi
 
-# Javadoc support required for the Java test-suite is available by default in jdk9+ and in tools.jar in earlier jdk versions
-AC_MSG_CHECKING(for java tools.jar)
-if test -n "$JAVA_HOME" && test -r "$JAVA_HOME/lib/tools.jar" ; then
-  JAVA_TOOLS_JAR="$JAVA_HOME/lib/tools.jar"
-  AC_MSG_RESULT([$JAVA_TOOLS_JAR])
-else
-  AC_MSG_RESULT(not found)
-fi
-
 case $host in
 *-*-cygwin*)
         # TODO: Only use this flag if the compiler supports it, later versions of gcc no longer have it
@@ -1483,7 +1501,6 @@
 AC_SUBST(JAVAC)
 AC_SUBST(JAVAINC)
 AC_SUBST(JAVA_CLASSPATH_SEP)
-AC_SUBST(JAVA_TOOLS_JAR)
 AC_SUBST(JAVADYNAMICLINKING)
 AC_SUBST(JAVALIBRARYPREFIX)
 AC_SUBST(JAVASO)