merge from trunk

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/gsoc2009-sploving@11489 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Baozeng Ding 2009-08-02 01:20:12 +00:00
commit 21671f7534
86 changed files with 3689 additions and 502 deletions

View file

@ -1,6 +1,46 @@
Version 1.3.40 (in progress)
============================
2009-07-31: olly
[Python] Fix indentation so that we give a useful error if the
module can't be loaded. Patch from Gaetan Lehmann in SF#2829853.
2009-07-29: wsfulton
Add $typemap(method, typelist) special variable macro. This allows
the contents of a typemap to be inserted within another typemap.
Fully documented in Typemaps.html.
2009-07-29: vmiklos
[PHP] Static member variables are now prefixed with the
class name. This allows static member variables with the
same name in different classes.
2009-07-29: olly
[Python] Add missing locks to std::map wrappers. Patch from
Paul Hampson in SF#2813836.
2009-07-29: olly
[PHP] Fix memory leak in PHP OUTPUT typemaps. Reported by Hitoshi
Amano in SF#2826322.
2009-07-29: olly
[PHP] Fix memory leak in PHP resource destructor for classes
without a destructor and non-class types. Patch from Hitoshi Amano
in SF#2825303.
2009-07-28: olly
[PHP] Update warnings about clashes between identifiers and PHP
keywords and automatic renaming to work with the PHP5 class
wrappers. Fixes SF#1613679.
2009-07-28: vmiklos
[PHP] If a member function is not public but it has a base
which is public, then now a warning is issued and the member
function will be public, as PHP requires this.
2009-07-21: vmiklos
[PHP] Director support added.
2009-07-15: olly
[Perl] Don't specify Perl prototype "()" for a constructor with a
different name to the class, as such constructors can still take
@ -17,6 +57,10 @@ Version 1.3.40 (in progress)
of the manual. Based on patch from SF#2810380 by Christian
Gollwitzer.
2009-07-02: vmiklos
[PHP] Added factory.i for PHP, see the li_factory testcase
for more info on how to use it.
2009-07-02: wsfulton
Fix -Wallkw option as reported by Solomon Gibbs.
@ -24,6 +68,14 @@ Version 1.3.40 (in progress)
Fix syntax error when a nested struct contains a comment containing a * followed eventually by a /.
Regression from 1.3.37, reported by Solomon Gibbs.
2009-07-01: vmiklos
[PHP] Unknown properties are no longer ignored in proxy
classes.
2009-07-01: vmiklos
[PHP] Fixed %newobject behaviour, previously any method
marked with %newobject was handled as a constructor.
2009-06-30: olly
[Ruby] Undefine close and connect macros defined by Ruby API
headers as we don't need them and they can clash with C++ methods
@ -66,6 +118,12 @@ Version 1.3.40 (in progress)
*** POTENTIAL INCOMPATIBILITY ***
2009-05-20: vmiklos
[PHP] Add the 'thisown' member to classes. The usage of it
is the same as the Python thisown one: it's 1 by default and
you can set it to 0 if you want to prevent freeing it. (For
example to prevent a double free.)
2009-05-14: bhy
[Python] Fix the wrong pointer value returned by SwigPyObject_repr().

View file

@ -337,13 +337,13 @@
</ul>
<li><a href="Typemaps.html#Typemaps_nn10">Typemap specifications</a>
<ul>
<li><a href="Typemaps.html#Typemaps_nn11">Defining a typemap</a>
<li><a href="Typemaps.html#Typemaps_defining">Defining a typemap</a>
<li><a href="Typemaps.html#Typemaps_nn12">Typemap scope</a>
<li><a href="Typemaps.html#Typemaps_nn13">Copying a typemap</a>
<li><a href="Typemaps.html#Typemaps_nn14">Deleting a typemap</a>
<li><a href="Typemaps.html#Typemaps_nn15">Placement of typemaps</a>
</ul>
<li><a href="Typemaps.html#Typemaps_nn16">Pattern matching rules</a>
<li><a href="Typemaps.html#Typemaps_pattern_matching">Pattern matching rules</a>
<ul>
<li><a href="Typemaps.html#Typemaps_nn17">Basic matching rules</a>
<li><a href="Typemaps.html#Typemaps_nn18">Typedef reductions</a>
@ -356,6 +356,11 @@
<li><a href="Typemaps.html#Typemaps_nn22">Scope</a>
<li><a href="Typemaps.html#Typemaps_nn23">Declaring new local variables</a>
<li><a href="Typemaps.html#Typemaps_special_variables">Special variables</a>
<li><a href="Typemaps.html#Typemaps_special_variable_macros">Special variable macros</a>
<ul>
<li><a href="Typemaps.html#Typemaps_special_macro_descriptor">$descriptor(type)</a>
<li><a href="Typemaps.html#Typemaps_special_macro_typemap">$typemap(method, typepattern)</a>
</ul>
</ul>
<li><a href="Typemaps.html#Typemaps_nn25">Common typemap methods</a>
<ul>
@ -384,7 +389,7 @@
<li><a href="Typemaps.html#runtime_type_checker">The run-time type checker</a>
<ul>
<li><a href="Typemaps.html#Typemaps_nn45">Implementation</a>
<li><a href="Typemaps.html#Typemaps_nn46">Usage</a>
<li><a href="Typemaps.html#Typemaps_runtime_type_checker_usage">Usage</a>
</ul>
<li><a href="Typemaps.html#Typemaps_overloading">Typemaps and overloading</a>
<li><a href="Typemaps.html#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
@ -1115,7 +1120,7 @@
<li><a href="Perl5.html#Perl5_nn24">Modules and packages</a>
</ul>
<li><a href="Perl5.html#Perl5_nn25">Input and output parameters</a>
<li><a href="Perl5.html#Perl5_nn26">Exception handling </a>
<li><a href="Perl5.html#Perl5_nn26">Exception handling</a>
<li><a href="Perl5.html#Perl5_nn27">Remapping datatypes with typemaps</a>
<ul>
<li><a href="Perl5.html#Perl5_nn28">A simple typemap example</a>
@ -1125,8 +1130,8 @@
</ul>
<li><a href="Perl5.html#Perl5_nn32">Typemap Examples</a>
<ul>
<li><a href="Perl5.html#Perl5_nn33">Converting a Perl5 array to a char ** </a>
<li><a href="Perl5.html#Perl5_nn34">Return values </a>
<li><a href="Perl5.html#Perl5_nn33">Converting a Perl5 array to a char **</a>
<li><a href="Perl5.html#Perl5_nn34">Return values</a>
<li><a href="Perl5.html#Perl5_nn35">Returning values from arguments</a>
<li><a href="Perl5.html#Perl5_nn36">Accessing array structure members</a>
<li><a href="Perl5.html#Perl5_nn37">Turning Perl references into C pointers</a>
@ -1173,6 +1178,16 @@
</ul>
<li><a href="Php.html#Php_nn2_7">PHP Pragmas, Startup and Shutdown code</a>
</ul>
<li><a href="Php.html#Php_nn3">Cross language polymorphism</a>
<ul>
<li><a href="Php.html#Php_nn3_1">Enabling directors</a>
<li><a href="Php.html#Php_nn3_2">Director classes</a>
<li><a href="Php.html#Php_nn3_3">Ownership and object destruction</a>
<li><a href="Php.html#Php_nn3_4">Exception unrolling</a>
<li><a href="Php.html#Php_nn3_5">Overhead and code bloat</a>
<li><a href="Php.html#Php_nn3_6">Typemaps</a>
<li><a href="Php.html#Php_nn3_7">Miscellaneous</a>
</ul>
</ul>
</div>
<!-- INDEX -->
@ -1502,6 +1517,7 @@
<ul>
<li><a href="Tcl.html#Tcl_nn45">Proxy classes</a>
</ul>
<li><a href="Tcl.html#Tcl_nn46">Tcl/Tk Stubs</a>
</ul>
</div>
<!-- INDEX -->

View file

@ -32,6 +32,16 @@
</ul>
<li><a href="#Php_nn2_7">PHP Pragmas, Startup and Shutdown code</a>
</ul>
<li><a href="#Php_nn3">Cross language polymorphism</a>
<ul>
<li><a href="#Php_nn3_1">Enabling directors</a>
<li><a href="#Php_nn3_2">Director classes</a>
<li><a href="#Php_nn3_3">Ownership and object destruction</a>
<li><a href="#Php_nn3_4">Exception unrolling</a>
<li><a href="#Php_nn3_5">Overhead and code bloat</a>
<li><a href="#Php_nn3_6">Typemaps</a>
<li><a href="#Php_nn3_7">Miscellaneous</a>
</ul>
</ul>
</div>
<!-- INDEX -->
@ -866,5 +876,381 @@ The <tt>%rinit</tt> and <tt>%rshutdown</tt> statements insert code
into the request init and shutdown code respectively.
</p>
<H2><a name="Php_nn3"></a>29.3 Cross language polymorphism</H2>
<p>
Proxy classes provide a more natural, object-oriented way to access
extension classes. As described above, each proxy instance has an
associated C++ instance, and method calls to the proxy are passed to the
C++ instance transparently via C wrapper functions.
</p>
<p>
This arrangement is asymmetric in the sense that no corresponding
mechanism exists to pass method calls down the inheritance chain from
C++ to PHP. In particular, if a C++ class has been extended in PHP
(by extending the proxy class), these extensions will not be visible
from C++ code. Virtual method calls from C++ are thus not able access
the lowest implementation in the inheritance chain.
</p>
<p>
Changes have been made to SWIG 1.3.18 to address this problem and make
the relationship between C++ classes and proxy classes more symmetric.
To achieve this goal, new classes called directors are introduced at the
bottom of the C++ inheritance chain. Support for generating PHP classes
has been added in SWIG 1.3.40. The job of the directors is to route
method calls correctly, either to C++ implementations higher in the
inheritance chain or to PHP implementations lower in the inheritance
chain. The upshot is that C++ classes can be extended in PHP and from
C++ these extensions look exactly like native C++ classes. Neither C++
code nor PHP code needs to know where a particular method is
implemented: the combination of proxy classes, director classes, and C
wrapper functions takes care of all the cross-language method routing
transparently.
</p>
<H3><a name="Php_nn3_1"></a>29.3.1 Enabling directors</H3>
<p>
The director feature is disabled by default. To use directors you
must make two changes to the interface file. First, add the "directors"
option to the %module directive, like this:
</p>
<div class="code">
<pre>
%module(directors="1") modulename
</pre>
</div>
<p>
Without this option no director code will be generated. Second, you
must use the %feature("director") directive to tell SWIG which classes
and methods should get directors. The %feature directive can be applied
globally, to specific classes, and to specific methods, like this:
</p>
<div class="code">
<pre>
// generate directors for all classes that have virtual methods
%feature("director");
// generate directors for all virtual methods in class Foo
%feature("director") Foo;
// generate a director for just Foo::bar()
%feature("director") Foo::bar;
</pre>
</div>
<p>
You can use the %feature("nodirector") directive to turn off
directors for specific classes or methods. So for example,
</p>
<div class="code">
<pre>
%feature("director") Foo;
%feature("nodirector") Foo::bar;
</pre>
</div>
<p>
will generate directors for all virtual methods of class Foo except
bar().
</p>
<p>
Directors can also be generated implicitly through inheritance.
In the following, class Bar will get a director class that handles
the methods one() and two() (but not three()):
</p>
<div class="code">
<pre>
%feature("director") Foo;
class Foo {
public:
Foo(int foo);
virtual void one();
virtual void two();
};
class Bar: public Foo {
public:
virtual void three();
};
</pre>
</div>
<p>
then at the PHP side you can define
</p>
<div class="targetlang">
<pre>
require("mymodule.php");
class MyFoo extends Foo {
function one() {
print "one from php\n";
}
}
</pre>
</div>
<H3><a name="Php_nn3_2"></a>29.3.2 Director classes</H3>
<p>
For each class that has directors enabled, SWIG generates a new class
that derives from both the class in question and a special
<tt>Swig::Director</tt> class. These new classes, referred to as director
classes, can be loosely thought of as the C++ equivalent of the PHP
proxy classes. The director classes store a pointer to their underlying
PHP object. Indeed, this is quite similar to the "_cPtr" and "thisown"
members of the PHP proxy classes.
</p>
<p>
For simplicity let's ignore the <tt>Swig::Director</tt> class and refer to the
original C++ class as the director's base class. By default, a director
class extends all virtual methods in the inheritance chain of its base
class (see the preceding section for how to modify this behavior).
Thus all virtual method calls, whether they originate in C++ or in
PHP via proxy classes, eventually end up in at the implementation in the
director class. The job of the director methods is to route these method
calls to the appropriate place in the inheritance chain. By "appropriate
place" we mean the method that would have been called if the C++ base
class and its extensions in PHP were seamlessly integrated. That
seamless integration is exactly what the director classes provide,
transparently skipping over all the messy extension API glue that binds
the two languages together.
</p>
<p>
In reality, the "appropriate place" is one of only two possibilities:
C++ or PHP. Once this decision is made, the rest is fairly easy. If the
correct implementation is in C++, then the lowest implementation of the
method in the C++ inheritance chain is called explicitly. If the correct
implementation is in PHP, the Zend API is used to call the method of the
underlying PHP object (after which the usual virtual method resolution
in PHP automatically finds the right implementation).
</p>
<p>
Now how does the director decide which language should handle the method call?
The basic rule is to handle the method in PHP, unless there's a good
reason not to. The reason for this is simple: PHP has the most
"extended" implementation of the method. This assertion is guaranteed,
since at a minimum the PHP proxy class implements the method. If the
method in question has been extended by a class derived from the proxy
class, that extended implementation will execute exactly as it should.
If not, the proxy class will route the method call into a C wrapper
function, expecting that the method will be resolved in C++. The wrapper
will call the virtual method of the C++ instance, and since the director
extends this the call will end up right back in the director method. Now
comes the "good reason not to" part. If the director method were to blindly
call the PHP method again, it would get stuck in an infinite loop. We avoid this
situation by adding special code to the C wrapper function that tells
the director method to not do this. The C wrapper function compares the
called and the declaring class name of the given method. If these are
not the same, then the C wrapper function tells the director to resolve
the method by calling up the C++ inheritance chain, preventing an
infinite loop.
</p>
<p>
One more point needs to be made about the relationship between director
classes and proxy classes. When a proxy class instance is created in
PHP, SWIG creates an instance of the original C++ class and assigns it
to <tt>-&gt;_cPtr</tt>. This is exactly what happens without directors
and is true even if directors are enabled for the particular class in
question. When a class <i>derived</i> from a proxy class is created,
however, SWIG then creates an instance of the corresponding C++ director
class. The reason for this difference is that user-defined subclasses
may override or extend methods of the original class, so the director
class is needed to route calls to these methods correctly. For
unmodified proxy classes, all methods are ultimately implemented in C++
so there is no need for the extra overhead involved with routing the
calls through PHP.
</p>
<H3><a name="Php_nn3_3"></a>29.3.3 Ownership and object destruction</H3>
<p>
Memory management issues are slightly more complicated with directors
than for proxy classes alone. PHP instances hold a pointer to the
associated C++ director object, and the director in turn holds a pointer
back to the PHP object. By default, proxy classes own their C++ director
object and take care of deleting it when they are garbage collected.
</p>
<p>
This relationship can be reversed by calling the special
<tt>-&gt;thisown</tt> property of the proxy class. After setting this
property to <tt>0</tt>, the director class no longer destroys the PHP
object. Assuming no outstanding references to the PHP object remain,
the PHP object will be destroyed at the same time. This is a good thing,
since directors and proxies refer to each other and so must be created
and destroyed together. Destroying one without destroying the other will
likely cause your program to segfault.
</p>
<p>
Here is an example:
</p>
<div class="code">
<pre>
class Foo {
public:
...
};
class FooContainer {
public:
void addFoo(Foo *);
...
};
</pre>
</div>
<br>
<div class="targetlang">
<pre>
$c = new FooContainer();
$a = new Foo();
$a-&gt;thisown = 0;
$c-&gt;addFoo($a);
</pre>
</div>
<p>
In this example, we are assuming that FooContainer will take care of
deleting all the Foo pointers it contains at some point.
</p>
<H3><a name="Php_nn3_4"></a>29.3.4 Exception unrolling</H3>
<p>
With directors routing method calls to PHP, and proxies routing them
to C++, the handling of exceptions is an important concern. By default, the
directors ignore exceptions that occur during method calls that are
resolved in PHP. To handle such exceptions correctly, it is necessary
to temporarily translate them into C++ exceptions. This can be done with
the %feature("director:except") directive. The following code should
suffice in most cases:
</p>
<div class="code">
<pre>
%feature("director:except") {
if ($error == FAILURE) {
throw Swig::DirectorMethodException();
}
}
</pre>
</div>
<p>
This code will check the PHP error state after each method call from a
director into PHP, and throw a C++ exception if an error occurred. This
exception can be caught in C++ to implement an error handler.
Currently no information about the PHP error is stored in the
Swig::DirectorMethodException object, but this will likely change in the
future.
</p>
<p>
It may be the case that a method call originates in PHP, travels up to
C++ through a proxy class, and then back into PHP via a director method.
If an exception occurs in PHP at this point, it would be nice for that
exception to find its way back to the original caller. This can be done
by combining a normal %exception directive with the
<tt>director:except</tt> handler shown above. Here is an example of a
suitable exception handler:
</p>
<div class="code">
<pre>
%exception {
try { $action }
catch (Swig::DirectorException &amp;e) { SWIG_fail; }
}
</pre>
</div>
<p>
The class Swig::DirectorException used in this example is actually a
base class of Swig::DirectorMethodException, so it will trap this
exception. Because the PHP error state is still set when
Swig::DirectorMethodException is thrown, PHP will register the exception
as soon as the C wrapper function returns.
</p>
<H3><a name="Php_nn3_5"></a>29.3.5 Overhead and code bloat</H3>
<p>
Enabling directors for a class will generate a new director method for
every virtual method in the class' inheritance chain. This alone can
generate a lot of code bloat for large hierarchies. Method arguments
that require complex conversions to and from target language types can
result in large director methods. For this reason it is recommended that
you selectively enable directors only for specific classes that are
likely to be extended in PHP and used in C++.
</p>
<p>
Compared to classes that do not use directors, the call routing in the
director methods does add some overhead. In particular, at least one
dynamic cast and one extra function call occurs per method call from
PHP. Relative to the speed of PHP execution this is probably completely
negligible. For worst case routing, a method call that ultimately
resolves in C++ may take one extra detour through PHP in order to ensure
that the method does not have an extended PHP implementation. This could
result in a noticeable overhead in some cases.
</p>
<p>
Although directors make it natural to mix native C++ objects with PHP
objects (as director objects) via a common base class pointer, one
should be aware of the obvious fact that method calls to PHP objects
will be much slower than calls to C++ objects. This situation can be
optimized by selectively enabling director methods (using the %feature
directive) for only those methods that are likely to be extended in PHP.
</p>
<H3><a name="Php_nn3_6"></a>29.3.6 Typemaps</H3>
<p>
Typemaps for input and output of most of the basic types from director
classes have been written. These are roughly the reverse of the usual
input and output typemaps used by the wrapper code. The typemap
operation names are 'directorin', 'directorout', and 'directorargout'.
The director code does not currently use any of the other kinds of
typemaps. It is not clear at this point which kinds are appropriate and
need to be supported.
</p>
<H3><a name="Php_nn3_7"></a>29.3.7 Miscellaneous</H3>
<p> Director typemaps for STL classes are mostly in place, and hence you
should be able to use std::string, etc., as you would any other type.
</p>
</body>
</html>

View file

@ -25,8 +25,8 @@
<li><a href="#scilab_nn10">Global variables</a>
<li><a href="#Scilab_nn11">Constants</a>
<li><a href="#Scilab_nn12">Enums</a>
<li><a href="#Octave_nn13">Pointers</a>
<li><a href="#Octave_nn14">Structs</a>
<li><a href="#Scilab_nn13">Pointers</a>
<li><a href="#Scilab_nn14">Structs</a>
</ul>
</ul>
</div>
@ -315,7 +315,7 @@ scilab:4&gt; printf(" GREEN = %i\n", color.GREEN);
</pre></div>
<H3><a name="Octave_nn13"></a>27.3.5 Pointers</H3>
<H3><a name="Scilab_nn13"></a>27.3.5 Pointers</H3>
<p>
Pointers are fully supported by SWIG. One way to deal with the pointers is using the INPUT and OUTPUT typemaps. For example, in order to call C functions as the following:
</p>
@ -356,7 +356,7 @@ scilab:4&gt; printf(" 42/37 = %d remainder %d\n",q,r);
we only need a real value instead.
</p>
<H3><a name="Octave_nn14"></a>27.3.6 Structs</H3>
<H3><a name="Scilab_nn14"></a>27.3.6 Structs</H3>
<p>
SWIG creates a set of accessor functions when encountering a structure or union. For example:
</p>

View file

@ -3412,6 +3412,7 @@ interesting things.
<H2><a name="Tcl_nn46"></a>33.10 Tcl/Tk Stubs</H2>
<p>
For background information about the Tcl Stubs feature, see
<a href="http://www.tcl.tk/doc/howto/stubs.html">http://www.tcl.tk/doc/howto/stubs.html</a>.

View file

@ -22,13 +22,13 @@
</ul>
<li><a href="#Typemaps_nn10">Typemap specifications</a>
<ul>
<li><a href="#Typemaps_nn11">Defining a typemap</a>
<li><a href="#Typemaps_defining">Defining a typemap</a>
<li><a href="#Typemaps_nn12">Typemap scope</a>
<li><a href="#Typemaps_nn13">Copying a typemap</a>
<li><a href="#Typemaps_nn14">Deleting a typemap</a>
<li><a href="#Typemaps_nn15">Placement of typemaps</a>
</ul>
<li><a href="#Typemaps_nn16">Pattern matching rules</a>
<li><a href="#Typemaps_pattern_matching">Pattern matching rules</a>
<ul>
<li><a href="#Typemaps_nn17">Basic matching rules</a>
<li><a href="#Typemaps_nn18">Typedef reductions</a>
@ -41,6 +41,11 @@
<li><a href="#Typemaps_nn22">Scope</a>
<li><a href="#Typemaps_nn23">Declaring new local variables</a>
<li><a href="#Typemaps_special_variables">Special variables</a>
<li><a href="#Typemaps_special_variable_macros">Special variable macros</a>
<ul>
<li><a href="#Typemaps_special_macro_descriptor">$descriptor(type)</a>
<li><a href="#Typemaps_special_macro_typemap">$typemap(method, typepattern)</a>
</ul>
</ul>
<li><a href="#Typemaps_nn25">Common typemap methods</a>
<ul>
@ -69,7 +74,7 @@
<li><a href="#runtime_type_checker">The run-time type checker</a>
<ul>
<li><a href="#Typemaps_nn45">Implementation</a>
<li><a href="#Typemaps_nn46">Usage</a>
<li><a href="#Typemaps_runtime_type_checker_usage">Usage</a>
</ul>
<li><a href="#Typemaps_overloading">Typemaps and overloading</a>
<li><a href="#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
@ -655,7 +660,7 @@ of "The C Programming Language" by Kernighan and Ritchie or
This section describes the behavior of the <tt>%typemap</tt> directive itself.
</p>
<H3><a name="Typemaps_nn11"></a>10.2.1 Defining a typemap</H3>
<H3><a name="Typemaps_defining"></a>10.2.1 Defining a typemap</H3>
<p>
@ -988,7 +993,7 @@ It should be noted that for scoping to work, SWIG has to know that <tt>string</t
within a particular namespace. In this example, this is done using the class declaration <tt>class string</tt>.
</p>
<H2><a name="Typemaps_nn16"></a>10.3 Pattern matching rules</H2>
<H2><a name="Typemaps_pattern_matching"></a>10.3 Pattern matching rules</H2>
<p>
@ -1646,6 +1651,7 @@ each type must have its own local variable declaration.
<p>
Within all typemaps, the following special variables are expanded.
This is by no means a complete list as some target languages have additional special variables which are documented in the language specific chapters.
</p>
<center>
@ -1892,6 +1898,86 @@ Another approach, which only works for arrays is to use the <tt>$1_basetype</tt>
</pre>
</div>
<H3><a name="Typemaps_special_variable_macros"></a>10.4.4 Special variable macros</H3>
<p>
Special variable macros are like macro functions in that they take one or more input arguments
which are used for the macro expansion.
They look like macro/function calls but use the special variable <tt>$</tt> prefix to the macro name.
Note that unlike normal macros, the expansion is not done by the preprocessor,
it is done during the SWIG parsing/compilation stages.
The following special variable macros are available across all language modules.
</p>
<H4><a name="Typemaps_special_macro_descriptor"></a>10.4.4.1 $descriptor(type)</H4>
<p>
This macro expands into the type descriptor structure for any C/C++ type specified in <tt>type</tt>.
It behaves like the <tt>$1_descriptor</tt> special variable described above except that the type to expand is
taken from the macro argument rather than inferred from the typemap type.
For example, <tt>$descriptor(std::vector&lt;int&gt; *)</tt> will expand into <tt>SWIGTYPE_p_std__vectorT_int_t</tt>.
This macro is mostly used in the scripting target languages and is demonstrated later in the <a href="#Typemaps_runtime_type_checker_usage">Run-time type checker usage</a> section.
</p>
<H4><a name="Typemaps_special_macro_typemap"></a>10.4.4.2 $typemap(method, typepattern)</H4>
<p>
This macro uses the <a href="#Typemaps_pattern_matching">pattern matching rules</a> described earlier to lookup and
then substitute the special variable macro with the code in the matched typemap.
The typemap to search for is specified by the arguments, where <tt>method</tt> is the typemap method name and
<tt>typepattern</tt> is a type pattern as per the <tt>%typemap</tt> specification in the <a href="#Typemaps_defining">Defining a typemap</a> section.
</p>
<p>
The special variables within the matched typemap are expanded into those for the matched typemap type,
not the typemap within which the macro is called.
In practice, there is little use for this macro in the scripting target languages.
It is mostly used in the target languages that are statically typed as a way to obtain the target language type given the C/C++ type and more commonly only when the C++ type is a template parameter.
</p>
<p>
The example below is for C# only and uses some typemap method names documented in the C# chapter, but it shows some of the possible syntax variations.
</p>
<div class="code">
<pre>
%typemap(cstype) unsigned long "uint"
%typemap(cstype) unsigned long bb "bool"
%typemap(cscode) BarClass %{
void foo($typemap(cstype, unsigned long aa) var1,
$typemap(cstype, unsigned long bb) var2,
$typemap(cstype, (unsigned long bb)) var3,
$typemap(cstype, unsigned long) var4)
{
// do something
}
%}
</pre>
</div>
<p>
The result is the following expansion
</p>
<div class="code">
<pre>
%typemap(cstype) unsigned long "uint"
%typemap(cstype) unsigned long bb "bool"
%typemap(cscode) BarClass %{
void foo(uint var1,
bool var2,
bool var3,
uint var4)
{
// do something
}
%}
</pre>
</div>
<H2><a name="Typemaps_nn25"></a>10.5 Common typemap methods</H2>
@ -3295,7 +3381,7 @@ structures rather than creating new ones. These <tt>swig_module_info</tt>
structures are chained together in a circularly linked list.
</p>
<H3><a name="Typemaps_nn46"></a>10.10.2 Usage</H3>
<H3><a name="Typemaps_runtime_type_checker_usage"></a>10.10.2 Usage</H3>
<p>This section covers how to use these functions from typemaps. To learn how to
@ -3335,8 +3421,8 @@ type tables and improves efficiency.
<p>
Occasionally, you might need to write a typemap that needs to convert
pointers of other types. To handle this, a special macro substitution
<tt>$descriptor(type)</tt> can be used to generate the SWIG type
pointers of other types. To handle this, the special variable macro
<tt>$descriptor(type)</tt> covered earlier can be used to generate the SWIG type
descriptor name for any C datatype. For example:
</p>

View file

@ -0,0 +1,22 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = example.cxx
TARGET = example
INTERFACE = example.i
LIBS = -lm
SWIGOPT =
all::
$(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' php_cpp
static::
$(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
SWIGOPT='$(SWIGOPT)' TARGET='myphp' INTERFACE='$(INTERFACE)' php_cpp_static
clean::
$(MAKE) -f $(TOP)/Makefile php_clean
rm -f $(TARGET).php
check: all
$(MAKE) -f $(TOP)/Makefile php_run

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,22 @@
/* File : example.h */
#include <iostream>
class Callback {
public:
virtual ~Callback() { std::cout << "Callback::~Callback()" << std:: endl; }
virtual void run() { std::cout << "Callback::run()" << std::endl; }
};
class Caller {
private:
Callback *_callback;
public:
Caller(): _callback(0) {}
~Caller() { delCallback(); }
void delCallback() { delete _callback; _callback = 0; }
void setCallback(Callback *cb) { delCallback(); _callback = cb; }
void call() { if (_callback) _callback->run(); }
};

View file

@ -0,0 +1,13 @@
/* File : example.i */
%module(directors="1") example
%{
#include "example.h"
%}
%include "std_string.i"
/* turn on director wrapping Callback */
%feature("director") Callback;
%include "example.h"

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>SWIG:Examples:php:callback</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/php/callback/</tt>
<hr>
<H2>Implementing C++ callbacks in PHP</H2>
<p>
This example illustrates how to use directors to implement C++ callbacks in PHP.
<hr>
</body>
</html>

View file

@ -0,0 +1,47 @@
<?php
# This file illustrates the cross language polymorphism using directors.
require("example.php");
# Class, which overwrites Callback::run().
class PhpCallback extends Callback {
function run() {
print "PhpCallback.run()\n";
}
};
# Create an Caller instance
$caller = new Caller();
# Add a simple C++ callback (caller owns the callback, so
# we disown it first by clearing the .thisown flag).
print "Adding and calling a normal C++ callback\n";
print "----------------------------------------\n";
$callback = new Callback();
$callback->thisown = 0;
$caller->setCallback($callback);
$caller->call();
$caller->delCallback();
print "\n";
print "Adding and calling a PHP callback\n";
print "------------------------------------\n";
# Add a PHP callback.
$callback = new PhpCallback();
$callback->thisown = 0;
$caller->setCallback($callback);
$caller->call();
$caller->delCallback();
# All done.
print "php exit\n";
?>

View file

@ -0,0 +1,22 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
CXXSRCS = example.cxx
TARGET = example
INTERFACE = example.i
LIBS = -lm
SWIGOPT =
all::
$(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' php_cpp
static::
$(MAKE) -f $(TOP)/Makefile $(SWIGLIB) CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \
SWIGOPT='$(SWIGOPT)' TARGET='myphp' INTERFACE='$(INTERFACE)' php_cpp_static
clean::
$(MAKE) -f $(TOP)/Makefile php_clean
rm -f $(TARGET).php
check: all
$(MAKE) -f $(TOP)/Makefile php_run

View file

@ -0,0 +1,4 @@
/* File : example.cxx */
#include "example.h"

View file

@ -0,0 +1,56 @@
/* File : example.h */
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
class Employee {
private:
std::string name;
public:
Employee(const char* n): name(n) {}
virtual std::string getTitle() { return getPosition() + " " + getName(); }
virtual std::string getName() { return name; }
virtual std::string getPosition() const { return "Employee"; }
virtual ~Employee() { printf("~Employee() @ %p\n", this); }
};
class Manager: public Employee {
public:
Manager(const char* n): Employee(n) {}
virtual std::string getPosition() const { return "Manager"; }
};
class EmployeeList {
std::vector<Employee*> list;
public:
EmployeeList() {
list.push_back(new Employee("Bob"));
list.push_back(new Employee("Jane"));
list.push_back(new Manager("Ted"));
}
void addEmployee(Employee *p) {
list.push_back(p);
std::cout << "New employee added. Current employees are:" << std::endl;
std::vector<Employee*>::iterator i;
for (i=list.begin(); i!=list.end(); i++) {
std::cout << " " << (*i)->getTitle() << std::endl;
}
}
const Employee *get_item(int i) {
return list[i];
}
~EmployeeList() {
std::vector<Employee*>::iterator i;
std::cout << "~EmployeeList, deleting " << list.size() << " employees." << std::endl;
for (i=list.begin(); i!=list.end(); i++) {
delete *i;
}
std::cout << "~EmployeeList empty." << std::endl;
}
};

View file

@ -0,0 +1,15 @@
/* File : example.i */
%module(directors="1") example
%{
#include "example.h"
%}
%include "std_vector.i"
%include "std_string.i"
/* turn on director wrapping for Manager */
%feature("director") Employee;
%feature("director") Manager;
%include "example.h"

View file

@ -0,0 +1,19 @@
<html>
<head>
<title>SWIG:Examples:php:extend</title>
</head>
<body bgcolor="#ffffff">
<tt>SWIG/Examples/php/extend/</tt>
<hr>
<H2>Extending a simple C++ class in PHP</H2>
<p>
This example illustrates the extending of a C++ class with cross language polymorphism.
<hr>
</body>
</html>

View file

@ -0,0 +1,76 @@
<?php
# This file illustrates the cross language polymorphism using directors.
require("example.php");
# CEO class, which overrides Employee::getPosition().
class CEO extends Manager {
function getPosition() {
return "CEO";
}
}
# Create an instance of our employee extension class, CEO. The calls to
# getName() and getPosition() are standard, the call to getTitle() uses
# the director wrappers to call CEO.getPosition.
$e = new CEO("Alice");
print $e->getName() . " is a " . $e->getPosition() . "\n";
printf("Just call her \"%s\"\n", $e->getTitle());
print "----------------------\n";
# Create a new EmployeeList instance. This class does not have a C++
# director wrapper, but can be used freely with other classes that do.
$list = new EmployeeList();
# EmployeeList owns its items, so we must surrender ownership of objects
# we add. This involves first clearing the ->disown member to tell the
# C++ director to start reference counting.
$e->thisown = 0;
$list->addEmployee($e);
print "----------------------\n";
# Now we access the first four items in list (three are C++ objects that
# EmployeeList's constructor adds, the last is our CEO). The virtual
# methods of all these instances are treated the same. For items 0, 1, and
# 2, both all methods resolve in C++. For item 3, our CEO, getTitle calls
# getPosition which resolves in PHP. The call to getPosition is
# slightly different, however, from the e.getPosition() call above, since
# now the object reference has been "laundered" by passing through
# EmployeeList as an Employee*. Previously, PHP resolved the call
# immediately in CEO, but now PHP thinks the object is an instance of
# class Employee (actually EmployeePtr). So the call passes through the
# Employee proxy class and on to the C wrappers and C++ director,
# eventually ending up back at the CEO implementation of getPosition().
# The call to getTitle() for item 3 runs the C++ Employee::getTitle()
# method, which in turn calls getPosition(). This virtual method call
# passes down through the C++ director class to the PHP implementation
# in CEO. All this routing takes place transparently.
print "(position, title) for items 0-3:\n";
printf(" %s, \"%s\"\n", $list->get_item(0)->getPosition(), $list->get_item(0)->getTitle());
printf(" %s, \"%s\"\n", $list->get_item(1)->getPosition(), $list->get_item(1)->getTitle());
printf(" %s, \"%s\"\n", $list->get_item(2)->getPosition(), $list->get_item(2)->getTitle());
printf(" %s, \"%s\"\n", $list->get_item(3)->getPosition(), $list->get_item(3)->getTitle());
print "----------------------\n";
# Time to delete the EmployeeList, which will delete all the Employee*
# items it contains. The last item is our CEO, which gets destroyed as its
# reference count goes to zero. The PHP destructor runs, and is still
# able to call the getName() method since the underlying C++ object still
# exists. After this destructor runs the remaining C++ destructors run as
# usual to destroy the object.
unset($list);
print "----------------------\n";
# All done.
print "php exit\n";
?>

View file

@ -1,6 +1,5 @@
/* File : example.h */
#include <cstdio>
#include <iostream>
class Callback {

View file

@ -292,6 +292,7 @@ CPP_TEST_CASES += \
smart_pointer_templatevariables \
smart_pointer_typedef \
special_variables \
special_variable_macros \
static_array_member \
static_const_member \
static_const_member_2 \

View file

@ -0,0 +1,20 @@
using System;
using special_variable_macrosNamespace;
public class runme {
static void Main() {
Name name = new Name();
if (special_variable_macros.testFred(name) != "none")
throw new Exception("test failed");
if (special_variable_macros.testJack(name) != "$specialname")
throw new Exception("test failed");
if (special_variable_macros.testJill(name) != "jilly")
throw new Exception("test failed");
if (special_variable_macros.testMary(name) != "SWIGTYPE_p_NameWrap")
throw new Exception("test failed");
if (special_variable_macros.testJim(name) != "multiname num")
throw new Exception("test failed");
NewName newName = NewName.factory("factoryname");
name = newName.getStoredName();
}
}

View file

@ -25,7 +25,10 @@
"$csclassname.getCPtr(d$csinput)"
// post only in csin typemap
%typemap(csin, post=" int size = $csinput.Count;\n for (int i=0; i<size; ++i) {\n $csinput[i] /= 100;\n }") std::vector<double> &vpost
%typemap(csin, post=" int size = $csinput.Count;\n"
" for (int i=0; i<size; ++i) {\n"
" $csinput[i] /= 100;\n"
" }") std::vector<double> &vpost
"$csclassname.getCPtr($csinput)"
%inline %{

View file

@ -15,7 +15,9 @@
%feature("director") Foo;
%newobject Foo::cloner();
%newobject Foo::get_class();
%newobject Bar::cloner();
%newobject Bar::get_class();
%inline {

View file

@ -11,6 +11,13 @@
%newobject *::create();
#ifdef SWIGPHP
// TODO: Currently we do not track the dynamic type of returned objects
// in PHP, so we need the factory helper.
%include factory.i
%factory(Foo *Bar::create, Bar);
#endif
%rename(a) Bar::hello;
%rename(s) Foo::p;
%rename(q) Foo::r;

View file

@ -17,7 +17,11 @@
%feature("director") Foo;
%feature("director:except") {
#ifndef SWIGPHP
if ($error != NULL) {
#else
if ($error == FAILURE) {
#endif
throw Swig::DirectorMethodException();
}
}

View file

@ -1,5 +1,7 @@
%module(directors="1",dirprot="1") director_using
%warnfilter(SWIGWARN_PHP_PUBLIC_BASE) FooBar;
%{
#include <string>
#include <iostream>

View file

@ -0,0 +1,30 @@
import special_variable_macros.*;
public class special_variable_macros_runme {
static {
try {
System.loadLibrary("special_variable_macros");
} 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[]) {
Name name = new Name();
if (!special_variable_macros.testFred(name).equals("none"))
throw new RuntimeException("test failed");
if (!special_variable_macros.testJack(name).equals("$specialname"))
throw new RuntimeException("test failed");
if (!special_variable_macros.testJill(name).equals("jilly"))
throw new RuntimeException("test failed");
if (!special_variable_macros.testMary(name).equals("SWIGTYPE_p_NameWrap"))
throw new RuntimeException("test failed");
if (!special_variable_macros.testJim(name).equals("multiname num"))
throw new RuntimeException("test failed");
NewName newName = NewName.factory("factoryname");
name = newName.getStoredName();
}
}

View file

@ -6,6 +6,9 @@
%newobject Geometry::clone;
%factory(Geometry *Geometry::create, Point, Circle);
%factory(Geometry *Geometry::clone, Point, Circle);
#ifdef SWIGPHP
%rename(clone_) clone;
#endif
%factory(Geometry *Point::clone, Point, Circle);
%factory(Geometry *Circle::clone, Point, Circle);

View file

@ -35,7 +35,9 @@ namespace std
{
typedef complex None;
#ifndef SWIGPHP // clone() *is* an invalid method name in PHP.
A* clone(int) { return NULL; }
#endif
virtual ~A() {}
virtual int func() = 0;

View file

@ -12,7 +12,6 @@
%rename(PlusPlusPostfix) operator++(int);
#endif
%{
#include <iostream>
using namespace std;
@ -56,7 +55,7 @@ public:
Op& operator++() {k++; return *this;}
void Print() {std::cerr << k << std::endl;}
void PrintK() {std::cerr << k << std::endl;}
int k;
};

View file

@ -8,8 +8,8 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
#CPP_TEST_CASES += \
# php_namewarn_rename \
CPP_TEST_CASES += \
php_namewarn_rename \
include $(srcdir)/../common.mk
@ -17,7 +17,7 @@ include $(srcdir)/../common.mk
TARGETPREFIX =# Should be php_ for Windows, empty otherwise
# Custom tests - tests with additional commandline options
# none!
prefix.cpptest: SWIGOPT += -prefix Project
# write out tests without a _runme.php
missingcpptests:

View file

@ -0,0 +1,62 @@
<?php
require "tests.php";
require "director_abstract.php";
// No new functions
check::functions(array(foo_ping,foo_pong,example0_getxsize,example0_color,example0_get_color,example1_getxsize,example1_color,example1_get_color,example2_getxsize,example2_color,example2_get_color,example4_getxsize,example4_color,example4_get_color,example3_i_color,example3_i_get_color,g,a_f));
// No new classes
check::classes(array(director_abstract,Foo,Example0,Example1,Example2,Example4,Example3_i,A));
// now new vars
check::globals(array());
class MyFoo extends Foo {
function ping() {
return "MyFoo::ping()";
}
}
$a = new MyFoo();
check::equal($a->ping(), "MyFoo::ping()", "MyFoo::ping failed");
check::equal($a->pong(), "Foo::pong();MyFoo::ping()", "MyFoo::pong failed");
class MyExample1 extends Example1 {
function Color($r, $g, $b) {
return $r;
}
}
class MyExample2 extends Example1 {
function Color($r, $g, $b) {
return $g;
}
}
class MyExample3 extends Example1 {
function Color($r, $g, $b) {
return $b;
}
}
$me1 = new MyExample1();
check::equal($me1->Color(1, 2, 3), 1, "Example1_get_color failed");
$me2 = new MyExample2(1, 2);
check::equal($me2->Color(1, 2, 3), 2, "Example2_get_color failed");
$me3 = new MyExample3();
check::equal($me3->Color(1, 2, 3), 3, "Example3_get_color failed");
$class = new ReflectionClass('Example1');
check::equal($class->isAbstract(), true, "Example1 abstractness failed");
$class = new ReflectionClass('Example2');
check::equal($class->isAbstract(), true, "Example2 abstractness failed");
$class = new ReflectionClass('Example3_i');
check::equal($class->isAbstract(), true, "Example3_i abstractness failed");
check::done();
?>

View file

@ -0,0 +1,58 @@
<?php
require "tests.php";
require "director_basic.php";
// No new functions
check::functions(array(foo_ping,foo_pong,foo_get_self,a_f,a_rg,a1_ff,myclass_method,myclass_vmethod,myclass_pmethod,myclass_cmethod,myclass_get_self,myclass_call_pmethod,myclasst_i_method));
// No new classes
check::classes(array(Foo,A,A1,Bar,MyClass,MyClassT_i));
// now new vars
check::globals(array(bar_x));
class PhpFoo extends Foo {
function ping() {
return "PhpFoo::ping()";
}
}
$a = new PhpFoo();
check::equal($a->ping(), "PhpFoo::ping()", "ping failed");
check::equal($a->pong(), "Foo::pong();PhpFoo::ping()", "pong failed");
$b = new Foo();
check::equal($b->ping(), "Foo::ping()", "ping failed");
check::equal($b->pong(), "Foo::pong();Foo::ping()", "pong failed");
$a = new A1(1);
check::equal($a->rg(2), 2, "rg failed");
class PhpClass extends MyClass {
function vmethod($b) {
$b->x = $b->x + 31;
return $b;
}
}
$b = new Bar(3);
$d = new MyClass();
$c = new PhpClass();
$cc = MyClass::get_self($c);
$dd = MyClass::get_self($d);
$bc = $cc->cmethod($b);
$bd = $dd->cmethod($b);
$cc->method($b);
check::equal($bc->x, 34, "bc failed");
check::equal($bd->x, 16, "bd failed");
check::done();
?>

View file

@ -0,0 +1,150 @@
<?php
require "tests.php";
require "director_classic.php";
// No new functions
check::functions(array(being_id,person_id,child_id,grandchild_id,caller_delcallback,caller_setcallback,caller_resetcallback,caller_call,caller_baseclass));
// No new classes
check::classes(array(Being,Person,Child,GrandChild,OrphanPerson,OrphanChild,Caller));
// now new vars
check::globals(array());
class TargetLangPerson extends Person {
function id() {
$identifier = "TargetLangPerson";
return $identifier;
}
}
class TargetLangChild extends Child {
function id() {
$identifier = "TargetLangChild";
return $identifier;
}
}
class TargetLangGrandChild extends GrandChild {
function id() {
$identifier = "TargetLangGrandChild";
return $identifier;
}
}
# Semis - don't override id() in target language
class TargetLangSemiPerson extends Person {
# No id() override
}
class TargetLangSemiChild extends Child {
# No id() override
}
class TargetLangSemiGrandChild extends GrandChild {
# No id() override
}
# Orphans - don't override id() in C++
class TargetLangOrphanPerson extends OrphanPerson {
function id() {
$identifier = "TargetLangOrphanPerson";
return $identifier;
}
}
class TargetLangOrphanChild extends OrphanChild {
function id() {
$identifier = "TargetLangOrphanChild";
return $identifier;
}
}
function mycheck($person, $expected) {
$debug = 0;
# Normal target language polymorphic call
$ret = $person->id();
if ($debug)
print $ret . "\n";
check::equal($ret, $expected, "#1 failed");
# Polymorphic call from C++
$caller = new Caller();
$caller->setCallback($person);
$ret = $caller->call();
if ($debug)
print $ret . "\n";
check::equal($ret, $expected, "#2 failed");
# Polymorphic call of object created in target language and passed to
# C++ and back again
$baseclass = $caller->baseClass();
$ret = $baseclass->id();
if ($debug)
print $ret . "\n";
# TODO: Currently we do not track the dynamic type of returned
# objects, so in case it's possible that the dynamic type is not equal
# to the static type, we skip this check.
if (get_parent_class($person) === false)
check::equal($ret, $expected, "#3 failed");
$caller->resetCallback();
if ($debug)
print "----------------------------------------\n";
}
$person = new Person();
mycheck($person, "Person");
unset($person);
$person = new Child();
mycheck($person, "Child");
unset($person);
$person = new GrandChild();
mycheck($person, "GrandChild");
unset($person);
$person = new TargetLangPerson();
mycheck($person, "TargetLangPerson");
unset($person);
$person = new TargetLangChild();
mycheck($person, "TargetLangChild");
unset($person);
$person = new TargetLangGrandChild();
mycheck($person, "TargetLangGrandChild");
unset($person);
# Semis - don't override id() in target language
$person = new TargetLangSemiPerson();
mycheck($person, "Person");
unset($person);
$person = new TargetLangSemiChild();
mycheck($person, "Child");
unset($person);
$person = new TargetLangSemiGrandChild();
mycheck($person, "GrandChild");
unset($person);
# Orphans - don't override id() in C++
$person = new OrphanPerson();
mycheck($person, "Person");
unset($person);
$person = new OrphanChild();
mycheck($person, "Child");
unset($person);
$person = new TargetLangOrphanPerson();
mycheck($person, "TargetLangOrphanPerson");
unset($person);
$person = new TargetLangOrphanChild();
mycheck($person, "TargetLangOrphanChild");
unset($person);
check::done();
?>

View file

@ -0,0 +1,20 @@
<?php
require "tests.php";
require "director_default.php";
// No new functions
check::functions(array(foo_msg,foo_getmsg,bar_msg,bar_getmsg,defaultsbase_defaultargs,defaultsderived_defaultargs));
// No new classes
check::classes(array(Foo,Bar,DefaultsBase,DefaultsDerived));
// now new vars
check::globals(array());
$f = new Foo();
$f = new Foo(1);
$f = new Bar();
$f = new Bar(1);
check::done();
?>

View file

@ -0,0 +1,55 @@
<?php
require "tests.php";
require "director_detect.php";
// No new functions
check::functions(array(foo_cloner,foo_get_value,foo_get_class,foo_just_do_it,bar_baseclass,bar_cloner,bar_get_value,bar_get_class,bar_just_do_it));
// No new classes
check::classes(array(A,Foo,Bar));
// now new vars
check::globals(array());
class MyBar extends Bar {
function __construct($val = 2) {
parent::__construct();
$this->val = $val;
}
function get_value() {
$this->val = $this->val + 1;
return $this->val;
}
function get_class() {
$this->val = $this->val + 1;
return new A();
}
function just_do_it() {
$this->val = $this->val + 1;
}
/* clone is a reserved keyword */
function clone_() {
return new MyBar($this->val);
}
}
$b = new MyBar();
$f = $b->baseclass();
$v = $f->get_value();
$a = $f->get_class();
$f->just_do_it();
$c = $b->clone_();
$vc = $c->get_value();
check::equal($v, 3, "f: Bad virtual detection");
check::equal($b->val, 5, "b: Bad virtual detection");
check::equal($vc, 6, "c: Bad virtual detection");
check::done();
?>

View file

@ -0,0 +1,25 @@
<?php
require "tests.php";
require "director_enum.php";
// No new functions
check::functions(array(foo_say_hello,foo_say_hi,foo_say_bye,foo_say_hi_ref,foo_ping,foo_ping_ref,foo_ping_member_enum,a_f,a2_f));
// No new classes
check::classes(array(director_enum,Foo,A,B,A2,B2));
// now new vars
check::globals(array());
class MyFoo extends Foo {
function say_hi($val) {
return $val;
}
}
$b = new Foo();
$a = new MyFoo();
check::equal($a->say_hi(director_enum::hello), $b->say_hello(director_enum::hi), "say failed");
check::done();
?>

View file

@ -0,0 +1,78 @@
<?php
require "tests.php";
require "director_exception.php";
// No new functions
check::functions(array(foo_ping,foo_pong,launder,bar_ping,bar_pong,bar_pang));
// No new classes
check::classes(array(director_exception,Foo,Exception1,Exception2,Base,Bar));
// now new vars
check::globals(array());
class MyException extends Exception {
function __construct($a, $b) {
$this->msg = $a . $b;
}
}
class MyFoo extends Foo {
function ping() {
throw new Exception("MyFoo::ping() EXCEPTION");
}
}
class MyFoo2 extends Foo {
function ping() {
return true;
}
}
class MyFoo3 extends Foo {
function ping() {
throw new MyException("foo", "bar");
}
}
# Check that the Exception raised by MyFoo.ping() is returned by
# MyFoo.pong().
$ok = 0;
$a = new MyFoo();
# TODO: Currently we do not track the dynamic type of returned
# objects, so we skip the launder() call.
#$b = director_exception::launder($a);
$b = $a;
try {
$b->pong();
} catch (Exception $e) {
$ok = 1;
check::equal($e->getMessage(), "MyFoo::ping() EXCEPTION", "Unexpected error message #1");
}
check::equal($ok, 1, "Got no exception while expected one #1");
# Check that the director can return an exception which requires two
# arguments to the constructor, without mangling it.
$ok = 0;
$a = new MyFoo3();
#$b = director_exception::launder($a);
$b = $a;
try {
$b->pong();
} catch (Exception $e) {
$ok = 1;
check::equal($e->msg, "foobar", "Unexpected error message #2");
}
check::equal($ok, 1, "Got no exception while expected one #2");
try {
throw new Exception2();
} catch (Exception2 $e2) {
}
try {
throw new Exception1();
} catch (Exception1 $e1) {
}
check::done();
?>

View file

@ -0,0 +1,29 @@
<?php
require "tests.php";
require "director_extend.php";
// No new functions
check::functions(array(spobject_getfoobar,spobject_dummy,spobject_exceptionmethod));
// No new classes
check::classes(array(SpObject));
// now new vars
check::globals(array());
class MyObject extends SpObject{
function __construct() {
parent::__construct();
return;
}
function getFoo() {
return 123;
}
}
$m = new MyObject();
check::equal($m->dummy(), 666, "1st call");
check::equal($m->dummy(), 666, "2st call"); // Locked system
check::done();
?>

View file

@ -0,0 +1,61 @@
<?php
require "tests.php";
require "director_finalizer.php";
// No new functions
check::functions(array(foo_orstatus,deletefoo,getstatus,launder,resetstatus));
// No new classes
check::classes(array(director_finalizer,Foo));
// now new vars
check::globals(array());
class MyFoo extends Foo {
function __destruct() {
$this->orStatus(2);
if (method_exists(parent, "__destruct")) {
parent::__destruct();
}
}
}
resetStatus();
$a = new MyFoo();
unset($a);
check::equal(getStatus(), 3, "getStatus() failed #1");
resetStatus();
$a = new MyFoo();
launder($a);
check::equal(getStatus(), 0, "getStatus() failed #2");
unset($a);
check::equal(getStatus(), 3, "getStatus() failed #3");
resetStatus();
$a = new MyFoo();
$a->thisown = 0;
deleteFoo($a);
unset($a);
check::equal(getStatus(), 3, "getStatus() failed #4");
resetStatus();
$a = new MyFoo();
$a->thisown = 0;
deleteFoo(launder($a));
unset($a);
check::equal(getStatus(), 3, "getStatus() failed #5");
resetStatus();
check::done();
?>

View file

@ -0,0 +1,19 @@
<?php
require "tests.php";
require "director_frob.php";
// No new functions
check::functions(array(alpha_abs_method,bravo_abs_method,charlie_abs_method,ops_opint,ops_opintstarstarconst,ops_opintamp,ops_opintstar,ops_opconstintintstar,prims_ull,prims_callull,corecallbacks_on3dengineredrawn,corecallbacks_on3dengineredrawn2));
// No new classes
check::classes(array(Alpha,Bravo,Charlie,Delta,Ops,Prims,corePoint3d,coreCallbacks_On3dEngineRedrawnData,coreCallbacksOn3dEngineRedrawnData,coreCallbacks));
// now new vars
check::globals(array(corecallbacks_on3dengineredrawndata__eye,corecallbacks_on3dengineredrawndata__at,corecallbackson3dengineredrawndata__eye,corecallbackson3dengineredrawndata__at));
$foo = new Bravo();
$s = $foo->abs_method();
check::equal($s, "Bravo::abs_method()", "s failed");
check::done();
?>

View file

@ -0,0 +1,75 @@
<?php
// Sample test file
require "tests.php";
require "director_nested.php";
// No new functions
check::functions(array(foo_int_advance,foo_int_do_advance,bar_step,bar_do_advance,bar_do_step,foobar_int_get_value,foobar_int_get_name,foobar_int_name,foobar_int_get_self,foobar_int_do_advance,foobar_int_do_step));
// No new classes
check::classes(array(Foo_int,Bar,FooBar_int));
// now new vars
check::globals(array());
class A extends FooBar_int {
function do_step() {
return "A::do_step;";
}
function get_value() {
return "A::get_value";
}
}
$a = new A();
check::equal($a->step(), "Bar::step;Foo::advance;Bar::do_advance;A::do_step;", "Bad A virtual resolution");
class B extends FooBar_int {
function do_advance() {
return "B::do_advance;" . $this->do_step();
}
function do_step() {
return "B::do_step;";
}
function get_value() {
return 1;
}
}
$b = new B();
check::equal($b->step(), "Bar::step;Foo::advance;B::do_advance;B::do_step;", "Bad B virtual resolution");
class C extends FooBar_int {
function do_advance() {
return "C::do_advance;" . parent::do_advance();
}
function do_step() {
return "C::do_step;";
}
function get_value() {
return 2;
}
function get_name() {
return parent::get_name() . " hello";
}
}
$cc = new C();
# TODO: Currently we do not track the dynamic type of returned
# objects, so we skip the get_self() call.
#$c = Foobar_int::get_self($cc);
$c = $cc;
$c->advance();
check::equal($c->get_name(), "FooBar::get_name hello", "get_name failed");
check::equal($c->name(), "FooBar::get_name hello", "name failed");
check::done();
?>

View file

@ -0,0 +1,53 @@
<?php
require "tests.php";
require "director_profile.php";
// No new functions
check::functions(array(b_fn,b_vfi,b_fi,b_fj,b_fk,b_fl,b_get_self,b_vfs,b_fs));
// No new classes
check::classes(array(A,B));
// now new vars
check::globals(array());
class MyB extends B {
function vfi($a) {
return $a+3;
}
}
$a = new A();
$myb = new MyB();
$b = B::get_self($myb);
$i = 50000;
$a = 1;
while ($i) {
$a = $b->fi($a); #1
$a = $b->fi($a); #2
$a = $b->fi($a); #3
$a = $b->fi($a); #4
$a = $b->fi($a); #5
$a = $b->fi($a); #6
$a = $b->fi($a); #7
$a = $b->fi($a); #8
$a = $b->fi($a); #9
$a = $b->fi($a); #10
$a = $b->fi($a); #1
$a = $b->fi($a); #2
$a = $b->fi($a); #3
$a = $b->fi($a); #4
$a = $b->fi($a); #5
$a = $b->fi($a); #6
$a = $b->fi($a); #7
$a = $b->fi($a); #8
$a = $b->fi($a); #9
$a = $b->fi($a); #20
$i -= 1;
}
print $a . "\n";
check::done();
?>

View file

@ -0,0 +1,54 @@
<?php
require "tests.php";
require "director_protected.php";
// No new functions
check::functions(array(foo_pong,foo_s,foo_q,foo_ping,foo_pang,foo_used,bar_create,bar_pong,bar_used,bar_ping,bar_pang,a_draw,b_draw));
// No new classes
check::classes(array(Foo,Bar,PrivateFoo,A,B,AA,BB));
// now new vars
check::globals(array(bar_a));
class FooBar extends Bar {
protected function ping() {
return "FooBar::ping();";
}
}
class FooBar2 extends Bar {
function ping() {
return "FooBar2::ping();";
}
function pang() {
return "FooBar2::pang();";
}
}
$b = new Bar();
$f = $b->create();
$fb = new FooBar();
$fb2 = new FooBar2();
check::equal($fb->used(), "Foo::pang();Bar::pong();Foo::pong();FooBar::ping();", "bad FooBar::used");
check::equal($fb2->used(), "FooBar2::pang();Bar::pong();Foo::pong();FooBar2::ping();", "bad FooBar2::used");
check::equal($b->pong(), "Bar::pong();Foo::pong();Bar::ping();", "bad Bar::pong");
check::equal($f->pong(), "Bar::pong();Foo::pong();Bar::ping();", "bad Foo::pong");
check::equal($fb->pong(), "Bar::pong();Foo::pong();FooBar::ping();", "bad FooBar::pong");
$method = new ReflectionMethod('Bar', 'ping');
check::equal($method->isProtected(), true, "Boo::ping should be protected");
$method = new ReflectionMethod('Foo', 'ping');
check::equal($method->isProtected(), true, "Foo::ping should be protected");
$method = new ReflectionMethod('FooBar', 'pang');
check::equal($method->isProtected(), true, "FooBar::pang should be protected");
check::done();
?>

View file

@ -0,0 +1,60 @@
<?php
require "tests.php";
require "director_stl.php";
// No new functions
check::functions(array(foo_bar,foo_ping,foo_pong,foo_tping,foo_tpong,foo_pident,foo_vident,foo_vsecond,foo_tpident,foo_tvident,foo_tvsecond,foo_vidents,foo_tvidents));
// No new classes
check::classes(array(Foo));
// now new vars
check::globals(array());
class MyFoo extends Foo {
function ping($s) {
return "MyFoo::ping():" . $s;
}
function pident($arg) {
return $arg;
}
function vident($v) {
return $v;
}
function vidents($v) {
return $v;
}
function vsecond($v1, $v2) {
return $v2;
}
}
$a = new MyFoo();
$a->tping("hello");
$a->tpong("hello");
# TODO: automatic conversion between PHP arrays and std::pair or
# std::vector is not yet implemented.
/*$p = array(1, 2);
$a->pident($p);
$v = array(3, 4);
$a->vident($v);
$a->tpident($p);
$a->tvident($v);
$v1 = array(3, 4);
$v2 = array(5, 6);
$a->tvsecond($v1, $v2);
$vs = array("hi", "hello");
$vs;
$a->tvidents($vs);*/
check::done();
?>

View file

@ -0,0 +1,34 @@
<?php
require "tests.php";
require "director_string.php";
// No new functions
check::functions(array(a_get_first,a_call_get_first,a_string_length,a_process_text,a_call_process_func,stringvector_size,stringvector_is_empty,stringvector_clear,stringvector_push,stringvector_pop));
// No new classes
check::classes(array(A,StringVector));
// now new vars
check::globals(array(a,a_call,a_m_strings,stringvector));
class B extends A {
function get_first() {
return parent::get_first() . " world!";
}
function process_text($string) {
parent::process_text($string);
$this->smem = "hello";
}
}
$b = new B("hello");
$b->get(0);
check::equal($b->get_first(),"hello world!", "get_first failed");
$b->call_process_func();
check::equal($b->smem, "hello", "smem failed");
check::done();
?>

View file

@ -0,0 +1,29 @@
<?php
require "tests.php";
require "director_thread.php";
// No new functions
check::functions(array(millisecondsleep,foo_stop,foo_run,foo_do_foo));
// No new classes
check::classes(array(director_thread,Foo));
// now new vars
check::globals(array(foo_val));
class Derived extends Foo {
function do_foo() {
$this->val = $this->val - 1;
}
}
$d = new Derived();
$d->run();
if ($d->val >= 0) {
check::fail($d->val);
}
$d->stop();
check::done();
?>

View file

@ -0,0 +1,29 @@
<?php
require "tests.php";
require "director_unroll.php";
// No new functions
check::functions(array(foo_ping,foo_pong));
// No new classes
check::classes(array(Foo,Bar));
// now new vars
check::globals(array(bar));
class MyFoo extends Foo {
function ping() {
return "MyFoo::ping()";
}
}
$a = new MyFoo();
$b = new Bar();
$b->set($a);
$c = $b->get();
check::equal($a->this, $c->this, "this failed");
check::done();
?>

View file

@ -31,7 +31,8 @@ $spam=new spam();
check::is_a($spam,"spam");
check::equal(1,$spam->_foo,"1==spam->_foo");
check::equal(2,$spam->_bar,"2==spam->_bar");
check::equal(3,$spam->_baz,"3==spam->_baz");
// multiple inheritance not supported in PHP
check::equal(null,$spam->_baz,"null==spam->_baz");
check::equal(4,$spam->_spam,"4==spam->_spam");
check::done();

View file

@ -11,5 +11,11 @@ check::classes(array(doubleArray));
// now new vars
check::globals(array());
$d = new doubleArray(10);
$d->setitem(0, 7);
$d->setitem(5, $d->getitem(0) + 3);
check::equal($d->getitem(0) + $d->getitem(5), 17., "7+10==17");
check::done();
?>

View file

@ -0,0 +1,22 @@
<?php
require "tests.php";
require "li_factory.php";
// No new functions
check::functions(array(geometry_draw,geometry_create,geometry_clone_,point_draw,point_width,point_clone_,circle_draw,circle_radius,circle_clone_));
// No new classes
check::classes(array(Geometry,Point,Circle));
// now new vars
check::globals(array());
$circle = Geometry::create(Geometry::CIRCLE);
$r = $circle->radius();
check::equal($r, 1.5, "r failed");
$point = Geometry::create(Geometry::POINT);
$w = $point->width();
check::equal($w, 1.0, "w failed");
check::done();
?>

View file

@ -0,0 +1,20 @@
<?php
// Sample test file
require "tests.php";
require "newobject1.php";
// No new functions
check::functions(array(foo_makefoo,foo_makemore,foo_foocount));
// No new classes
check::classes(array(Foo));
// now new vars
check::globals(array());
$foo = Foo::makeFoo();
check::equal(get_class($foo), "Foo", "static failed");
$bar = $foo->makeMore();
check::equal(get_class($bar), "Foo", "regular failed");
check::done();
?>

View file

@ -0,0 +1,19 @@
<?php
// Sample test file
require "tests.php";
require "prefix.php";
// No new functions
check::functions(array(foo_get_self));
// No new classes
check::classes(array(ProjectFoo));
// now new vars
check::globals(array());
$f = new ProjectFoo();
// This resulted in "Fatal error: Class 'Foo' not found"
$f->get_self();
check::done();
?>

View file

@ -34,8 +34,11 @@ class check {
$df=array_flip($df[internal]);
foreach($_original_functions[internal] as $func) unset($df[$func]);
// Now chop out any get/set accessors
foreach(array_keys($df) as $func) if (GETSET && ereg('_[gs]et$',$func)) $extrags[]=$func;
else $extra[]=$func;
foreach(array_keys($df) as $func)
if ((GETSET && ereg('_[gs]et$',$func)) || ereg('^new_', $func)
|| ereg('_(alter|get)_newobject$', $func))
$extrags[]=$func;
else $extra[]=$func;
// $extra=array_keys($df);
}
if ($gs) return $extrags;

View file

@ -0,0 +1,14 @@
// Test that was failing for PHP - the value of the -prefix option was
// ignored
%module prefix
%inline %{
class Foo {
public:
Foo *get_self() {
return this;
}
};
%}

View file

@ -0,0 +1,14 @@
import special_variable_macros
name = special_variable_macros.Name()
if special_variable_macros.testFred(name) != "none":
raise "test failed"
if special_variable_macros.testJack(name) != "$specialname":
raise "test failed"
if special_variable_macros.testJill(name) != "jilly":
raise "test failed"
if special_variable_macros.testMary(name) != "SWIGTYPE_p_NameWrap":
raise "test failed"
if special_variable_macros.testJim(name) != "multiname num":
raise "test failed"

View file

@ -0,0 +1,145 @@
%module special_variable_macros
// test $typemap() special variable function
// these tests are not typical of how $typemap() should be used, but it checks that it is mostly working
%inline %{
struct Name {
Name(const char *n="none") : name(n) {}
const char *getName() const { return name; };
Name *getNamePtr() { return this; };
private:
const char *name;
};
struct NameWrap {
NameWrap(const char *n="casternone") : name(n) {}
Name *getNamePtr() { return &name; };
private:
Name name;
};
%}
// check $1 and $input get expanded properly when used from $typemap()
%typemap(in) Name *GENERIC ($*1_type temp)
%{
/*%typemap(in) Name *GENERIC start */
temp = Name("$specialname");
(void)$input;
$1 = ($1_ltype) &temp;
/*%typemap(in) Name *GENERIC end */
%}
// This would never be done in real code, it is just a test of what madness can be done.
// Note that the special variable substitutions $*1_type, $descriptor etc are for NameWrap
// even when used within the Name typemap via $typemap. I can't think of any useful use cases
// for this behaviour in the C/C++ typemaps, but it is possible.
%typemap(in) NameWrap *NAMEWRAP ($*1_type temp)
%{
/*%typemap(in) NameWrap *NAMEWRAP start */
temp = $*1_ltype("$descriptor");
(void)$input;
$1 = temp.getNamePtr();
/*%typemap(in) NameWrap *NAMEWRAP end */
%}
//////////////////////////////////////////////////////////////////////////////////////
// This should use Name *GENERIC typemap which ignores passed in Name * and instead uses a newly a newly constructed Name
// held in a typemap variable with name="$specialname"
%typemap(in) Name *jack {
// %typemap(in) Name *jack start
$typemap(in, Name *GENERIC)
// %typemap(in) Name *jack end
}
// as above, but also perform variable substitution
%typemap(in) Name *jill {
// %typemap(in) Name *jill start
$typemap(in, Name *GENERIC, specialname=jilly)
// %typemap(in) Name *jill end
}
%typemap(in) Name *mary {
// %typemap(in) Name *mary start
$typemap(in, NameWrap *NAMEWRAP)
// %typemap(in) Name *mary end
}
%inline %{
const char * testFred(Name *fred) {
return fred->getName();
}
const char * testJack(Name *jack) {
return jack->getName();
}
const char * testJill(Name *jill) {
return jill->getName();
}
const char * testMary(Name *mary) {
return mary->getName();
}
%}
//////////////////////////////////////////////////////////////////////////////////////
// Multi-arg typemap lookup
// One would never do something like this in reality, it just checks $typemap with multi-arg typemaps
%typemap(in) (Name *multiname, int num)($*1_type temp_name, $2_ltype temp_count)
%{
/*%typemap(in) (Name *multiname, int num) start */
temp_name = $*1_ltype("multiname num");
temp_count = strlen(temp_name.getNamePtr()->getName());
(void)$input;
$1 = temp_name.getNamePtr();
$2 = temp_count + 100;
/*%typemap(in) (Name *multiname, int num) end */
%}
%typemap(in) (Name *jim, int count) {
// %typemap(in) Name *jim start
$typemap(in, (Name *multiname, int num))
// %typemap(in) Name *jim end
}
%inline %{
const char * testJim(Name *jim, int count) {
if (count != strlen(jim->getNamePtr()->getName()) + 100)
return "size check failed";
else
return jim->getName();
}
%}
//////////////////////////////////////////////////////////////////////////////////////
// A real use case for $typemap
#if defined(SWIGCSHARP)
%typemap(cscode) Space::RenameMe %{
public static NewName factory(String s) {
//below should expand to:
//return new NewName( new Name(s) );
return new $typemap(cstype, Space::RenameMe)( new $typemap(cstype, Name)(s) );
}
%}
#elif defined(SWIGJAVA)
%typemap(javacode) Space::RenameMe %{
public static NewName factory(String s) {
//below should expand to:
//return new NewName( new Name(s) );
return new $typemap(jstype, Space::RenameMe)( new $typemap(jstype, Name)(s) );
}
%}
#endif
%rename(NewName) Space::RenameMe;
%inline %{
namespace Space {
struct RenameMe {
RenameMe(Name n) : storedName(n) {}
Name getStoredName() { return storedName; }
private:
Name storedName;
};
}
%}

View file

@ -1,8 +1,7 @@
%module template_default
%warnfilter(SWIGWARN_RUBY_WRONG_NAME) ns1::Traits::c; /* Ruby, wrong constant name */
namespace ns1 {
namespace ns2 {
@ -154,8 +153,8 @@ namespace ns1 {
%}
%template(Do) ns1::ns4::D<ns1::Traits>;
%template(Bo) ns1::ns4::Base<ns1::Traits, ns1::ns4::D<ns1::Traits> >;
%template(Doo) ns1::ns4::D<ns1::Traits>;
%template(Boo) ns1::ns4::Base<ns1::Traits, ns1::ns4::D<ns1::Traits> >;

View file

@ -8,7 +8,7 @@
enum Polarization { UnaryPolarization, BinaryPolarization };
template <Polarization P>
struct Interface
struct Interface_tpl
{
};
@ -19,7 +19,7 @@
template <class C,
Polarization P = C::pmode,
class Base = Interface<P> > // **** problem here *****
class Base = Interface_tpl<P> > // **** problem here *****
struct Module : Base
{
};
@ -29,12 +29,12 @@
namespace oss
{
%template(Interface_UP) Interface<UnaryPolarization>;
%template(Interface_UP) Interface_tpl<UnaryPolarization>;
// This works
%template(Module_UP1) Module<traits,
UnaryPolarization,
Interface<UnaryPolarization> >;
Interface_tpl<UnaryPolarization> >;
// These don't
%template(Module_UP2) Module<traits, UnaryPolarization>;

198
Lib/php/director.swg Normal file
View file

@ -0,0 +1,198 @@
/* -----------------------------------------------------------------------------
* See the LICENSE file for information on copyright, usage and redistribution
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* director.swg
*
* This file contains support for director classes that proxy
* method calls from C++ to PHP extensions.
* ----------------------------------------------------------------------------- */
#ifndef SWIG_DIRECTOR_PHP_HEADER_
#define SWIG_DIRECTOR_PHP_HEADER_
#ifdef __cplusplus
#include <string>
#include <map>
/*
Use -DSWIG_DIRECTOR_STATIC if you prefer to avoid the use of the
'Swig' namespace. This could be useful for multi-modules projects.
*/
#ifdef SWIG_DIRECTOR_STATIC
/* Force anonymous (static) namespace */
#define Swig
#endif
namespace Swig {
/* memory handler */
struct GCItem
{
virtual ~GCItem() {}
virtual int get_own() const
{
return 0;
}
};
struct GCItem_var
{
GCItem_var(GCItem *item = 0) : _item(item)
{
}
GCItem_var& operator=(GCItem *item)
{
GCItem *tmp = _item;
_item = item;
delete tmp;
return *this;
}
~GCItem_var()
{
delete _item;
}
GCItem * operator->() const
{
return _item;
}
private:
GCItem *_item;
};
struct GCItem_Object : GCItem
{
GCItem_Object(int own) : _own(own)
{
}
virtual ~GCItem_Object()
{
}
int get_own() const
{
return _own;
}
private:
int _own;
};
template <typename Type>
struct GCItem_T : GCItem
{
GCItem_T(Type *ptr) : _ptr(ptr)
{
}
virtual ~GCItem_T()
{
delete _ptr;
}
private:
Type *_ptr;
};
class Director {
protected:
zval *swig_self;
typedef std::map<void*, GCItem_var> ownership_map;
mutable ownership_map owner;
public:
Director(zval* self) : swig_self(self) {
}
~Director() {
for (ownership_map::iterator i = owner.begin(); i != owner.end(); i++) {
owner.erase(i);
}
}
bool is_overriden_method(char *cname, char *lc_fname) {
zval classname;
zend_class_entry **ce;
zend_function *mptr;
int name_len = strlen(lc_fname);
ZVAL_STRING(&classname, cname, 0);
if (zend_lookup_class(Z_STRVAL_P(&classname), Z_STRLEN_P(&classname), &ce TSRMLS_CC) != SUCCESS) {
return false;
}
if (zend_hash_find(&(*ce)->function_table, lc_fname, name_len + 1, (void**) &mptr) != SUCCESS) {
return false;
}
// common.scope points to the declaring class
return strcmp(mptr->common.scope->name, cname);
}
template <typename Type>
void swig_acquire_ownership(Type *vptr) const
{
if (vptr) {
owner[vptr] = new GCItem_T<Type>(vptr);
}
}
};
/* base class for director exceptions */
class DirectorException {
protected:
std::string swig_msg;
public:
DirectorException(int code, const char *hdr, const char* msg)
: swig_msg(hdr)
{
if (strlen(msg)) {
swig_msg += " ";
swig_msg += msg;
}
SWIG_ErrorCode() = code;
SWIG_ErrorMsg() = swig_msg.c_str();
}
static void raise(int code, const char *hdr, const char* msg)
{
throw DirectorException(code, hdr, msg);
}
};
/* attempt to call a pure virtual method via a director method */
class DirectorPureVirtualException : public Swig::DirectorException
{
public:
DirectorPureVirtualException(const char* msg)
: DirectorException(E_ERROR, "Swig director pure virtual method called", msg)
{
}
static void raise(const char *msg)
{
throw DirectorPureVirtualException(msg);
}
};
/* any php exception that occurs during a director method call */
class DirectorMethodException : public Swig::DirectorException
{
public:
DirectorMethodException(const char* msg = "")
: DirectorException(E_ERROR, "Swig director method error", msg)
{
}
static void raise(const char *msg)
{
throw DirectorMethodException(msg);
}
};
}
#endif /* __cplusplus */
#endif

109
Lib/php/factory.i Normal file
View file

@ -0,0 +1,109 @@
/*
Implement a more natural wrap for factory methods, for example, if
you have:
---- geometry.h --------
struct Geometry {
enum GeomType{
POINT,
CIRCLE
};
virtual ~Geometry() {}
virtual int draw() = 0;
//
// Factory method for all the Geometry objects
//
static Geometry *create(GeomType i);
};
struct Point : Geometry {
int draw() { return 1; }
double width() { return 1.0; }
};
struct Circle : Geometry {
int draw() { return 2; }
double radius() { return 1.5; }
};
//
// Factory method for all the Geometry objects
//
Geometry *Geometry::create(GeomType type) {
switch (type) {
case POINT: return new Point();
case CIRCLE: return new Circle();
default: return 0;
}
}
---- geometry.h --------
You can use the %factory with the Geometry::create method as follows:
%newobject Geometry::create;
%factory(Geometry *Geometry::create, Point, Circle);
%include "geometry.h"
and Geometry::create will return a 'Point' or 'Circle' instance
instead of the plain 'Geometry' type. For example, in python:
circle = Geometry.create(Geometry.CIRCLE)
r = circle.radius()
where circle is a Circle proxy instance.
NOTES: remember to fully qualify all the type names and don't
use %factory inside a namespace declaration, ie, instead of
namespace Foo {
%factory(Geometry *Geometry::create, Point, Circle);
}
use
%factory(Foo::Geometry *Foo::Geometry::create, Foo::Point, Foo::Circle);
*/
/* for loop for macro with one argument */
%define %_formacro_1(macro, arg1,...)macro(arg1)
#if #__VA_ARGS__ != "__fordone__"
%_formacro_1(macro, __VA_ARGS__)
#endif
%enddef
/* for loop for macro with one argument */
%define %formacro_1(macro,...)%_formacro_1(macro,__VA_ARGS__,__fordone__)%enddef
%define %formacro(macro,...)%_formacro_1(macro,__VA_ARGS__,__fordone__)%enddef
/* for loop for macro with two arguments */
%define %_formacro_2(macro, arg1, arg2, ...)macro(arg1, arg2)
#if #__VA_ARGS__ != "__fordone__"
%_formacro_2(macro, __VA_ARGS__)
#endif
%enddef
/* for loop for macro with two arguments */
%define %formacro_2(macro,...)%_formacro_2(macro, __VA_ARGS__, __fordone__)%enddef
%define %_factory_dispatch(Type)
if (!dcast) {
Type *dobj = dynamic_cast<Type *>($1);
if (dobj) {
dcast = 1;
SWIG_SetPointerZval(return_value, SWIG_as_voidptr(dobj),$descriptor(Type *), $owner);
}
}%enddef
%define %factory(Method,Types...)
%typemap(out) Method {
int dcast = 0;
%formacro(%_factory_dispatch, Types)
if (!dcast) {
SWIG_SetPointerZval(return_value, SWIG_as_voidptr($1),$descriptor, $owner);
}
}%enddef

View file

@ -89,6 +89,14 @@
$1 = *tmp;
}
%typemap(directorout) SWIGTYPE ($&1_ltype tmp)
{
if(SWIG_ConvertPtr(*$input, (void **) &tmp, $&1_descriptor, 0) < 0 || tmp == NULL) {
SWIG_PHP_Error(E_ERROR, "Type error in argument $argnum of $symname. Expected $&1_descriptor");
}
$result = *tmp;
}
%typemap(in) SWIGTYPE *,
SWIGTYPE []
{
@ -176,17 +184,42 @@
ZVAL_LONG(return_value,$1);
}
%typemap(directorin) int,
unsigned int,
short,
unsigned short,
long,
unsigned long,
signed char,
unsigned char,
size_t,
enum SWIGTYPE
{
ZVAL_LONG($input,$1_name);
}
%typemap(out) bool
{
ZVAL_BOOL(return_value,($1)?1:0);
}
%typemap(directorin) bool
{
ZVAL_BOOL($input,($1_name)?1:0);
}
%typemap(out) float,
double
{
ZVAL_DOUBLE(return_value,$1);
}
%typemap(directorin) float,
double
{
ZVAL_DOUBLE($input,$1_name);
}
%typemap(out) char
{
ZVAL_STRINGL(return_value,&$1, 1, 1);
@ -209,6 +242,13 @@
SWIG_SetPointerZval(return_value, (void *)$1, $1_descriptor, $owner);
%}
%typemap(directorin) SWIGTYPE *,
SWIGTYPE [],
SWIGTYPE &
%{
SWIG_SetPointerZval($input, (void *)&$1_name, $1_descriptor, $owner);
%}
%typemap(out) SWIGTYPE *DYNAMIC,
SWIGTYPE &DYNAMIC
{
@ -230,6 +270,19 @@
}
#endif
%typemap(directorin) SWIGTYPE
#ifdef __cplusplus
{
SWIG_SetPointerZval($input, SWIG_as_voidptr(&$1_name), $&1_descriptor, 2);
}
#else
{
$&1_ltype resultobj = ($&1_ltype) emalloc(sizeof($1_type));
memcpy(resultobj, &$1, sizeof($1_type));
SWIG_SetPointerZval($input, (void *)resultobj, $&1_descriptor, 2);
}
#endif
%typemap(out) void "";
%typemap(out) char [ANY]

View file

@ -3,19 +3,13 @@
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
*
* phpkw.swg
*
* The 'keywords' in PHP are global, ie, the following names are fine
* when used as class methods.
* ----------------------------------------------------------------------------- */
#define PHPKW(x) %keywordwarn("'" `x` "' is a PHP keyword, renamed as 'c_" `x` "'",sourcefmt="%(lower)s", rename="c_%s",fullname=1) `x`
#define PHPKW(x) %keywordwarn("'" `x` "' is a PHP keyword, renamed as 'c_" `x` "'",sourcefmt="%(lower)s",$isclass,rename="c_%s") `x`
%define PHPCN(x)
%keywordwarn("'" `x` "' is a PHP reserved class name, class renamed as 'c_" `x` "'",%$isclass,rename="c_%s") `x`;
%keywordwarn("'" `x` "' is a PHP reserved class name, constructor renamed as 'c_" `x` "'",%$isconstructor,rename="c_%s") `x`;
%enddef
#define PHPCN(x) %keywordwarn("'" `x` "' is a PHP reserved class name, class renamed as 'c_" `x` "'",%$isclass,rename="c_%s") `x`
#define PHPBN1(x) %builtinwarn("'" `x` "' conflicts with a built-in name in PHP",sourcefmt="%(lower)s",fullname=1) `x`
#define PHPBN1(x) %builtinwarn("'" `x` "' conflicts with a built-in name in PHP",sourcefmt="%(lower)s") `x`
#define PHPBN2(x) %builtinwarn("'" `x` "' conflicts with a built-in name in PHP") "::" `x`

View file

@ -13,6 +13,7 @@ extern "C" {
#include "zend.h"
#include "zend_API.h"
#include "php.h"
#include "ext/standard/php_string.h"
#ifdef ZEND_RAW_FENTRY
/* ZEND_RAW_FENTRY was added somewhere between 5.2.0 and 5.2.3 */
@ -84,6 +85,7 @@ typedef struct {
static ZEND_RSRC_DTOR_FUNC(SWIG_landfill) { (void)rsrc; }
#define SWIG_SetPointerZval(a,b,c,d) SWIG_ZTS_SetPointerZval(a,b,c,d TSRMLS_CC)
#define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a))
static void
SWIG_ZTS_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject TSRMLS_DC) {
@ -101,7 +103,31 @@ SWIG_ZTS_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject
value=(swig_object_wrapper *)emalloc(sizeof(swig_object_wrapper));
value->ptr=ptr;
value->newobject=newobject;
ZEND_REGISTER_RESOURCE(z, value, *(int *)(type->clientdata));
if (newobject <= 1) {
ZEND_REGISTER_RESOURCE(z, value, *(int *)(type->clientdata));
} else {
value->newobject = 0;
zval *resource;
MAKE_STD_ZVAL(resource);
ZEND_REGISTER_RESOURCE(resource, value, *(int *)(type->clientdata));
zend_class_entry **ce = NULL;
zval *classname;
MAKE_STD_ZVAL(classname);
/* _p_Foo -> Foo */
ZVAL_STRING(classname, (char*)type->name+3, 1);
/* class names are stored in lowercase */
php_strtolower(Z_STRVAL_PP(&classname), Z_STRLEN_PP(&classname));
if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &ce TSRMLS_CC) != SUCCESS) {
/* class does not exists */
object_init(z);
} else {
object_init_ex(z, *ce);
}
z->refcount = 1;
z->is_ref = 1;
zend_hash_update(HASH_OF(z), (char*)"_cPtr", sizeof("_cPtr"), (void*)&resource, sizeof(zval), NULL);
FREE_ZVAL(classname);
}
return;
}
zend_error(E_ERROR, "Type: %s not registered with zend",type->name);
@ -156,7 +182,7 @@ SWIG_ZTS_ConvertResourcePtr(zval *z, swig_type_info *ty, int flags TSRMLS_DC) {
char *type_name;
value = (swig_object_wrapper *) zend_list_find(z->value.lval, &type);
if ( flags && SWIG_POINTER_DISOWN ) {
if ( flags & SWIG_POINTER_DISOWN ) {
value->newobject = 0;
}
p = value->ptr;

View file

@ -35,6 +35,11 @@ namespace std {
$1.assign(Z_STRVAL_PP($input), Z_STRLEN_PP($input));
%}
%typemap(directorout) string %{
convert_to_string_ex($input);
$result.assign(Z_STRVAL_PP($input), Z_STRLEN_PP($input));
%}
%typemap(typecheck,precedence=SWIG_TYPECHECK_STRING) const string& %{
$1 = ( Z_TYPE_PP($input) == IS_STRING ) ? 1 : 0;
%}
@ -43,6 +48,10 @@ namespace std {
ZVAL_STRINGL($result, const_cast<char*>($1.data()), $1.size(), 1);
%}
%typemap(directorin) string %{
ZVAL_STRINGL($input, const_cast<char*>($1_name.data()), $1_name.size(), 1);
%}
%typemap(out) const string & %{
ZVAL_STRINGL($result, const_cast<char*>($1->data()), $1->size(), 1);
%}
@ -63,6 +72,14 @@ namespace std {
$1 = &temp;
%}
%typemap(directorout) string & (std::string *temp) %{
convert_to_string_ex($input);
temp = new std::string;
temp->assign(Z_STRVAL_PP($input), Z_STRLEN_PP($input));
swig_acquire_ownership(temp);
$result = temp;
%}
%typemap(argout) string & %{
ZVAL_STRINGL(*($input), const_cast<char*>($1->data()), $1->size(), 1);
%}

View file

@ -37,6 +37,10 @@
%{
CONVERT_IN($1,$1_ltype,$input);
%}
%typemap(directorout) TYPE, const TYPE &
%{
CONVERT_IN($result,$1_ltype,$input);
%}
%enddef
%fragment("t_output_helper","header") %{
@ -49,6 +53,7 @@ t_output_helper( zval **target, zval *o) {
}
if ( (*target)->type == IS_NULL ) {
REPLACE_ZVAL_VALUE(target,o,1);
FREE_ZVAL(o);
return;
}
zval *tmp;

View file

@ -20,6 +20,7 @@
typedef std::map<K,T> map_type;
static int asptr(PyObject *obj, map_type **val) {
int res = SWIG_ERROR;
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
if (PyDict_Check(obj)) {
SwigVar_PyObject items = PyObject_CallMethod(obj,(char *)"items",NULL);
%#if PY_VERSION_HEX >= 0x03000000
@ -32,6 +33,7 @@
res = SWIG_ConvertPtr(obj,(void**)&p,swig::type_info<map_type>(),0);
if (SWIG_IsOK(res) && val) *val = p;
}
SWIG_PYTHON_THREAD_END_BLOCK;
return res;
}
};
@ -47,10 +49,10 @@
if (desc && desc->clientdata) {
return SWIG_NewPointerObj(new map_type(map), desc, SWIG_POINTER_OWN);
} else {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
size_type size = map.size();
int pysize = (size <= (size_type) INT_MAX) ? (int) size : -1;
if (pysize < 0) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(PyExc_OverflowError,
"map size not valid in python");
SWIG_PYTHON_THREAD_END_BLOCK;
@ -62,6 +64,7 @@
swig::SwigVar_PyObject val = swig::from(i->second);
PyDict_SetItem(obj, key, val);
}
SWIG_PYTHON_THREAD_END_BLOCK;
return obj;
}
}
@ -165,8 +168,8 @@
PyObject* keys() {
Map::size_type size = self->size();
int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1;
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
if (pysize < 0) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(PyExc_OverflowError,
"map size not valid in python");
SWIG_PYTHON_THREAD_END_BLOCK;
@ -177,14 +180,15 @@
for (int j = 0; j < pysize; ++i, ++j) {
PyList_SET_ITEM(keyList, j, swig::from(i->first));
}
SWIG_PYTHON_THREAD_END_BLOCK;
return keyList;
}
PyObject* values() {
Map::size_type size = self->size();
int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1;
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
if (pysize < 0) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(PyExc_OverflowError,
"map size not valid in python");
SWIG_PYTHON_THREAD_END_BLOCK;
@ -195,14 +199,15 @@
for (int j = 0; j < pysize; ++i, ++j) {
PyList_SET_ITEM(valList, j, swig::from(i->second));
}
SWIG_PYTHON_THREAD_END_BLOCK;
return valList;
}
PyObject* items() {
Map::size_type size = self->size();
int pysize = (size <= (Map::size_type) INT_MAX) ? (int) size : -1;
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
if (pysize < 0) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyErr_SetString(PyExc_OverflowError,
"map size not valid in python");
SWIG_PYTHON_THREAD_END_BLOCK;
@ -213,6 +218,7 @@
for (int j = 0; j < pysize; ++i, ++j) {
PyList_SET_ITEM(itemList, j, swig::from(*i));
}
SWIG_PYTHON_THREAD_END_BLOCK;
return itemList;
}

4
README
View file

@ -59,7 +59,11 @@ Major contributors include:
Martin Froehlich <MartinFroehlich@ACM.org> (Guile)
Marcio Luis Teixeira <marciot@holly.colostate.edu> (Guile)
Duncan Temple Lang (R)
<<<<<<< .working
Baozeng Ding <sploving1@163.com> (Scilab)
=======
Miklos Vajna <vmiklos@frugalware.org> (PHP directors)
>>>>>>> .merge-right.r11488
Past contributors include:
James Michael DuPont, Clark McGrew, Dustin Mitchell, Ian Cooke, Catalin Dumitrescu, Baran

View file

@ -1465,7 +1465,7 @@ static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) {
} decl;
Parm *tparms;
struct {
String *op;
String *method;
Hash *kwargs;
} tmap;
struct {
@ -2499,10 +2499,10 @@ varargs_parms : parms { $$ = $1; }
typemap_directive : TYPEMAP LPAREN typemap_type RPAREN tm_list stringbrace {
$$ = 0;
if ($3.op) {
if ($3.method) {
String *code = 0;
$$ = new_node("typemap");
Setattr($$,"method",$3.op);
Setattr($$,"method",$3.method);
if ($3.kwargs) {
ParmList *kw = $3.kwargs;
code = remove_block(kw, $6);
@ -2516,17 +2516,17 @@ typemap_directive : TYPEMAP LPAREN typemap_type RPAREN tm_list stringbrace {
}
| TYPEMAP LPAREN typemap_type RPAREN tm_list SEMI {
$$ = 0;
if ($3.op) {
if ($3.method) {
$$ = new_node("typemap");
Setattr($$,"method",$3.op);
Setattr($$,"method",$3.method);
appendChild($$,$5);
}
}
| TYPEMAP LPAREN typemap_type RPAREN tm_list EQUAL typemap_parm SEMI {
$$ = 0;
if ($3.op) {
if ($3.method) {
$$ = new_node("typemapcopy");
Setattr($$,"method",$3.op);
Setattr($$,"method",$3.method);
Setattr($$,"pattern", Getattr($7,"pattern"));
appendChild($$,$5);
}
@ -2546,15 +2546,15 @@ typemap_type : kwargs {
/* two argument typemap form */
name = Getattr($1,"name");
if (!name || (Strcmp(name,typemap_lang))) {
$$.op = 0;
$$.method = 0;
$$.kwargs = 0;
} else {
$$.op = Getattr(p,"name");
$$.method = Getattr(p,"name");
$$.kwargs = nextSibling(p);
}
} else {
/* one-argument typemap-form */
$$.op = Getattr($1,"name");
$$.method = Getattr($1,"name");
$$.kwargs = p;
}
}

View file

@ -250,6 +250,7 @@
#define WARN_PHP_MULTIPLE_INHERITANCE 870
#define WARN_PHP_UNKNOWN_PRAGMA 871
#define WARN_PHP_PUBLIC_BASE 872
/* please leave 870-889 free for PHP */

View file

@ -8,7 +8,7 @@ BUILD_SOURCE_DIR=$(top_builddir)/Source
SWIG_CXX_DEFS = @SWILL@
AM_CFLAGS = -I$(BUILD_SOURCE_DIR)/Include \
AM_CPPFLAGS = -I$(BUILD_SOURCE_DIR)/Include \
-I$(BUILD_SOURCE_DIR)/CParse \
-I$(SOURCE_DIR)/Include \
-I$(SOURCE_DIR)/DOH \
@ -17,8 +17,7 @@ AM_CFLAGS = -I$(BUILD_SOURCE_DIR)/Include \
-I$(SOURCE_DIR)/Swig \
-I$(SOURCE_DIR)/Modules
AM_CXXFLAGS = $(AM_CFLAGS) \
$(SWIG_CXX_DEFS)
AM_CXXFLAGS = $(SWIG_CXX_DEFS)
AM_YFLAGS = -d

View file

@ -1803,13 +1803,13 @@ static List *Swig_overload_rank(Node *n, bool script_lang_wrapping) {
String *t2 = Getattr(p2, "tmap:typecheck:precedence");
if ((!t1) && (!nodes[i].error)) {
Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n),
"Overloaded %s(%s) not supported (no type checking rule for '%s').\n",
Getattr(nodes[i].n, "name"), ParmList_str_defaultargs(Getattr(nodes[i].n, "parms")), SwigType_str(Getattr(p1, "type"), 0));
"Overloaded method %s not supported (no type checking rule for '%s').\n",
Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0));
nodes[i].error = 1;
} else if ((!t2) && (!nodes[j].error)) {
Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n),
"Overloaded %s(%s) not supported (no type checking rule for '%s').\n",
Getattr(nodes[j].n, "name"), ParmList_str_defaultargs(Getattr(nodes[j].n, "parms")), SwigType_str(Getattr(p2, "type"), 0));
"Overloaded method %s not supported (no type checking rule for '%s').\n",
Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0));
nodes[j].error = 1;
}
if (t1 && t2) {
@ -1937,19 +1937,15 @@ static List *Swig_overload_rank(Node *n, bool script_lang_wrapping) {
if (!nodes[j].error) {
if (script_lang_wrapping) {
Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n),
"Overloaded %s(%s)%s is shadowed by %s(%s)%s at %s:%d.\n",
Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms),
SwigType_isconst(Getattr(nodes[j].n, "decl")) ? " const" : "",
Getattr(nodes[i].n, "name"), ParmList_errorstr(nodes[i].parms),
SwigType_isconst(Getattr(nodes[i].n, "decl")) ? " const" : "", Getfile(nodes[i].n), Getline(nodes[i].n));
"Overloaded method %s is shadowed by %s at %s:%d.\n",
Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n),
Getfile(nodes[i].n), Getline(nodes[i].n));
} else {
if (!Getattr(nodes[j].n, "overload:ignore"))
Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n),
"Overloaded method %s(%s)%s ignored. Method %s(%s)%s at %s:%d used.\n",
Getattr(nodes[j].n, "name"), ParmList_errorstr(nodes[j].parms),
SwigType_isconst(Getattr(nodes[j].n, "decl")) ? " const" : "",
Getattr(nodes[i].n, "name"), ParmList_errorstr(nodes[i].parms),
SwigType_isconst(Getattr(nodes[i].n, "decl")) ? " const" : "", Getfile(nodes[i].n), Getline(nodes[i].n));
"Overloaded method %s ignored. Method %s at %s:%d used.\n",
Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n),
Getfile(nodes[i].n), Getline(nodes[i].n));
}
nodes[j].error = 1;
}
@ -2010,7 +2006,7 @@ Node *parent_node_skipping_extends(Node *n) {
* emit_num_lin_arguments()
*
* Calculate the total number of arguments. This function is safe for use
* with multi-valued typemaps which may change the number of arguments in
* with multi-argument typemaps which may change the number of arguments in
* strange ways.
* ----------------------------------------------------------------------------- */

View file

@ -2766,6 +2766,16 @@ public:
Delete(func_name);
}
/*----------------------------------------------------------------------
* replaceSpecialVariables()
*--------------------------------------------------------------------*/
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
SwigType *type = Getattr(parm, "type");
substituteClassname(type, tm);
}
/*----------------------------------------------------------------------
* decodeEnumFeature()
* Decode the possible enum features, which are one of:
@ -2859,15 +2869,15 @@ public:
/* -----------------------------------------------------------------------------
* substituteClassname()
*
* Substitute $csclassname with the proxy class name for classes/structs/unions that SWIG knows about.
* Also substitutes enums with enum name.
* Substitute the special variable $csclassname with the proxy class name for classes/structs/unions
* that SWIG knows about. Also substitutes enums with enum name.
* Otherwise use the $descriptor name for the C# class name. Note that the $&csclassname substitution
* is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
* Inputs:
* pt - parameter type
* tm - cstype typemap
* tm - typemap contents that might contain the special variable to be replaced
* Outputs:
* tm - cstype typemap with $csclassname substitution
* tm - typemap contents complete with the special variable substitution
* Return:
* substitution_performed - flag indicating if a substitution was performed
* ----------------------------------------------------------------------------- */
@ -3029,7 +3039,7 @@ public:
/* -----------------------------------------------------------------------------
* typemapLookup()
* n - for input only and must contain info for Getfile(n) and Getline(n) to work
* op - typemap method name
* tmap_method - typemap method name
* type - typemap type to lookup
* warning - warning number to issue if no typemaps found
* typemap_attributes - the typemap attributes are attached to this node and will
@ -3037,16 +3047,16 @@ public:
* return is never NULL, unlike Swig_typemap_lookup()
* ----------------------------------------------------------------------------- */
const String *typemapLookup(Node *n, const_String_or_char_ptr op, SwigType *type, int warning, Node *typemap_attributes = 0) {
const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) {
Node *node = !typemap_attributes ? NewHash() : typemap_attributes;
Setattr(node, "type", type);
Setfile(node, Getfile(n));
Setline(node, Getline(n));
const String *tm = Swig_typemap_lookup(op, node, "", 0);
const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0);
if (!tm) {
tm = empty_string;
if (warning != WARN_NONE)
Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", op, SwigType_str(type, 0));
Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0));
}
if (!typemap_attributes)
Delete(node);

View file

@ -200,7 +200,7 @@ void emit_attach_parmmaps(ParmList *l, Wrapper *f) {
* emit_num_arguments()
*
* Calculate the total number of arguments. This function is safe for use
* with multi-valued typemaps which may change the number of arguments in
* with multi-argument typemaps which may change the number of arguments in
* strange ways.
* ----------------------------------------------------------------------------- */
@ -232,7 +232,7 @@ int emit_num_arguments(ParmList *parms) {
* emit_num_required()
*
* Computes the number of required arguments. This function is safe for
* use with multi-valued typemaps and knows how to skip over everything
* use with multi-argument typemaps and knows how to skip over everything
* properly. Note that parameters with default values are counted unless
* the compact default args option is on.
* ----------------------------------------------------------------------------- */

View file

@ -2603,6 +2603,16 @@ public:
Delete(func_name);
}
/*----------------------------------------------------------------------
* replaceSpecialVariables()
*--------------------------------------------------------------------*/
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
SwigType *type = Getattr(parm, "type");
substituteClassname(type, tm);
}
/*----------------------------------------------------------------------
* decodeEnumFeature()
* Decode the possible enum features, which are one of:
@ -2700,16 +2710,16 @@ public:
/* -----------------------------------------------------------------------------
* substituteClassname()
*
* Substitute $javaclassname with the proxy class name for classes/structs/unions that SWIG knows about.
* Also substitutes enums with enum name.
* Substitute the special variable $javaclassname with the proxy class name for classes/structs/unions
* that SWIG knows about. Also substitutes enums with enum name.
* Otherwise use the $descriptor name for the Java class name. Note that the $&javaclassname substitution
* is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
* Inputs:
* pt - parameter type
* tm - jstype typemap
* tm - typemap contents that might contain the special variable to be replaced
* jnidescriptor - if set, inner class names are separated with '$' otherwise a '.'
* Outputs:
* tm - jstype typemap with $javaclassname substitution
* tm - typemap contents complete with the special variable substitution
* Return:
* substitution_performed - flag indicating if a substitution was performed
* ----------------------------------------------------------------------------- */
@ -2862,7 +2872,7 @@ public:
/* -----------------------------------------------------------------------------
* typemapLookup()
* n - for input only and must contain info for Getfile(n) and Getline(n) to work
* op - typemap method name
* tmap_method - typemap method name
* type - typemap type to lookup
* warning - warning number to issue if no typemaps found
* typemap_attributes - the typemap attributes are attached to this node and will
@ -2870,16 +2880,16 @@ public:
* return is never NULL, unlike Swig_typemap_lookup()
* ----------------------------------------------------------------------------- */
const String *typemapLookup(Node *n, const_String_or_char_ptr op, SwigType *type, int warning, Node *typemap_attributes = 0) {
const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) {
Node *node = !typemap_attributes ? NewHash() : typemap_attributes;
Setattr(node, "type", type);
Setfile(node, Getfile(n));
Setline(node, Getline(n));
const String *tm = Swig_typemap_lookup(op, node, "", 0);
const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0);
if (!tm) {
tm = empty_string;
if (warning != WARN_NONE)
Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", op, SwigType_str(type, 0));
Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0));
}
if (!typemap_attributes)
Delete(node);

View file

@ -18,6 +18,7 @@ static int director_mode = 0;
static int director_protected_mode = 1;
static int all_protected_mode = 0;
static int naturalvar_mode = 0;
Language* Language::this_ = 0;
/* Set director_protected_mode */
void Wrapper_director_mode_set(int flag) {
@ -46,6 +47,9 @@ extern "C" {
int Swig_all_protected_mode() {
return all_protected_mode;
}
void Language_replace_special_variables(String *method, String *tm, Parm *parm) {
Language::instance()->replaceSpecialVariables(method, tm, parm);
}
}
/* Some status variables used during parsing */
@ -323,6 +327,8 @@ directors(0) {
director_prot_ctor_code = 0;
director_multiple_inheritance = 1;
director_language = 0;
assert(!this_);
this_ = this;
}
Language::~Language() {
@ -331,6 +337,7 @@ Language::~Language() {
Delete(enumtypes);
Delete(director_ctor_code);
Delete(none_comparison);
this_ = 0;
}
/* ----------------------------------------------------------------------
@ -874,30 +881,8 @@ int Language::cDeclaration(Node *n) {
if (over)
over = first_nontemplate(over);
if (over && (over != n)) {
SwigType *tc = Copy(decl);
SwigType *td = SwigType_pop_function(tc);
String *oname;
String *cname;
if (CurrentClass) {
oname = NewStringf("%s::%s", ClassName, name);
cname = NewStringf("%s::%s", ClassName, Getattr(over, "name"));
} else {
oname = NewString(name);
cname = NewString(Getattr(over, "name"));
}
SwigType *tc2 = Copy(Getattr(over, "decl"));
SwigType *td2 = SwigType_pop_function(tc2);
Swig_warning(WARN_LANG_OVERLOAD_DECL, input_file, line_number, "Overloaded declaration ignored. %s\n", SwigType_str(td, SwigType_namestr(oname)));
Swig_warning(WARN_LANG_OVERLOAD_DECL, Getfile(over), Getline(over), "Previous declaration is %s\n", SwigType_str(td2, SwigType_namestr(cname)));
Delete(tc2);
Delete(td2);
Delete(tc);
Delete(td);
Delete(oname);
Delete(cname);
Swig_warning(WARN_LANG_OVERLOAD_DECL, input_file, line_number, "Overloaded declaration ignored. %s\n", Swig_name_decl(n));
Swig_warning(WARN_LANG_OVERLOAD_DECL, Getfile(over), Getline(over), "Previous declaration is %s\n", Swig_name_decl(over));
return SWIG_NOWRAP;
}
}
@ -978,7 +963,7 @@ int Language::cDeclaration(Node *n) {
if (Strncmp(symname, "__dummy_", 8) == 0) {
SetFlag(n, "feature:ignore");
Swig_warning(WARN_LANG_TEMPLATE_METHOD_IGNORE, input_file, line_number,
"%%template() contains no name. Template method ignored: %s\n", SwigType_str(decl, SwigType_namestr(Getattr(n,"name"))));
"%%template() contains no name. Template method ignored: %s\n", Swig_name_decl(n));
}
}
if (!GetFlag(n, "feature:ignore"))
@ -3423,6 +3408,24 @@ String *Language::defaultExternalRuntimeFilename() {
return 0;
}
/* -----------------------------------------------------------------------------
* Language::replaceSpecialVariables()
* Language modules should implement this if special variables are to be handled
* correctly in the $typemap(...) special variable macro.
* method - typemap method name
* tm - string containing typemap contents
* parm - a parameter describing the typemap type to be handled
* ----------------------------------------------------------------------------- */
void Language::replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
(void)tm;
(void)parm;
}
Language *Language::instance() {
return this_;
}
Hash *Language::getClassHash() const {
return classhash;
}

View file

@ -3581,17 +3581,28 @@ MODULA3():
Delete(throws_hash);
}
/*----------------------------------------------------------------------
* replaceSpecialVariables()
*--------------------------------------------------------------------*/
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
SwigType *type = Getattr(parm, "type");
substituteClassname(type, tm);
}
/* -----------------------------------------------------------------------------
* substituteClassname()
*
* Substitute $m3classname with the proxy class name for classes/structs/unions that SWIG knows about.
* Substitute the special variable $m3classname with the proxy class name for classes/structs/unions
* that SWIG knows about.
* Otherwise use the $descriptor name for the Modula 3 class name. Note that the $&m3classname substitution
* is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
* Inputs:
* pt - parameter type
* tm - m3wraptype typemap
* tm - typemap contents that might contain the special variable to be replaced
* Outputs:
* tm - m3wraptype typemap with $m3classname substitution
* tm - typemap contents complete with the special variable substitution
* Return:
* substitution_performed - flag indicating if a substitution was performed
* ----------------------------------------------------------------------------- */
@ -3807,7 +3818,7 @@ MODULA3():
/* -----------------------------------------------------------------------------
* typemapLookup()
* n - for input only and must contain info for Getfile(n) and Getline(n) to work
* op - typemap method name
* tmap_method - typemap method name
* type - typemap type to lookup
* warning - warning number to issue if no typemaps found
* typemap_attributes - the typemap attributes are attached to this node and will
@ -3815,16 +3826,16 @@ MODULA3():
* return is never NULL, unlike Swig_typemap_lookup()
* ----------------------------------------------------------------------------- */
const String *typemapLookup(Node *n, const_String_or_char_ptr op, SwigType *type, int warning, Node *typemap_attributes = 0) {
const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) {
Node *node = !typemap_attributes ? NewHash() : typemap_attributes;
Setattr(node, "type", type);
Setfile(node, Getfile(n));
Setline(node, Getline(n));
const String *tm = Swig_typemap_lookup(op, node, "", 0);
const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0);
if (!tm) {
tm = empty_string;
if (warning != WARN_NONE)
Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", op, SwigType_str(type, 0));
Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0));
}
if (!typemap_attributes)
Delete(node);

View file

@ -718,6 +718,10 @@ String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxar
Parm *pi = Getattr(ni, "wrap:parms");
int num_required = emit_num_required(pi);
int num_arguments = emit_num_arguments(pi);
if (GetFlag(n, "wrap:this")) {
num_required++;
num_arguments++;
}
if (num_arguments > *maxargs)
*maxargs = num_arguments;
int varargs = emit_isvarargs(pi);
@ -751,7 +755,7 @@ String *Swig_overload_dispatch(Node *n, const_String_or_char_ptr fmt, int *maxar
Printf(f, "}\n");
Delete(lfmt);
}
if (print_typecheck(f, j, pj)) {
if (print_typecheck(f, (GetFlag(n, "wrap:this") ? j + 1 : j), pj)) {
Printf(f, "if (_v) {\n");
num_braces++;
}

File diff suppressed because it is too large Load diff

View file

@ -728,7 +728,7 @@ public:
Printf(f_shadow, tab8 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module);
Printv(f_shadow, tab4 tab8, "finally:\n", NULL);
Printv(f_shadow, tab8 tab8, "fp.close()\n", NULL);
Printv(f_shadow, tab8 tab8, "return _mod\n", NULL);
Printv(f_shadow, tab4 tab8, "return _mod\n", NULL);
Printf(f_shadow, tab4 "%s = swig_import_helper()\n", module);
Printv(f_shadow, tab4, "del swig_import_helper\n", NULL);
Printv(f_shadow, "else:\n", NULL);

View file

@ -1418,15 +1418,13 @@ static List * Swig_overload_rank(Node *n,
String *t2 = Getattr(p2,"tmap:typecheck:precedence");
if ((!t1) && (!nodes[i].error)) {
Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n),
"Overloaded %s(%s) not supported (no type checking rule for '%s').\n",
Getattr(nodes[i].n,"name"),ParmList_str_defaultargs(Getattr(nodes[i].n,"parms")),
SwigType_str(Getattr(p1,"type"),0));
"Overloaded method %s not supported (no type checking rule for '%s').\n",
Swig_name_decl(nodes[i].n), SwigType_str(Getattr(p1, "type"), 0));
nodes[i].error = 1;
} else if ((!t2) && (!nodes[j].error)) {
Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n),
"Overloaded %s(%s) not supported (no type checking rule for '%s').\n",
Getattr(nodes[j].n,"name"),ParmList_str_defaultargs(Getattr(nodes[j].n,"parms")),
SwigType_str(Getattr(p2,"type"),0));
"xx Overloaded method %s not supported (no type checking rule for '%s').\n",
Swig_name_decl(nodes[j].n), SwigType_str(Getattr(p2, "type"), 0));
nodes[j].error = 1;
}
if (t1 && t2) {
@ -1556,21 +1554,15 @@ static List * Swig_overload_rank(Node *n,
if (!nodes[j].error) {
if (script_lang_wrapping) {
Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n),
"Overloaded %s(%s)%s is shadowed by %s(%s)%s at %s:%d.\n",
Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms),
SwigType_isconst(Getattr(nodes[j].n,"decl")) ? " const" : "",
Getattr(nodes[i].n,"name"), ParmList_errorstr(nodes[i].parms),
SwigType_isconst(Getattr(nodes[i].n,"decl")) ? " const" : "",
Getfile(nodes[i].n),Getline(nodes[i].n));
"Overloaded method %s is shadowed by %s at %s:%d.\n",
Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n),
Getfile(nodes[i].n), Getline(nodes[i].n));
} else {
if (!Getattr(nodes[j].n, "overload:ignore"))
Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n),
"Overloaded method %s(%s)%s ignored. Method %s(%s)%s at %s:%d used.\n",
Getattr(nodes[j].n,"name"), ParmList_errorstr(nodes[j].parms),
SwigType_isconst(Getattr(nodes[j].n,"decl")) ? " const" : "",
Getattr(nodes[i].n,"name"), ParmList_errorstr(nodes[i].parms),
SwigType_isconst(Getattr(nodes[i].n,"decl")) ? " const" : "",
Getfile(nodes[i].n),Getline(nodes[i].n));
"Overloaded method %s ignored. Method %s at %s:%d used.\n",
Swig_name_decl(nodes[j].n), Swig_name_decl(nodes[i].n),
Getfile(nodes[i].n), Getline(nodes[i].n));
}
nodes[j].error = 1;
}

View file

@ -216,6 +216,7 @@ public:
virtual int is_assignable(Node *n); /* Is variable assignable? */
virtual String *runtimeCode(); /* returns the language specific runtime code */
virtual String *defaultExternalRuntimeFilename(); /* the default filename for the external runtime */
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm); /* Language specific special variable substitutions for $typemap() */
/* Runtime is C++ based, so extern "C" header section */
void enable_cplus_runtime_mode();
@ -250,6 +251,9 @@ public:
/* Set overload variable templates argc and argv */
void setOverloadResolutionTemplates(String *argc, String *argv);
/* Language instance is a singleton - get instance */
static Language* instance();
protected:
/* Allow multiple-input typemaps */
void allow_multiple_input(int val = 1);
@ -307,6 +311,7 @@ private:
int multiinput;
int cplus_runtime;
int directors;
static Language *this_;
};
int SWIG_main(int, char **, Language *);
@ -347,7 +352,9 @@ void Swig_director_emit_dynamic_cast(Node *n, Wrapper *f);
extern "C" {
void SWIG_typemap_lang(const char *);
typedef Language *(*ModuleFactory) (void);
} void Swig_register_module(const char *name, ModuleFactory fac);
}
void Swig_register_module(const char *name, ModuleFactory fac);
ModuleFactory Swig_find_module(const char *name);
/* Utilities */

View file

@ -1611,7 +1611,7 @@ String *Swig_name_decl(Node *n) {
qname = NewString("");
if (qualifier && Len(qualifier) > 0)
Printf(qname, "%s::", qualifier);
Printf(qname, "%s", name);
Printf(qname, "%s", SwigType_str(name, 0));
decl = NewStringf("%s(%s)%s", qname, ParmList_errorstr(Getattr(n, "parms")), SwigType_isconst(Getattr(n, "decl")) ? " const" : "");

View file

@ -85,6 +85,7 @@ void Scanner_clear(Scanner * s) {
Clear(s->text);
Clear(s->scanobjs);
Delete(s->error);
s->str = 0;
s->error = 0;
s->line = 1;
s->nexttoken = -1;

View file

@ -363,19 +363,19 @@ extern int ParmList_is_compactdefargs(ParmList *p);
/* --- Legacy Typemap API (somewhat simplified, ha!) --- */
extern void Swig_typemap_init(void);
extern void Swig_typemap_register(const_String_or_char_ptr op, ParmList *pattern, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs);
extern int Swig_typemap_copy(const_String_or_char_ptr op, ParmList *srcpattern, ParmList *pattern);
extern void Swig_typemap_clear(const_String_or_char_ptr op, ParmList *pattern);
extern void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *pattern, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs);
extern int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcpattern, ParmList *pattern);
extern void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *pattern);
extern int Swig_typemap_apply(ParmList *srcpat, ParmList *destpat);
extern void Swig_typemap_clear_apply(ParmList *pattern);
extern void Swig_typemap_debug(void);
extern String *Swig_typemap_lookup(const_String_or_char_ptr op, Node *n, const_String_or_char_ptr lname, Wrapper *f);
extern String *Swig_typemap_lookup_out(const_String_or_char_ptr op, Node *n, const_String_or_char_ptr lname, Wrapper *f, String *actioncode);
extern String *Swig_typemap_lookup(const_String_or_char_ptr tmap_method, Node *n, const_String_or_char_ptr lname, Wrapper *f);
extern String *Swig_typemap_lookup_out(const_String_or_char_ptr tmap_method, Node *n, const_String_or_char_ptr lname, Wrapper *f, String *actioncode);
extern void Swig_typemap_new_scope(void);
extern Hash *Swig_typemap_pop_scope(void);
extern void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wrapper *f);
extern void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f);
/* --- Code fragment support --- */
@ -390,6 +390,7 @@ extern int ParmList_is_compactdefargs(ParmList *p);
extern void Wrapper_director_mode_set(int);
extern void Wrapper_director_protected_mode_set(int);
extern void Wrapper_all_protected_mode_set(int);
extern void Language_replace_special_variables(String *method, String *tm, Parm *parm);
/* -- template init -- */

View file

@ -17,7 +17,7 @@ char cvsroot_typemap_c[] = "$Id$";
#define SWIG_DEBUG
#endif
static void replace_embedded_typemap(String *s);
static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f);
/* -----------------------------------------------------------------------------
* Typemaps are stored in a collection of nested hash tables. Something like
@ -31,14 +31,24 @@ static void replace_embedded_typemap(String *s);
* different typemap methods. These are referenced by names such as
* "tmap:in", "tmap:out", "tmap:argout", and so forth.
*
* The object corresponding to a specific method has the following
* attributes:
* The object corresponding to a specific typemap method has the following attributes:
*
* "type" - Typemap type
* "pname" - Parameter name
* "code" - Typemap code
* "typemap" - Descriptive text describing the actual map
* "locals" - Local variables (if any)
* "kwargs" - Typemap attributes
*
* Example for a typemap method named "in":
* %typemap(in, warning="987:my warning", noblock=1) int &my_int (int tmp) "$1 = $input;"
*
* "type" - r.int
* "pname" - my_int
* "code" - $1 = $input;
* "typemap" - typemap(in) int &my_int
* "locals" - int tmp
* "kwargs" - warning="987:my typemap warning", foo=123
*
* ----------------------------------------------------------------------------- */
@ -107,29 +117,29 @@ void Swig_typemap_init() {
tm_scope = 0;
}
static String *tmop_name(const_String_or_char_ptr op) {
static String *typemap_method_name(const_String_or_char_ptr tmap_method) {
static Hash *names = 0;
String *s;
/* Due to "interesting" object-identity semantics of DOH,
we have to make sure that we only intern strings without object
identity into the hash table.
(typemap_attach_kwargs calls tmop_name several times with
the "same" String *op (i.e., same object identity) but differing
(typemap_attach_kwargs calls typemap_method_name several times with
the "same" String *tmap_method (i.e., same object identity) but differing
string values.)
Most other callers work around this by using char* rather than
String *.
-- mkoeppe, Jun 17, 2003
*/
const char *op_without_object_identity = Char(op);
const char *method_without_object_identity = Char(tmap_method);
if (!names)
names = NewHash();
s = Getattr(names, op_without_object_identity);
s = Getattr(names, method_without_object_identity);
if (s)
return s;
s = NewStringf("tmap:%s", op);
Setattr(names, op_without_object_identity, s);
s = NewStringf("tmap:%s", tmap_method);
Setattr(names, method_without_object_identity, s);
Delete(s);
return s;
}
@ -163,21 +173,21 @@ Hash *Swig_typemap_pop_scope() {
/* -----------------------------------------------------------------------------
* Swig_typemap_register()
*
* Add a new multi-valued typemap
* Add a new multi-argument typemap
* ----------------------------------------------------------------------------- */
void Swig_typemap_register(const_String_or_char_ptr op, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs) {
void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs) {
Hash *tm;
Hash *tm1;
Hash *tm2;
Parm *np;
String *tmop;
String *tm_method;
SwigType *type;
String *pname;
if (!parms)
return;
tmop = tmop_name(op);
tm_method = typemap_method_name(tmap_method);
/* Register the first type in the parameter list */
@ -202,15 +212,15 @@ void Swig_typemap_register(const_String_or_char_ptr op, ParmList *parms, const_S
tm = tm1;
}
/* Now see if this typemap op has been seen before */
tm2 = Getattr(tm, tmop);
/* Now see if this typemap method has been seen before */
tm2 = Getattr(tm, tm_method);
if (!tm2) {
tm2 = NewHash();
Setattr(tm, tmop, tm2);
Setattr(tm, tm_method, tm2);
Delete(tm2);
}
/* For a multi-valued typemap, the typemap code and information
/* For a multi-argument typemap, the typemap code and information
is really only stored in the last argument. However, to
make this work, we perform a really neat trick using
the typemap operator name.
@ -237,7 +247,7 @@ void Swig_typemap_register(const_String_or_char_ptr op, ParmList *parms, const_S
np = nextSibling(parms);
if (np) {
/* Make an entirely new operator key */
String *newop = NewStringf("%s-%s+%s:", op, type, pname);
String *newop = NewStringf("%s-%s+%s:", tmap_method, type, pname);
/* Now reregister on the remaining arguments */
Swig_typemap_register(newop, np, code, locals, kwargs);
@ -245,7 +255,7 @@ void Swig_typemap_register(const_String_or_char_ptr op, ParmList *parms, const_S
Delete(newop);
} else {
String *str = SwigType_str(type, pname);
String *typemap = NewStringf("typemap(%s) %s", op, str);
String *typemap = NewStringf("typemap(%s) %s", tmap_method, str);
ParmList *clocals = CopyParmList(locals);
ParmList *ckwargs = CopyParmList(kwargs);
@ -294,21 +304,21 @@ static Hash *typemap_get(SwigType *type, const_String_or_char_ptr name, int scop
* Copy a typemap
* ----------------------------------------------------------------------------- */
int Swig_typemap_copy(const_String_or_char_ptr op, ParmList *srcparms, ParmList *parms) {
int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcparms, ParmList *parms) {
Hash *tm = 0;
String *tmop;
String *tm_method;
Parm *p;
String *pname;
SwigType *ptype;
int ts = tm_scope;
String *tmops, *newop;
String *tm_methods, *newop;
if (ParmList_len(parms) != ParmList_len(srcparms))
return -1;
tmop = tmop_name(op);
tm_method = typemap_method_name(tmap_method);
while (ts >= 0) {
p = srcparms;
tmops = NewString(tmop);
tm_methods = NewString(tm_method);
while (p) {
ptype = Getattr(p, "type");
pname = Getattr(p, "name");
@ -318,22 +328,22 @@ int Swig_typemap_copy(const_String_or_char_ptr op, ParmList *srcparms, ParmList
if (!tm)
break;
tm = Getattr(tm, tmops);
tm = Getattr(tm, tm_methods);
if (!tm)
break;
/* Got a match. Look for next typemap */
newop = NewStringf("%s-%s+%s:", tmops, ptype, pname);
Delete(tmops);
tmops = newop;
newop = NewStringf("%s-%s+%s:", tm_methods, ptype, pname);
Delete(tm_methods);
tm_methods = newop;
p = nextSibling(p);
}
Delete(tmops);
Delete(tm_methods);
if (!p && tm) {
/* Got some kind of match */
Swig_typemap_register(op, parms, Getattr(tm, "code"), Getattr(tm, "locals"), Getattr(tm, "kwargs"));
Swig_typemap_register(tmap_method, parms, Getattr(tm, "code"), Getattr(tm, "locals"), Getattr(tm, "kwargs"));
return 0;
}
ts--;
@ -346,10 +356,10 @@ int Swig_typemap_copy(const_String_or_char_ptr op, ParmList *srcparms, ParmList
/* -----------------------------------------------------------------------------
* Swig_typemap_clear()
*
* Delete a multi-valued typemap
* Delete a multi-argument typemap
* ----------------------------------------------------------------------------- */
void Swig_typemap_clear(const_String_or_char_ptr op, ParmList *parms) {
void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *parms) {
SwigType *type;
String *name;
Parm *p;
@ -357,7 +367,7 @@ void Swig_typemap_clear(const_String_or_char_ptr op, ParmList *parms) {
Hash *tm = 0;
/* This might not work */
newop = NewString(op);
newop = NewString(tmap_method);
p = parms;
while (p) {
type = Getattr(p, "type");
@ -370,7 +380,7 @@ void Swig_typemap_clear(const_String_or_char_ptr op, ParmList *parms) {
Printf(newop, "-%s+%s:", type, name);
}
if (tm) {
tm = Getattr(tm, tmop_name(newop));
tm = Getattr(tm, typemap_method_name(newop));
if (tm) {
Delattr(tm, "code");
Delattr(tm, "locals");
@ -591,7 +601,7 @@ static SwigType *strip_arrays(SwigType *type) {
* that includes a 'code' attribute.
* ----------------------------------------------------------------------------- */
static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_String_or_char_ptr name, SwigType **matchtype) {
static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type, const_String_or_char_ptr name, SwigType **matchtype) {
Hash *result = 0, *tm, *tm1, *tma;
Hash *backup = 0;
SwigType *noarrays = 0;
@ -601,7 +611,7 @@ static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_S
int isarray;
const String *cname = 0;
SwigType *unstripped = 0;
String *tmop = tmop_name(op);
String *tm_method = typemap_method_name(tmap_method);
if ((name) && Len(name))
cname = name;
@ -615,7 +625,7 @@ static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_S
if (tm && cname) {
tm1 = Getattr(tm, cname);
if (tm1) {
result = Getattr(tm1, tmop); /* See if there is a type-name match */
result = Getattr(tm1, tm_method); /* See if there is a type-name match */
if (result && Getattr(result, "code"))
goto ret_result;
if (result)
@ -623,7 +633,7 @@ static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_S
}
}
if (tm) {
result = Getattr(tm, tmop); /* See if there is simply a type match */
result = Getattr(tm, tm_method); /* See if there is simply a type match */
if (result && Getattr(result, "code"))
goto ret_result;
if (result)
@ -640,7 +650,7 @@ static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_S
if (tma && cname) {
tm1 = Getattr(tma, cname);
if (tm1) {
result = Getattr(tm1, tmop); /* type-name match */
result = Getattr(tm1, tm_method); /* type-name match */
if (result && Getattr(result, "code"))
goto ret_result;
if (result)
@ -648,7 +658,7 @@ static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_S
}
}
if (tma) {
result = Getattr(tma, tmop); /* type match */
result = Getattr(tma, tm_method); /* type match */
if (result && Getattr(result, "code"))
goto ret_result;
if (result)
@ -692,13 +702,13 @@ static Hash *typemap_search(const_String_or_char_ptr op, SwigType *type, const_S
if (tm && cname) {
tm1 = Getattr(tm, cname);
if (tm1) {
result = Getattr(tm1, tmop); /* See if there is a type-name match */
result = Getattr(tm1, tm_method); /* See if there is a type-name match */
if (result)
goto ret_result;
}
}
if (tm) { /* See if there is simply a type match */
result = Getattr(tm, tmop);
result = Getattr(tm, tm_method);
if (result)
goto ret_result;
}
@ -735,10 +745,10 @@ ret_result:
/* -----------------------------------------------------------------------------
* typemap_search_multi()
*
* Search for a multi-valued typemap.
* Search for a multi-argument typemap.
* ----------------------------------------------------------------------------- */
static Hash *typemap_search_multi(const_String_or_char_ptr op, ParmList *parms, int *nmatch) {
static Hash *typemap_search_multi(const_String_or_char_ptr tmap_method, ParmList *parms, int *nmatch) {
SwigType *type;
SwigType *mtype = 0;
String *name;
@ -753,13 +763,13 @@ static Hash *typemap_search_multi(const_String_or_char_ptr op, ParmList *parms,
name = Getattr(parms, "name");
/* Try to find a match on the first type */
tm = typemap_search(op, type, name, &mtype);
tm = typemap_search(tmap_method, type, name, &mtype);
if (tm) {
if (mtype && SwigType_isarray(mtype)) {
Setattr(parms, "tmap:match", mtype);
}
Delete(mtype);
newop = NewStringf("%s-%s+%s:", op, type, name);
newop = NewStringf("%s-%s+%s:", tmap_method, type, name);
tm1 = typemap_search_multi(newop, nextSibling(parms), nmatch);
if (tm1)
tm = tm1;
@ -806,7 +816,7 @@ static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, Swi
SwigType *ftype;
int bare_substitution_count = 0;
Replaceall(s, "$typemap", "$TYPEMAP");
Replaceall(s, "$typemap", "$TYPEMAP"); /* workaround for $type substitution below */
ftype = SwigType_typedef_resolve_all(type);
@ -1162,16 +1172,26 @@ static void typemap_locals(DOHString * s, ParmList *l, Wrapper *f, int argnum) {
*
* Attach one or more typemaps to a node and optionally generate the typemap contents
* into the wrapper.
* op - typemap name, eg "out", "newfree"
* node - the node to attach the typemaps to
* lname - name of variable to substitute $1, $2 etc for
* f - wrapper code to generate into if non null
* actioncode - code to generate into f before the out typemap code, unless
*
* Looks for a typemap matching the given type and name and attaches the typemap code
* and any typemap attributes to the provided node.
*
* The node should contain the "type" and "name" attributes for the typemap match on.
* input. The typemap code and typemap attribute values are attached onto the node
* prefixed with "tmap:". For example with tmap_method="in", the typemap code can be retrieved
* with a call to Getattr(node, "tmap:in") (this is also the string returned) and the
* "noblock" attribute can be retrieved with a call to Getattr(node, "tmap:in:noblock").
*
* tmap_method - typemap method, eg "in", "out", "newfree"
* node - the node to attach the typemap and typemap attributes to
* lname - name of variable to substitute $1, $2 etc for
* f - wrapper code to generate into if non null
* actioncode - code to generate into f before the out typemap code, unless
* the optimal attribute is set in the out typemap in which case
* $1 in the out typemap will be replaced by the code in actioncode.
* ----------------------------------------------------------------------------- */
static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) {
static String *Swig_typemap_lookup_impl(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) {
SwigType *type;
SwigType *mtype = 0;
String *pname;
@ -1184,14 +1204,14 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
String *symname;
String *cname = 0;
String *clname = 0;
char *cop = Char(op);
char *cop = Char(tmap_method);
int optimal_attribute = 0;
int optimal_substitution = 0;
int num_substitutions = 0;
/* special case, we need to check for 'ref' call
and set the default code 'sdef' */
if (node && Cmp(op, "newfree") == 0) {
if (node && Cmp(tmap_method, "newfree") == 0) {
sdef = Swig_ref_call(node, lname);
}
@ -1214,7 +1234,7 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
String *qsn = st ? Swig_symbol_string_qualify(pname, st) : 0;
if (qsn) {
if (Len(qsn) && !Equal(qsn, pname)) {
tm = typemap_search(op, type, qsn, &mtype);
tm = typemap_search(tmap_method, type, qsn, &mtype);
if (tm && (!Getattr(tm, "pname") || strstr(Char(Getattr(tm, "type")), "SWIGTYPE"))) {
tm = 0;
}
@ -1224,7 +1244,7 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
}
if (!tm)
#endif
tm = typemap_search(op, type, pname, &mtype);
tm = typemap_search(tmap_method, type, pname, &mtype);
if (!tm)
return sdef;
@ -1242,15 +1262,15 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
kw = Getattr(tm, "kwargs");
while (kw) {
String *value = Copy(Getattr(kw, "value"));
String *type = Getattr(kw, "type");
String *kwtype = Getattr(kw, "type");
char *ckwname = Char(Getattr(kw, "name"));
if (type) {
String *mangle = Swig_string_mangle(type);
if (kwtype) {
String *mangle = Swig_string_mangle(kwtype);
Append(value, mangle);
Delete(mangle);
}
sprintf(temp, "%s:%s", cop, ckwname);
Setattr(node, tmop_name(temp), value);
Setattr(node, typemap_method_name(temp), value);
if (Cmp(temp, "out:optimal") == 0)
optimal_attribute = (Cmp(value, "0") != 0) ? 1 : 0;
Delete(value);
@ -1324,7 +1344,13 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
if (locals && f) {
typemap_locals(s, locals, f, -1);
}
replace_embedded_typemap(s);
{
ParmList *parm_sublist = NewParm(type, pname);
Setattr(parm_sublist, "lname", lname);
replace_embedded_typemap(s, parm_sublist, f);
Delete(parm_sublist);
}
Replace(s, "$name", pname, DOH_REPLACE_ANY);
@ -1333,23 +1359,23 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
Replace(s, "$symname", symname, DOH_REPLACE_ANY);
}
Setattr(node, tmop_name(op), s);
Setattr(node, typemap_method_name(tmap_method), s);
if (locals) {
sprintf(temp, "%s:locals", cop);
Setattr(node, tmop_name(temp), locals);
Setattr(node, typemap_method_name(temp), locals);
Delete(locals);
}
if (Checkattr(tm, "type", "SWIGTYPE")) {
sprintf(temp, "%s:SWIGTYPE", cop);
Setattr(node, tmop_name(temp), "1");
Setattr(node, typemap_method_name(temp), "1");
}
/* Look for warnings */
{
String *w;
sprintf(temp, "%s:warning", cop);
w = Getattr(node, tmop_name(temp));
w = Getattr(node, typemap_method_name(temp));
if (w) {
Swig_warning(0, Getfile(node), Getline(node), "%s\n", w);
}
@ -1357,11 +1383,11 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
/* Look for code fragments */
{
String *f;
String *fragment;
sprintf(temp, "%s:fragment", cop);
f = Getattr(node, tmop_name(temp));
if (f) {
String *fname = Copy(f);
fragment = Getattr(node, typemap_method_name(temp));
if (fragment) {
String *fname = Copy(fragment);
Setfile(fname, Getfile(node));
Setline(fname, Getline(node));
Swig_fragment_emit(fname);
@ -1382,14 +1408,14 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
return s;
}
String *Swig_typemap_lookup_out(const_String_or_char_ptr op, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) {
String *Swig_typemap_lookup_out(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) {
assert(actioncode);
assert(Cmp(op, "out") == 0);
return Swig_typemap_lookup_impl(op, node, lname, f, actioncode);
assert(Cmp(tmap_method, "out") == 0);
return Swig_typemap_lookup_impl(tmap_method, node, lname, f, actioncode);
}
String *Swig_typemap_lookup(const_String_or_char_ptr op, Node *node, const_String_or_char_ptr lname, Wrapper *f) {
return Swig_typemap_lookup_impl(op, node, lname, f, 0);
String *Swig_typemap_lookup(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f) {
return Swig_typemap_lookup_impl(tmap_method, node, lname, f, 0);
}
/* -----------------------------------------------------------------------------
@ -1403,7 +1429,7 @@ String *Swig_typemap_lookup(const_String_or_char_ptr op, Node *node, const_Strin
* A new attribute called "tmap:in:foo" with value "xyz" is attached to p.
* ----------------------------------------------------------------------------- */
static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr op, Parm *p) {
static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr tmap_method, Parm *p) {
String *temp = NewStringEmpty();
Parm *kw = Getattr(tm, "kwargs");
while (kw) {
@ -1417,36 +1443,36 @@ static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr op, Parm *p
value = v;
}
Clear(temp);
Printf(temp, "%s:%s", op, Getattr(kw, "name"));
Setattr(p, tmop_name(temp), value);
Printf(temp, "%s:%s", tmap_method, Getattr(kw, "name"));
Setattr(p, typemap_method_name(temp), value);
Delete(value);
kw = nextSibling(kw);
}
Clear(temp);
Printf(temp, "%s:match_type", op);
Setattr(p, tmop_name(temp), Getattr(tm, "type"));
Printf(temp, "%s:match_type", tmap_method);
Setattr(p, typemap_method_name(temp), Getattr(tm, "type"));
Delete(temp);
}
/* -----------------------------------------------------------------------------
* typemap_warn()
*
* If any warning message is attached to this parameter's "tmap:op:warning"
* If any warning message is attached to this parameter's "tmap:<method>:warning"
* attribute, print that warning message.
* ----------------------------------------------------------------------------- */
static void typemap_warn(const_String_or_char_ptr op, Parm *p) {
String *temp = NewStringf("%s:warning", op);
String *w = Getattr(p, tmop_name(temp));
static void typemap_warn(const_String_or_char_ptr tmap_method, Parm *p) {
String *temp = NewStringf("%s:warning", tmap_method);
String *w = Getattr(p, typemap_method_name(temp));
Delete(temp);
if (w) {
Swig_warning(0, Getfile(p), Getline(p), "%s\n", w);
}
}
static void typemap_emit_code_fragments(const_String_or_char_ptr op, Parm *p) {
String *temp = NewStringf("%s:fragment", op);
String *f = Getattr(p, tmop_name(temp));
static void typemap_emit_code_fragments(const_String_or_char_ptr tmap_method, Parm *p) {
String *temp = NewStringf("%s:fragment", tmap_method);
String *f = Getattr(p, typemap_method_name(temp));
if (f) {
String *fname = Copy(f);
Setfile(fname, Getfile(p));
@ -1457,13 +1483,6 @@ static void typemap_emit_code_fragments(const_String_or_char_ptr op, Parm *p) {
Delete(temp);
}
/* -----------------------------------------------------------------------------
* Swig_typemap_attach_parms()
*
* Given a parameter list, this function attaches all of the typemaps for a
* given typemap type
* ----------------------------------------------------------------------------- */
static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) {
Parm *kw = Getattr(tm, "kwargs");
while (kw) {
@ -1476,7 +1495,23 @@ static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) {
return 0;
}
void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wrapper *f) {
/* -----------------------------------------------------------------------------
* Swig_typemap_attach_parms()
*
* Given a parameter list, this function attaches all of the typemaps and typemap
* attributes to the parameter for each type in the parameter list.
*
* This function basically provides the typemap code and typemap attribute values as
* attributes on each parameter prefixed with "tmap:". For example with tmap_method="in", the typemap
* code can be retrieved for the first parameter with a call to Getattr(parm, "tmap:in")
* and the "numinputs" attribute can be retrieved with a call to Getattr(parm, "tmap:in:numinputs").
*
* tmap_method - typemap method, eg "in", "out", "newfree"
* parms - parameter list to attach each typemap and all typemap attributes
* f - wrapper code to generate into if non null
* ----------------------------------------------------------------------------- */
void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f) {
Parm *p, *firstp;
Hash *tm;
int nmatch = 0;
@ -1485,21 +1520,21 @@ void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wra
ParmList *locals;
int argnum = 0;
char temp[256];
char *cop = Char(op);
char *cop = Char(tmap_method);
String *kwmatch = 0;
p = parms;
#ifdef SWIG_DEBUG
Printf(stdout, "Swig_typemap_attach_parms: %s\n", op);
Printf(stdout, "Swig_typemap_attach_parms: %s\n", tmap_method);
#endif
while (p) {
argnum++;
nmatch = 0;
#ifdef SWIG_DEBUG
Printf(stdout, "parms: %s %s %s\n", op, Getattr(p, "name"), Getattr(p, "type"));
Printf(stdout, "parms: %s %s %s\n", tmap_method, Getattr(p, "name"), Getattr(p, "type"));
#endif
tm = typemap_search_multi(op, p, &nmatch);
tm = typemap_search_multi(tmap_method, p, &nmatch);
#ifdef SWIG_DEBUG
if (tm)
Printf(stdout, "found: %s\n", tm);
@ -1605,7 +1640,7 @@ void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wra
if (Checkattr(tm, "type", "SWIGTYPE")) {
sprintf(temp, "%s:SWIGTYPE", cop);
Setattr(p, tmop_name(temp), "1");
Setattr(p, typemap_method_name(temp), "1");
}
p = nextSibling(p);
}
@ -1614,7 +1649,7 @@ void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wra
typemap_locals(s, locals, f, argnum);
}
replace_embedded_typemap(s);
replace_embedded_typemap(s, firstp, f);
/* Replace the argument number */
sprintf(temp, "%d", argnum);
@ -1622,34 +1657,34 @@ void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wra
/* Attach attributes to object */
#ifdef SWIG_DEBUG
Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, "name"), tmop_name(op), s);
Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), s);
#endif
Setattr(firstp, tmop_name(op), s); /* Code object */
Setattr(firstp, typemap_method_name(tmap_method), s); /* Code object */
if (locals) {
sprintf(temp, "%s:locals", cop);
Setattr(firstp, tmop_name(temp), locals);
Setattr(firstp, typemap_method_name(temp), locals);
Delete(locals);
}
/* Attach a link to the next parameter. Needed for multimaps */
sprintf(temp, "%s:next", cop);
Setattr(firstp, tmop_name(temp), p);
Setattr(firstp, typemap_method_name(temp), p);
/* Attach kwargs */
typemap_attach_kwargs(tm, op, firstp);
typemap_attach_kwargs(tm, tmap_method, firstp);
/* Print warnings, if any */
typemap_warn(op, firstp);
typemap_warn(tmap_method, firstp);
/* Look for code fragments */
typemap_emit_code_fragments(op, firstp);
typemap_emit_code_fragments(tmap_method, firstp);
/* increase argnum to consider numinputs */
argnum += nmatch - 1;
Delete(s);
#ifdef SWIG_DEBUG
Printf(stdout, "res: %s %s %s\n", Getattr(firstp, "name"), tmop_name(op), Getattr(firstp, tmop_name(op)));
Printf(stdout, "res: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), Getattr(firstp, typemap_method_name(tmap_method)));
#endif
}
@ -1659,23 +1694,8 @@ void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wra
}
/* -----------------------------------------------------------------------------
* split_embedded()
*
* This function replaces the special variable $typemap(....) with typemap
* code. The general form of $typemap is as follows:
*
* $TYPEMAP(method, $var1=value, $var2=value, $var3=value,...)
*
* For example:
*
* $TYPEMAP(in, $1=int x, $input=y, ...)
*
* Note: this was added as an experiment and could be removed
* ----------------------------------------------------------------------------- */
/* Splits the arguments of an embedded typemap */
static List *split_embedded(String *s) {
static List *split_embedded_typemap(String *s) {
List *args = 0;
char *c, *start;
int level = 0;
@ -1683,6 +1703,7 @@ static List *split_embedded(String *s) {
args = NewList();
c = strchr(Char(s), '(');
assert(c);
c++;
start = c;
@ -1723,41 +1744,36 @@ static List *split_embedded(String *s) {
return args;
}
static void split_var(String *s, String **name, String **value) {
char *eq;
char *c;
/* -----------------------------------------------------------------------------
* replace_embedded_typemap()
*
* This function replaces the special variable macro $typemap(...) with typemap
* code. The general form of $typemap is as follows:
*
* $typemap(method, typelist, var1=value, var2=value, ...)
*
* where varx parameters are optional and undocumented; they were used in an earlier version of $typemap.
* A search is made using the typemap matching rules of form:
*
* %typemap(method) typelist {...}
*
* and if found will substitute in the typemap contents, making appropriate variable replacements.
*
* For example:
* $typemap(in, int) # simple usage matching %typemap(in) int { ... }
* $typemap(in, int b) # simple usage matching %typemap(in) int b { ... } or above %typemap
* $typemap(in, (Foo<int, bool> a, int b)) # multi-argument typemap matching %typemap(in) (Foo<int, bool> a, int b) {...}
* ----------------------------------------------------------------------------- */
eq = strchr(Char(s), '=');
if (!eq) {
*name = 0;
*value = 0;
return;
}
c = Char(s);
*name = NewStringWithSize(c, eq - c);
/* Look for $n variables */
if (isdigit((int) *(c))) {
/* Parse the value as a type */
String *v;
Parm *p;
v = NewString(eq + 1);
p = Swig_cparse_parm(v);
Delete(v);
*value = p;
} else {
*value = NewString(eq + 1);
}
}
static void replace_embedded_typemap(String *s) {
static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f) {
char *start = 0;
while ((start = strstr(Char(s), "$TYPEMAP("))) {
while ((start = strstr(Char(s), "$TYPEMAP("))) { /* note $typemap capitalisation to $TYPEMAP hack */
/* Gather the argument */
/* Gather the parameters */
char *end = 0, *c;
int level = 0;
String *tmp;
String *dollar_typemap;
int syntax_error = 1;
c = start;
while (*c) {
if (*c == '(')
@ -1772,103 +1788,127 @@ static void replace_embedded_typemap(String *s) {
c++;
}
if (end) {
tmp = NewStringWithSize(start, (end - start));
dollar_typemap = NewStringWithSize(start, (end - start));
syntax_error = 0;
} else {
tmp = 0;
dollar_typemap = NewStringWithSize(start, (c - start));
}
/* Got a substitution. Split it apart into pieces */
if (tmp) {
if (!syntax_error) {
List *l;
String *tmap_method;
Hash *vars;
String *method;
int i, ilen;
syntax_error = 1;
l = split_embedded(tmp);
vars = NewHash();
ilen = Len(l);
for (i = 1; i < ilen; i++) {
String *n, *v;
split_var(Getitem(l, i), &n, &v);
if (n && v) {
Insert(n, 0, "$");
Setattr(vars, n, v);
}
Delete(n);
Delete(v);
}
/* Split apart each parameter in $typemap(...) */
l = split_embedded_typemap(dollar_typemap);
method = Getitem(l, 0);
/* Generate the parameter list for matching typemaps */
if (Len(l) >= 2) {
ParmList *to_match_parms;
tmap_method = Getitem(l, 0);
{
Parm *p = 0;
Parm *first = 0;
char temp[32];
int n = 1;
while (1) {
Hash *v;
sprintf(temp, "$%d", n);
v = Getattr(vars, temp);
if (v) {
if (p) {
set_nextSibling(p, v);
set_previousSibling(v, p);
/* the second parameter might contain multiple sub-parameters for multi-argument
* typemap matching, so split these parameters apart */
to_match_parms = Swig_cparse_parms(Getitem(l, 1));
if (to_match_parms) {
Parm *p = to_match_parms;
Parm *sub_p = parm_sublist;
String *empty_string = NewStringEmpty();
String *lname = empty_string;
while (p) {
if (sub_p) {
lname = Getattr(sub_p, "lname");
sub_p = nextSibling(sub_p);
}
p = v;
Setattr(p, "lname", Getattr(p, "name"));
if (Getattr(p, "value")) {
Setattr(p, "name", Getattr(p, "value"));
}
if (!first)
first = p;
DohIncref(p);
Delattr(vars, temp);
} else {
break;
Setattr(p, "lname", lname);
p = nextSibling(p);
}
n++;
Delete(empty_string);
}
/* process optional extra parameters - the variable replacements (undocumented) */
vars = NewHash();
{
int i, ilen;
ilen = Len(l);
for (i = 2; i < ilen; i++) {
String *parm = Getitem(l, i);
char *eq = strchr(Char(parm), '=');
char *c = Char(parm);
if (eq && (eq - c > 0)) {
String *name = NewStringWithSize(c, eq - c);
String *value = NewString(eq + 1);
Insert(name, 0, "$");
Setattr(vars, name, value);
} else {
to_match_parms = 0; /* error - variable replacement parameters must be of form varname=value */
}
}
}
/* Perform a typemap search */
if (first) {
if (to_match_parms) {
static int already_substituting = 0;
String *tm;
String *attr;
int match = 0;
#ifdef SWIG_DEBUG
Printf(stdout, "Swig_typemap_attach_parms: embedded\n");
#endif
Swig_typemap_attach_parms(method, first, 0);
{
String *tm;
int match = 0;
char attr[64];
sprintf(attr, "tmap:%s", Char(method));
if (!already_substituting) {
already_substituting = 1;
Swig_typemap_attach_parms(tmap_method, to_match_parms, f);
already_substituting = 0;
/* Look for the typemap code */
tm = Getattr(first, attr);
attr = NewStringf("tmap:%s", tmap_method);
tm = Getattr(to_match_parms, attr);
if (tm) {
sprintf(attr, "tmap:%s:next", Char(method));
if (!Getattr(first, attr)) {
/* Should be no more matches. Hack??? */
/* Replace all of the remaining variables */
Printf(attr, "%s", ":next");
/* fail if multi-argument lookup requested in $typemap(...) and the lookup failed */
if (!Getattr(to_match_parms, attr)) {
/* Replace parameter variables */
Iterator ki;
for (ki = First(vars); ki.key; ki = Next(ki)) {
Replace(tm, ki.key, ki.item, DOH_REPLACE_ANY);
}
/* Do the replacement */
Replace(s, tmp, tm, DOH_REPLACE_ANY);
/* offer the target language module the chance to make special variable substitutions */
Language_replace_special_variables(tmap_method, tm, to_match_parms);
/* finish up - do the substitution */
Replace(s, dollar_typemap, tm, DOH_REPLACE_ANY);
Delete(tm);
match = 1;
}
}
if (!match) {
Swig_error(Getfile(s), Getline(s), "No typemap found for %s\n", tmp);
String *dtypemap = NewString(dollar_typemap);
Replaceall(dtypemap, "$TYPEMAP", "$typemap");
Swig_error(Getfile(s), Getline(s), "No typemap found for %s\n", dtypemap);
Delete(dtypemap);
}
Delete(attr);
} else {
/* simple recursive call check, but prevents using an embedded typemap that contains another embedded typemap */
String *dtypemap = NewString(dollar_typemap);
Replaceall(dtypemap, "$TYPEMAP", "$typemap");
Swig_error(Getfile(s), Getline(s), "Recursive $typemap calls not supported - %s\n", dtypemap);
Delete(dtypemap);
}
syntax_error = 0;
}
Delete(vars);
}
Replace(s, tmp, "<embedded typemap>", DOH_REPLACE_ANY);
Delete(vars);
Delete(tmp);
Delete(l);
}
if (syntax_error) {
String *dtypemap = NewString(dollar_typemap);
Replaceall(dtypemap, "$TYPEMAP", "$typemap");
Swig_error(Getfile(s), Getline(s), "Syntax error in: %s\n", dtypemap);
Delete(dtypemap);
}
Replace(s, dollar_typemap, "<error in embedded typemap>", DOH_REPLACE_ANY);
Delete(dollar_typemap);
}
}