(method, typelist) special variable macro fixed/enhanced and made official

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@11470 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2009-07-29 20:50:39 +00:00
commit bf0ee4471c
17 changed files with 532 additions and 161 deletions

View file

@ -1,6 +1,11 @@
Version 1.3.40 (in progress) Version 1.3.40 (in progress)
============================ ============================
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 2009-07-29: vmiklos
[PHP] Static member variables are now prefixed with the [PHP] Static member variables are now prefixed with the
class name. This allows static member variables with the class name. This allows static member variables with the

View file

@ -337,13 +337,13 @@
</ul> </ul>
<li><a href="Typemaps.html#Typemaps_nn10">Typemap specifications</a> <li><a href="Typemaps.html#Typemaps_nn10">Typemap specifications</a>
<ul> <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_nn12">Typemap scope</a>
<li><a href="Typemaps.html#Typemaps_nn13">Copying a typemap</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_nn14">Deleting a typemap</a>
<li><a href="Typemaps.html#Typemaps_nn15">Placement of typemaps</a> <li><a href="Typemaps.html#Typemaps_nn15">Placement of typemaps</a>
</ul> </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> <ul>
<li><a href="Typemaps.html#Typemaps_nn17">Basic matching rules</a> <li><a href="Typemaps.html#Typemaps_nn17">Basic matching rules</a>
<li><a href="Typemaps.html#Typemaps_nn18">Typedef reductions</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_nn22">Scope</a>
<li><a href="Typemaps.html#Typemaps_nn23">Declaring new local variables</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_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> </ul>
<li><a href="Typemaps.html#Typemaps_nn25">Common typemap methods</a> <li><a href="Typemaps.html#Typemaps_nn25">Common typemap methods</a>
<ul> <ul>
@ -384,7 +389,7 @@
<li><a href="Typemaps.html#runtime_type_checker">The run-time type checker</a> <li><a href="Typemaps.html#runtime_type_checker">The run-time type checker</a>
<ul> <ul>
<li><a href="Typemaps.html#Typemaps_nn45">Implementation</a> <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> </ul>
<li><a href="Typemaps.html#Typemaps_overloading">Typemaps and overloading</a> <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> <li><a href="Typemaps.html#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></a>
@ -1502,6 +1507,7 @@
<ul> <ul>
<li><a href="Tcl.html#Tcl_nn45">Proxy classes</a> <li><a href="Tcl.html#Tcl_nn45">Proxy classes</a>
</ul> </ul>
<li><a href="Tcl.html#Tcl_nn46">Tcl/Tk Stubs</a>
</ul> </ul>
</div> </div>
<!-- INDEX --> <!-- INDEX -->

View file

@ -22,13 +22,13 @@
</ul> </ul>
<li><a href="#Typemaps_nn10">Typemap specifications</a> <li><a href="#Typemaps_nn10">Typemap specifications</a>
<ul> <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_nn12">Typemap scope</a>
<li><a href="#Typemaps_nn13">Copying a typemap</a> <li><a href="#Typemaps_nn13">Copying a typemap</a>
<li><a href="#Typemaps_nn14">Deleting a typemap</a> <li><a href="#Typemaps_nn14">Deleting a typemap</a>
<li><a href="#Typemaps_nn15">Placement of typemaps</a> <li><a href="#Typemaps_nn15">Placement of typemaps</a>
</ul> </ul>
<li><a href="#Typemaps_nn16">Pattern matching rules</a> <li><a href="#Typemaps_pattern_matching">Pattern matching rules</a>
<ul> <ul>
<li><a href="#Typemaps_nn17">Basic matching rules</a> <li><a href="#Typemaps_nn17">Basic matching rules</a>
<li><a href="#Typemaps_nn18">Typedef reductions</a> <li><a href="#Typemaps_nn18">Typedef reductions</a>
@ -41,6 +41,11 @@
<li><a href="#Typemaps_nn22">Scope</a> <li><a href="#Typemaps_nn22">Scope</a>
<li><a href="#Typemaps_nn23">Declaring new local variables</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_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> </ul>
<li><a href="#Typemaps_nn25">Common typemap methods</a> <li><a href="#Typemaps_nn25">Common typemap methods</a>
<ul> <ul>
@ -69,7 +74,7 @@
<li><a href="#runtime_type_checker">The run-time type checker</a> <li><a href="#runtime_type_checker">The run-time type checker</a>
<ul> <ul>
<li><a href="#Typemaps_nn45">Implementation</a> <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> </ul>
<li><a href="#Typemaps_overloading">Typemaps and overloading</a> <li><a href="#Typemaps_overloading">Typemaps and overloading</a>
<li><a href="#Typemaps_nn48">More about <tt>%apply</tt> and <tt>%clear</tt></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. This section describes the behavior of the <tt>%typemap</tt> directive itself.
</p> </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> <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>. within a particular namespace. In this example, this is done using the class declaration <tt>class string</tt>.
</p> </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> <p>
@ -1646,6 +1651,7 @@ each type must have its own local variable declaration.
<p> <p>
Within all typemaps, the following special variables are expanded. 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> </p>
<center> <center>
@ -1892,6 +1898,86 @@ Another approach, which only works for arrays is to use the <tt>$1_basetype</tt>
</pre> </pre>
</div> </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> <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. structures are chained together in a circularly linked list.
</p> </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 <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> <p>
Occasionally, you might need to write a typemap that needs to convert Occasionally, you might need to write a typemap that needs to convert
pointers of other types. To handle this, a special macro substitution pointers of other types. To handle this, the special variable macro
<tt>$descriptor(type)</tt> can be used to generate the SWIG type <tt>$descriptor(type)</tt> covered earlier can be used to generate the SWIG type
descriptor name for any C datatype. For example: descriptor name for any C datatype. For example:
</p> </p>

View file

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

View file

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

View file

@ -25,7 +25,10 @@
"$csclassname.getCPtr(d$csinput)" "$csclassname.getCPtr(d$csinput)"
// post only in csin typemap // 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)" "$csclassname.getCPtr($csinput)"
%inline %{ %inline %{

View file

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

View file

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

View file

@ -0,0 +1,121 @@
%module special_variable_functions
// 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
#warning TODO!!!
//////////////////////////////////////////////////////////////////////////////////////
// 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

@ -2766,6 +2766,16 @@ public:
Delete(func_name); Delete(func_name);
} }
/*----------------------------------------------------------------------
* replaceSpecialVariables()
*--------------------------------------------------------------------*/
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
SwigType *type = Getattr(parm, "type");
substituteClassname(type, tm);
}
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
* decodeEnumFeature() * decodeEnumFeature()
* Decode the possible enum features, which are one of: * Decode the possible enum features, which are one of:
@ -2859,15 +2869,15 @@ public:
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* substituteClassname() * substituteClassname()
* *
* Substitute $csclassname with the proxy class name for classes/structs/unions that SWIG knows about. * Substitute the special variable $csclassname with the proxy class name for classes/structs/unions
* Also substitutes enums with enum name. * 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 * 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. * is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
* Inputs: * Inputs:
* pt - parameter type * pt - parameter type
* tm - cstype typemap * tm - typemap contents that might contain the special variable to be replaced
* Outputs: * Outputs:
* tm - cstype typemap with $csclassname substitution * tm - typemap contents complete with the special variable substitution
* Return: * Return:
* substitution_performed - flag indicating if a substitution was performed * substitution_performed - flag indicating if a substitution was performed
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */

View file

@ -2603,6 +2603,16 @@ public:
Delete(func_name); Delete(func_name);
} }
/*----------------------------------------------------------------------
* replaceSpecialVariables()
*--------------------------------------------------------------------*/
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
SwigType *type = Getattr(parm, "type");
substituteClassname(type, tm);
}
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
* decodeEnumFeature() * decodeEnumFeature()
* Decode the possible enum features, which are one of: * Decode the possible enum features, which are one of:
@ -2700,16 +2710,16 @@ public:
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* substituteClassname() * substituteClassname()
* *
* Substitute $javaclassname with the proxy class name for classes/structs/unions that SWIG knows about. * Substitute the special variable $javaclassname with the proxy class name for classes/structs/unions
* Also substitutes enums with enum name. * 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 * 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. * is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
* Inputs: * Inputs:
* pt - parameter type * 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 '.' * jnidescriptor - if set, inner class names are separated with '$' otherwise a '.'
* Outputs: * Outputs:
* tm - jstype typemap with $javaclassname substitution * tm - typemap contents complete with the special variable substitution
* Return: * Return:
* substitution_performed - flag indicating if a substitution was performed * substitution_performed - flag indicating if a substitution was performed
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */

View file

@ -18,6 +18,7 @@ static int director_mode = 0;
static int director_protected_mode = 1; static int director_protected_mode = 1;
static int all_protected_mode = 0; static int all_protected_mode = 0;
static int naturalvar_mode = 0; static int naturalvar_mode = 0;
Language* Language::this_ = 0;
/* Set director_protected_mode */ /* Set director_protected_mode */
void Wrapper_director_mode_set(int flag) { void Wrapper_director_mode_set(int flag) {
@ -46,6 +47,9 @@ extern "C" {
int Swig_all_protected_mode() { int Swig_all_protected_mode() {
return 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 */ /* Some status variables used during parsing */
@ -323,6 +327,8 @@ directors(0) {
director_prot_ctor_code = 0; director_prot_ctor_code = 0;
director_multiple_inheritance = 1; director_multiple_inheritance = 1;
director_language = 0; director_language = 0;
assert(!this_);
this_ = this;
} }
Language::~Language() { Language::~Language() {
@ -331,6 +337,7 @@ Language::~Language() {
Delete(enumtypes); Delete(enumtypes);
Delete(director_ctor_code); Delete(director_ctor_code);
Delete(none_comparison); Delete(none_comparison);
this_ = 0;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -3423,6 +3430,24 @@ String *Language::defaultExternalRuntimeFilename() {
return 0; 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 { Hash *Language::getClassHash() const {
return classhash; return classhash;
} }

View file

@ -3581,17 +3581,28 @@ MODULA3():
Delete(throws_hash); Delete(throws_hash);
} }
/*----------------------------------------------------------------------
* replaceSpecialVariables()
*--------------------------------------------------------------------*/
virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) {
(void)method;
SwigType *type = Getattr(parm, "type");
substituteClassname(type, tm);
}
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* substituteClassname() * 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 * 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. * is the same as a $&descriptor substitution, ie one pointer added to descriptor name.
* Inputs: * Inputs:
* pt - parameter type * pt - parameter type
* tm - m3wraptype typemap * tm - typemap contents that might contain the special variable to be replaced
* Outputs: * Outputs:
* tm - m3wraptype typemap with $m3classname substitution * tm - typemap contents complete with the special variable substitution
* Return: * Return:
* substitution_performed - flag indicating if a substitution was performed * substitution_performed - flag indicating if a substitution was performed
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */

View file

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

View file

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

View file

@ -390,6 +390,7 @@ extern int ParmList_is_compactdefargs(ParmList *p);
extern void Wrapper_director_mode_set(int); extern void Wrapper_director_mode_set(int);
extern void Wrapper_director_protected_mode_set(int); extern void Wrapper_director_protected_mode_set(int);
extern void Wrapper_all_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 -- */ /* -- template init -- */

View file

@ -17,7 +17,7 @@ char cvsroot_typemap_c[] = "$Id$";
#define SWIG_DEBUG #define SWIG_DEBUG
#endif #endif
static void replace_embedded_typemap(String *s); static void replace_embedded_typemap(String *s, String *lname, Wrapper *f);
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Typemaps are stored in a collection of nested hash tables. Something like * 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 * different typemap methods. These are referenced by names such as
* "tmap:in", "tmap:out", "tmap:argout", and so forth. * "tmap:in", "tmap:out", "tmap:argout", and so forth.
* *
* The object corresponding to a specific method has the following * The object corresponding to a specific typemap method has the following attributes:
* attributes:
* *
* "type" - Typemap type * "type" - Typemap type
* "pname" - Parameter name * "pname" - Parameter name
* "code" - Typemap code * "code" - Typemap code
* "typemap" - Descriptive text describing the actual map * "typemap" - Descriptive text describing the actual map
* "locals" - Local variables (if any) * "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
* *
* ----------------------------------------------------------------------------- */ * ----------------------------------------------------------------------------- */
@ -163,7 +173,7 @@ Hash *Swig_typemap_pop_scope() {
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Swig_typemap_register() * 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 op, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs) {
@ -210,7 +220,7 @@ void Swig_typemap_register(const_String_or_char_ptr op, ParmList *parms, const_S
Delete(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 is really only stored in the last argument. However, to
make this work, we perform a really neat trick using make this work, we perform a really neat trick using
the typemap operator name. the typemap operator name.
@ -346,7 +356,7 @@ int Swig_typemap_copy(const_String_or_char_ptr op, ParmList *srcparms, ParmList
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Swig_typemap_clear() * 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 op, ParmList *parms) {
@ -735,7 +745,7 @@ ret_result:
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* typemap_search_multi() * 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 op, ParmList *parms, int *nmatch) {
@ -806,7 +816,7 @@ static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, Swi
SwigType *ftype; SwigType *ftype;
int bare_substitution_count = 0; int bare_substitution_count = 0;
Replaceall(s, "$typemap", "$TYPEMAP"); Replaceall(s, "$typemap", "$TYPEMAP"); /* workaround for $type substitution below */
ftype = SwigType_typedef_resolve_all(type); ftype = SwigType_typedef_resolve_all(type);
@ -1162,8 +1172,18 @@ 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 * Attach one or more typemaps to a node and optionally generate the typemap contents
* into the wrapper. * into the wrapper.
* op - typemap name, eg "out", "newfree" *
* node - the node to attach the typemaps to * 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 op="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").
*
* op - 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 * lname - name of variable to substitute $1, $2 etc for
* f - wrapper code to generate into if non null * f - wrapper code to generate into if non null
* actioncode - code to generate into f before the out typemap code, unless * actioncode - code to generate into f before the out typemap code, unless
@ -1242,10 +1262,10 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
kw = Getattr(tm, "kwargs"); kw = Getattr(tm, "kwargs");
while (kw) { while (kw) {
String *value = Copy(Getattr(kw, "value")); String *value = Copy(Getattr(kw, "value"));
String *type = Getattr(kw, "type"); String *kwtype = Getattr(kw, "type");
char *ckwname = Char(Getattr(kw, "name")); char *ckwname = Char(Getattr(kw, "name"));
if (type) { if (kwtype) {
String *mangle = Swig_string_mangle(type); String *mangle = Swig_string_mangle(kwtype);
Append(value, mangle); Append(value, mangle);
Delete(mangle); Delete(mangle);
} }
@ -1324,7 +1344,7 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
if (locals && f) { if (locals && f) {
typemap_locals(s, locals, f, -1); typemap_locals(s, locals, f, -1);
} }
replace_embedded_typemap(s); replace_embedded_typemap(s, NewString(lname), f);
Replace(s, "$name", pname, DOH_REPLACE_ANY); Replace(s, "$name", pname, DOH_REPLACE_ANY);
@ -1357,11 +1377,11 @@ static String *Swig_typemap_lookup_impl(const_String_or_char_ptr op, Node *node,
/* Look for code fragments */ /* Look for code fragments */
{ {
String *f; String *fragment;
sprintf(temp, "%s:fragment", cop); sprintf(temp, "%s:fragment", cop);
f = Getattr(node, tmop_name(temp)); fragment = Getattr(node, tmop_name(temp));
if (f) { if (fragment) {
String *fname = Copy(f); String *fname = Copy(fragment);
Setfile(fname, Getfile(node)); Setfile(fname, Getfile(node));
Setline(fname, Getline(node)); Setline(fname, Getline(node));
Swig_fragment_emit(fname); Swig_fragment_emit(fname);
@ -1457,13 +1477,6 @@ static void typemap_emit_code_fragments(const_String_or_char_ptr op, Parm *p) {
Delete(temp); 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) { static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) {
Parm *kw = Getattr(tm, "kwargs"); Parm *kw = Getattr(tm, "kwargs");
while (kw) { while (kw) {
@ -1476,6 +1489,22 @@ static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) {
return 0; return 0;
} }
/* -----------------------------------------------------------------------------
* 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 op="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").
*
* op - 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 op, ParmList *parms, Wrapper *f) { void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wrapper *f) {
Parm *p, *firstp; Parm *p, *firstp;
Hash *tm; Hash *tm;
@ -1614,7 +1643,7 @@ void Swig_typemap_attach_parms(const_String_or_char_ptr op, ParmList *parms, Wra
typemap_locals(s, locals, f, argnum); typemap_locals(s, locals, f, argnum);
} }
replace_embedded_typemap(s); replace_embedded_typemap(s, Getattr(firstp, "lname"), f);
/* Replace the argument number */ /* Replace the argument number */
sprintf(temp, "%d", argnum); sprintf(temp, "%d", argnum);
@ -1659,23 +1688,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 */ /* Splits the arguments of an embedded typemap */
static List *split_embedded(String *s) { static List *split_embedded_typemap(String *s) {
List *args = 0; List *args = 0;
char *c, *start; char *c, *start;
int level = 0; int level = 0;
@ -1683,6 +1697,7 @@ static List *split_embedded(String *s) {
args = NewList(); args = NewList();
c = strchr(Char(s), '('); c = strchr(Char(s), '(');
assert(c);
c++; c++;
start = c; start = c;
@ -1723,41 +1738,36 @@ static List *split_embedded(String *s) {
return args; return args;
} }
static void split_var(String *s, String **name, String **value) { /* -----------------------------------------------------------------------------
char *eq; * replace_embedded_typemap()
char *c; *
* 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), '='); static void replace_embedded_typemap(String *s, String *lname, Wrapper *f) {
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) {
char *start = 0; 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; char *end = 0, *c;
int level = 0; int level = 0;
String *tmp; String *dollar_typemap;
int syntax_error = 1;
c = start; c = start;
while (*c) { while (*c) {
if (*c == '(') if (*c == '(')
@ -1772,103 +1782,119 @@ static void replace_embedded_typemap(String *s) {
c++; c++;
} }
if (end) { if (end) {
tmp = NewStringWithSize(start, (end - start)); dollar_typemap = NewStringWithSize(start, (end - start));
syntax_error = 0;
} else { } else {
tmp = 0; dollar_typemap = NewStringWithSize(start, (c - start));
} }
/* Got a substitution. Split it apart into pieces */ if (!syntax_error) {
if (tmp) {
List *l; List *l;
String *op;
Hash *vars; Hash *vars;
String *method; syntax_error = 1;
int i, ilen;
l = split_embedded(tmp); /* Split apart each parameter in $typemap(...) */
vars = NewHash(); l = split_embedded_typemap(dollar_typemap);
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);
}
method = Getitem(l, 0); if (Len(l) >= 2) {
/* Generate the parameter list for matching typemaps */ ParmList *to_match_parms;
op = Getitem(l, 0);
{ /* the second parameter might contain multiple sub-parameters for multi-argument
Parm *p = 0; * typemap matching, so split these parameters apart */
Parm *first = 0; to_match_parms = Swig_cparse_parms(Getitem(l, 1));
char temp[32]; if (to_match_parms) {
int n = 1; Parm *p = to_match_parms;;
while (1) { while (p) {
Hash *v; Setattr(p, "lname", lname);
sprintf(temp, "$%d", n); p = nextSibling(p);
v = Getattr(vars, temp);
if (v) {
if (p) {
set_nextSibling(p, v);
set_previousSibling(v, 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;
} }
n++;
} }
/* 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 */ /* 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 #ifdef SWIG_DEBUG
Printf(stdout, "Swig_typemap_attach_parms: embedded\n"); Printf(stdout, "Swig_typemap_attach_parms: embedded\n");
#endif #endif
Swig_typemap_attach_parms(method, first, 0); if (!already_substituting) {
{ already_substituting = 1;
String *tm; Swig_typemap_attach_parms(op, to_match_parms, f);
int match = 0; already_substituting = 0;
char attr[64];
sprintf(attr, "tmap:%s", Char(method));
/* Look for the typemap code */ /* Look for the typemap code */
tm = Getattr(first, attr); attr = NewStringf("tmap:%s", op);
tm = Getattr(to_match_parms, attr);
if (tm) { if (tm) {
sprintf(attr, "tmap:%s:next", Char(method)); Printf(attr, "%s", ":next");
if (!Getattr(first, attr)) { /* fail if multi-argument lookup requested in $typemap(...) and the lookup failed */
/* Should be no more matches. Hack??? */ if (!Getattr(to_match_parms, attr)) {
/* Replace all of the remaining variables */ /* Replace parameter variables */
Iterator ki; Iterator ki;
for (ki = First(vars); ki.key; ki = Next(ki)) { for (ki = First(vars); ki.key; ki = Next(ki)) {
Replace(tm, ki.key, ki.item, DOH_REPLACE_ANY); Replace(tm, ki.key, ki.item, DOH_REPLACE_ANY);
} }
/* Do the replacement */ /* offer the target language module the chance to make special variable substitutions */
Replace(s, tmp, tm, DOH_REPLACE_ANY); Language_replace_special_variables(op, tm, to_match_parms);
/* finish up - do the substitution */
Replace(s, dollar_typemap, tm, DOH_REPLACE_ANY);
Delete(tm); Delete(tm);
match = 1; match = 1;
} }
} }
if (!match) { 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); 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);
} }
} }