@@ -988,7 +993,7 @@ It should be noted that for scoping to work, SWIG has to know that stringclass string.
-
@@ -1646,6 +1651,7 @@ each type must have its own local variable declaration.
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.
@@ -1892,6 +1898,86 @@ Another approach, which only works for arrays is to use the $1_basetype
+10.4.4 Special variable macros
+
+
+
+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 $ 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.
+
+
+10.4.4.1 $descriptor(type)
+
+
+
+This macro expands into the type descriptor structure for any C/C++ type specified in type.
+It behaves like the $1_descriptor 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, $descriptor(std::vector<int> *) will expand into SWIGTYPE_p_std__vectorT_int_t.
+This macro is mostly used in the scripting target languages and is demonstrated later in the Run-time type checker usage section.
+
+
+10.4.4.2 $typemap(method, typepattern)
+
+
+
+This macro uses the pattern matching rules 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 method is the typemap method name and
+typepattern is a type pattern as per the %typemap specification in the Defining a typemap section.
+
+
+
+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.
+
+
+
+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.
+
+
+
+
+%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
+ }
+%}
+
+
+
+
+The result is the following expansion
+
+
+
+
+%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
+ }
+%}
+
+
+
10.5 Common typemap methods
@@ -3295,7 +3381,7 @@ structures rather than creating new ones. These swig_module_info
structures are chained together in a circularly linked list.
-10.10.2 Usage
+10.10.2 Usage
This section covers how to use these functions from typemaps. To learn how to
@@ -3335,8 +3421,8 @@ type tables and improves efficiency.
Occasionally, you might need to write a typemap that needs to convert
-pointers of other types. To handle this, a special macro substitution
-$descriptor(type) can be used to generate the SWIG type
+pointers of other types. To handle this, the special variable macro
+$descriptor(type) covered earlier can be used to generate the SWIG type
descriptor name for any C datatype. For example:
diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk
index ec52f29e3..96c7526b8 100644
--- a/Examples/test-suite/common.mk
+++ b/Examples/test-suite/common.mk
@@ -292,6 +292,7 @@ CPP_TEST_CASES += \
smart_pointer_templatevariables \
smart_pointer_typedef \
special_variables \
+ special_variable_functions \
static_array_member \
static_const_member \
static_const_member_2 \
diff --git a/Examples/test-suite/csharp/special_variable_functions_runme.cs b/Examples/test-suite/csharp/special_variable_functions_runme.cs
new file mode 100644
index 000000000..02d4995d2
--- /dev/null
+++ b/Examples/test-suite/csharp/special_variable_functions_runme.cs
@@ -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();
+ }
+}
diff --git a/Examples/test-suite/csharp_prepost.i b/Examples/test-suite/csharp_prepost.i
index 0c35c1833..817f5b9b9 100644
--- a/Examples/test-suite/csharp_prepost.i
+++ b/Examples/test-suite/csharp_prepost.i
@@ -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 &vpost
+%typemap(csin, post=" int size = $csinput.Count;\n"
+ " for (int i=0; i &vpost
"$csclassname.getCPtr($csinput)"
%inline %{
diff --git a/Examples/test-suite/java/special_variable_functions_runme.java b/Examples/test-suite/java/special_variable_functions_runme.java
new file mode 100644
index 000000000..b4d259932
--- /dev/null
+++ b/Examples/test-suite/java/special_variable_functions_runme.java
@@ -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();
+ }
+}
diff --git a/Examples/test-suite/python/special_variable_functions_runme.py b/Examples/test-suite/python/special_variable_functions_runme.py
new file mode 100644
index 000000000..9473880b8
--- /dev/null
+++ b/Examples/test-suite/python/special_variable_functions_runme.py
@@ -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"
+
diff --git a/Examples/test-suite/special_variable_functions.i b/Examples/test-suite/special_variable_functions.i
new file mode 100644
index 000000000..b0c39d73c
--- /dev/null
+++ b/Examples/test-suite/special_variable_functions.i
@@ -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;
+ };
+}
+%}
+
diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx
index 9154f959a..cb7bb67a0 100644
--- a/Source/Modules/csharp.cxx
+++ b/Source/Modules/csharp.cxx
@@ -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
* ----------------------------------------------------------------------------- */
diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx
index ea24f34d1..ab84df3f7 100644
--- a/Source/Modules/java.cxx
+++ b/Source/Modules/java.cxx
@@ -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
* ----------------------------------------------------------------------------- */
diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx
index 38658ce9c..36bbf5e9f 100644
--- a/Source/Modules/lang.cxx
+++ b/Source/Modules/lang.cxx
@@ -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;
}
/* ----------------------------------------------------------------------
@@ -3423,6 +3430,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;
}
diff --git a/Source/Modules/modula3.cxx b/Source/Modules/modula3.cxx
index 5445d0761..be2765bc1 100644
--- a/Source/Modules/modula3.cxx
+++ b/Source/Modules/modula3.cxx
@@ -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
* ----------------------------------------------------------------------------- */
diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h
index 8dec8d0af..440e0e960 100644
--- a/Source/Modules/swigmod.h
+++ b/Source/Modules/swigmod.h
@@ -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 */
diff --git a/Source/Swig/scanner.c b/Source/Swig/scanner.c
index 53f1ad4a0..3de794fdc 100644
--- a/Source/Swig/scanner.c
+++ b/Source/Swig/scanner.c
@@ -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;
diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h
index 68e7d3a10..86b956399 100644
--- a/Source/Swig/swig.h
+++ b/Source/Swig/swig.h
@@ -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 -- */
diff --git a/Source/Swig/typemap.c b/Source/Swig/typemap.c
index fd4e42579..3e1ffda49 100644
--- a/Source/Swig/typemap.c
+++ b/Source/Swig/typemap.c
@@ -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, String *lname, 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
*
* ----------------------------------------------------------------------------- */
@@ -163,7 +173,7 @@ 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) {
@@ -210,7 +220,7 @@ void Swig_typemap_register(const_String_or_char_ptr op, ParmList *parms, const_S
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.
@@ -346,7 +356,7 @@ 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) {
@@ -735,7 +745,7 @@ 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) {
@@ -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,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
* 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
* f - wrapper code to generate into if non null
* 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");
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);
}
@@ -1324,7 +1344,7 @@ 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);
+ replace_embedded_typemap(s, NewString(lname), f);
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 */
{
- String *f;
+ String *fragment;
sprintf(temp, "%s:fragment", cop);
- f = Getattr(node, tmop_name(temp));
- if (f) {
- String *fname = Copy(f);
+ fragment = Getattr(node, tmop_name(temp));
+ if (fragment) {
+ String *fname = Copy(fragment);
Setfile(fname, Getfile(node));
Setline(fname, Getline(node));
Swig_fragment_emit(fname);
@@ -1457,13 +1477,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,6 +1489,22 @@ static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) {
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) {
Parm *p, *firstp;
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);
}
- replace_embedded_typemap(s);
+ replace_embedded_typemap(s, Getattr(firstp, "lname"), f);
/* Replace the argument number */
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 */
-static List *split_embedded(String *s) {
+static List *split_embedded_typemap(String *s) {
List *args = 0;
char *c, *start;
int level = 0;
@@ -1683,6 +1697,7 @@ static List *split_embedded(String *s) {
args = NewList();
c = strchr(Char(s), '(');
+ assert(c);
c++;
start = c;
@@ -1723,41 +1738,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 a, int b)) # multi-argument typemap matching %typemap(in) (Foo 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, String *lname, 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 +1782,119 @@ 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 *op;
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;
+ op = 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);
- }
- 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;
+ /* 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;;
+ while (p) {
+ Setattr(p, "lname", lname);
+ p = nextSibling(p);
}
- 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 */
- 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(op, to_match_parms, f);
+ already_substituting = 0;
/* Look for the typemap code */
- tm = Getattr(first, attr);
+ attr = NewStringf("tmap:%s", op);
+ 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(op, 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, "", 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, "", DOH_REPLACE_ANY);
+ Delete(dollar_typemap);
}
}