mirror of https://github.com/swig/swig
2228 lines
68 KiB
C
2228 lines
68 KiB
C
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at https://www.swig.org/legal.html.
|
|
*
|
|
* typemap.c
|
|
*
|
|
* A somewhat generalized implementation of SWIG1.1 typemaps.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "swig.h"
|
|
#include "cparse.h"
|
|
#include <ctype.h>
|
|
|
|
#if 0
|
|
#define SWIG_DEBUG
|
|
#endif
|
|
|
|
static int typemap_search_debug = 0;
|
|
static int typemaps_used_debug = 0;
|
|
static int typemap_register_debug = 0;
|
|
static int in_typemap_search_multi = 0;
|
|
|
|
static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f, Node *file_line_node);
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Typemaps are stored in a collection of nested hash tables. Something like
|
|
* this:
|
|
*
|
|
* [ type ]
|
|
* +-------- [ name ]
|
|
* +-------- [ name ]
|
|
*
|
|
* Each hash table [ type ] or [ name ] then contains references to the
|
|
* 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 typemap method has the following attributes:
|
|
*
|
|
* "type" - Typemap type
|
|
* "pname" - Parameter name
|
|
* "code" - Typemap code
|
|
* "source" - Source directive (%apply or %typemap) for the typemap
|
|
* "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;
|
|
* "source" - typemap(in) int &my_int
|
|
* "locals" - int tmp
|
|
* "kwargs" - warning="987:my typemap warning", foo=123
|
|
*
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *typemaps;
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_identifier_fix()
|
|
*
|
|
* Create a type that can be used as a hash key lookup independent of the various
|
|
* ways a template parameter list can be defined. This is achieved by fully
|
|
* resolving the template parameters.
|
|
*
|
|
* This is a copy and modification of feature_identifier_fix in parser.y.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static SwigType *typemap_identifier_fix(const SwigType *s) {
|
|
String *tp = SwigType_istemplate_templateprefix(s);
|
|
if (tp) {
|
|
String *ts, *ta, *tq, *tr;
|
|
ts = SwigType_templatesuffix(s);
|
|
ta = SwigType_templateargs(s);
|
|
tq = Swig_symbol_type_qualify(ta, 0);
|
|
tr = SwigType_typedef_resolve_all(ta);
|
|
Append(tp,tr);
|
|
Append(tp,ts);
|
|
Delete(ts);
|
|
Delete(ta);
|
|
Delete(tq);
|
|
Delete(tr);
|
|
return tp;
|
|
} else {
|
|
return NewString(s);
|
|
}
|
|
}
|
|
|
|
static Hash *get_typemap(const SwigType *type) {
|
|
Hash *tm = 0;
|
|
SwigType *dtype = 0;
|
|
SwigType *hashtype;
|
|
|
|
if (SwigType_istemplate(type)) {
|
|
SwigType *rty = typemap_identifier_fix(type);
|
|
String *ty = Swig_symbol_template_deftype(rty, 0);
|
|
dtype = Swig_symbol_type_qualify(ty, 0);
|
|
type = dtype;
|
|
Delete(ty);
|
|
Delete(rty);
|
|
}
|
|
|
|
/* remove unary scope operator (::) prefix indicating global scope for looking up in the hashmap */
|
|
hashtype = SwigType_remove_global_scope_prefix(type);
|
|
tm = Getattr(typemaps, hashtype);
|
|
|
|
Delete(dtype);
|
|
Delete(hashtype);
|
|
|
|
return tm;
|
|
}
|
|
|
|
static void set_typemap(const SwigType *type, Hash **tmhash) {
|
|
SwigType *hashtype = 0;
|
|
Hash *new_tm = 0;
|
|
assert(*tmhash == 0);
|
|
if (SwigType_istemplate(type)) {
|
|
SwigType *rty = typemap_identifier_fix(type);
|
|
String *ty = Swig_symbol_template_deftype(rty, 0);
|
|
String *tyq = Swig_symbol_type_qualify(ty, 0);
|
|
hashtype = SwigType_remove_global_scope_prefix(tyq);
|
|
*tmhash = Getattr(typemaps, hashtype);
|
|
Delete(rty);
|
|
Delete(tyq);
|
|
Delete(ty);
|
|
} else {
|
|
hashtype = SwigType_remove_global_scope_prefix(type);
|
|
}
|
|
|
|
if (!*tmhash) {
|
|
/* this type has not been seen before even after resolving template parameter types */
|
|
new_tm = NewHash();
|
|
*tmhash = new_tm;
|
|
}
|
|
|
|
/* note that the unary scope operator (::) prefix indicating global scope has been removed from the type */
|
|
Setattr(typemaps, hashtype, *tmhash);
|
|
|
|
Delete(hashtype);
|
|
Delete(new_tm);
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_init()
|
|
*
|
|
* Initialize the typemap system
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_init(void) {
|
|
typemaps = NewHash();
|
|
}
|
|
|
|
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 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 *method_without_object_identity = Char(tmap_method);
|
|
if (!names)
|
|
names = NewHash();
|
|
s = Getattr(names, method_without_object_identity);
|
|
if (s)
|
|
return s;
|
|
s = NewStringf("tmap:%s", tmap_method);
|
|
Setattr(names, method_without_object_identity, s);
|
|
Delete(s);
|
|
return s;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_register()
|
|
*
|
|
* Internal implementation for Swig_typemap_register()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void typemap_register(const_String_or_char_ptr tmap_method, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs, String *source_directive) {
|
|
Hash *tm;
|
|
Hash *tm1;
|
|
Hash *tm2;
|
|
Parm *np;
|
|
String *tm_method;
|
|
SwigType *type;
|
|
String *pname;
|
|
if (!parms)
|
|
return;
|
|
|
|
if (typemap_register_debug) {
|
|
Printf(stdout, "Registering - %s\n", tmap_method);
|
|
Swig_print_node(parms);
|
|
}
|
|
|
|
tm_method = typemap_method_name(tmap_method);
|
|
|
|
/* Register the first type in the parameter list */
|
|
|
|
type = Getattr(parms, "type");
|
|
pname = Getattr(parms, "name");
|
|
|
|
/* See if this type has been seen before */
|
|
tm = get_typemap(type);
|
|
if (!tm) {
|
|
set_typemap(type, &tm);
|
|
}
|
|
if (pname) {
|
|
/* See if parameter has been seen before */
|
|
tm1 = Getattr(tm, pname);
|
|
if (!tm1) {
|
|
tm1 = NewHash();
|
|
Setattr(tm, pname, tm1);
|
|
Delete(tm1);
|
|
}
|
|
tm = tm1;
|
|
}
|
|
|
|
/* Now see if this typemap method has been seen before */
|
|
tm2 = Getattr(tm, tm_method);
|
|
if (!tm2) {
|
|
tm2 = NewHash();
|
|
Setattr(tm, tm_method, tm2);
|
|
Delete(tm2);
|
|
}
|
|
|
|
/* 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 method name.
|
|
|
|
For example, consider this typemap
|
|
|
|
%typemap(in) (int foo, int *bar, char *blah[]) {
|
|
...
|
|
}
|
|
|
|
To store it, we look at typemaps for the following:
|
|
|
|
typemap method type-name
|
|
----------------------------------------------
|
|
"in" int foo
|
|
"in-int+foo:" int *bar
|
|
"in-int+foo:-p.int+bar: char *blah[]
|
|
|
|
Notice how the typemap method name expands to encode information about
|
|
previous arguments.
|
|
|
|
*/
|
|
|
|
np = nextSibling(parms);
|
|
if (np) {
|
|
/* Make an entirely new typemap method key */
|
|
String *multi_tmap_method = NewStringf("%s-%s+%s:", tmap_method, type, pname);
|
|
|
|
/* Now reregister on the remaining arguments */
|
|
typemap_register(multi_tmap_method, np, code, locals, kwargs, source_directive);
|
|
|
|
Delete(multi_tmap_method);
|
|
} else {
|
|
ParmList *clocals = CopyParmList(locals);
|
|
ParmList *ckwargs = CopyParmList(kwargs);
|
|
|
|
Setfile(tm2, Getfile(code));
|
|
Setline(tm2, Getline(code));
|
|
Setattr(tm2, "code", code);
|
|
Setattr(tm2, "type", type);
|
|
Setattr(tm2, "source", source_directive);
|
|
if (pname) {
|
|
Setattr(tm2, "pname", pname);
|
|
}
|
|
Setattr(tm2, "locals", clocals);
|
|
Setattr(tm2, "kwargs", ckwargs);
|
|
|
|
Delete(clocals);
|
|
Delete(ckwargs);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_register()
|
|
*
|
|
* Add a new, possibly multi-argument, typemap
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs) {
|
|
String *parms_str = ParmList_str_multibrackets(parms);
|
|
String *source_directive = NewStringf("typemap(%s) %s", tmap_method, parms_str);
|
|
|
|
typemap_register(tmap_method, parms, code, locals, kwargs, source_directive);
|
|
|
|
Delete(source_directive);
|
|
Delete(parms_str);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_get()
|
|
*
|
|
* Retrieve typemap information.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *typemap_get(SwigType *type, const_String_or_char_ptr name) {
|
|
Hash *tm, *tm1;
|
|
tm = get_typemap(type);
|
|
if (!tm) {
|
|
return 0;
|
|
}
|
|
if ((name) && Len(name)) {
|
|
tm1 = Getattr(tm, name);
|
|
return tm1;
|
|
}
|
|
return tm;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_copy()
|
|
*
|
|
* Copy a typemap
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcparms, ParmList *parms) {
|
|
Hash *tm = 0;
|
|
String *tm_method;
|
|
Parm *p;
|
|
String *pname;
|
|
SwigType *ptype;
|
|
String *tm_methods, *multi_tmap_method;
|
|
if (ParmList_len(parms) != ParmList_len(srcparms))
|
|
return -1;
|
|
|
|
tm_method = typemap_method_name(tmap_method);
|
|
p = srcparms;
|
|
tm_methods = NewString(tm_method);
|
|
while (p) {
|
|
ptype = Getattr(p, "type");
|
|
pname = Getattr(p, "name");
|
|
|
|
/* Lookup the type */
|
|
tm = typemap_get(ptype, pname);
|
|
if (!tm)
|
|
break;
|
|
|
|
tm = Getattr(tm, tm_methods);
|
|
if (!tm)
|
|
break;
|
|
|
|
/* Got a match. Look for next typemap */
|
|
multi_tmap_method = NewStringf("%s-%s+%s:", tm_methods, ptype, pname);
|
|
Delete(tm_methods);
|
|
tm_methods = multi_tmap_method;
|
|
p = nextSibling(p);
|
|
}
|
|
Delete(tm_methods);
|
|
|
|
if (!p && tm) {
|
|
/* Got some kind of match */
|
|
String *parms_str = ParmList_str_multibrackets(parms);
|
|
String *srcparms_str = ParmList_str_multibrackets(srcparms);
|
|
String *source_directive = NewStringf("typemap(%s) %s = %s", tmap_method, parms_str, srcparms_str);
|
|
|
|
typemap_register(tmap_method, parms, Getattr(tm, "code"), Getattr(tm, "locals"), Getattr(tm, "kwargs"), source_directive);
|
|
|
|
Delete(source_directive);
|
|
Delete(srcparms_str);
|
|
Delete(parms_str);
|
|
return 0;
|
|
}
|
|
|
|
/* Not found */
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_clear()
|
|
*
|
|
* Delete a multi-argument typemap
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *parms) {
|
|
SwigType *type;
|
|
String *name;
|
|
Parm *p;
|
|
String *multi_tmap_method;
|
|
Hash *tm = 0;
|
|
|
|
/* This might not work */
|
|
multi_tmap_method = NewString(tmap_method);
|
|
p = parms;
|
|
while (p) {
|
|
type = Getattr(p, "type");
|
|
name = Getattr(p, "name");
|
|
tm = typemap_get(type, name);
|
|
if (!tm)
|
|
return;
|
|
p = nextSibling(p);
|
|
if (p)
|
|
Printf(multi_tmap_method, "-%s+%s:", type, name);
|
|
}
|
|
if (tm) {
|
|
tm = Getattr(tm, typemap_method_name(multi_tmap_method));
|
|
if (tm) {
|
|
Delattr(tm, "code");
|
|
Delattr(tm, "locals");
|
|
Delattr(tm, "kwargs");
|
|
}
|
|
}
|
|
Delete(multi_tmap_method);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_apply()
|
|
*
|
|
* Multi-argument %apply directive. This is pretty horrible so I sure hope
|
|
* it works.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int count_args(String *s) {
|
|
/* Count up number of arguments */
|
|
int na = 0;
|
|
char *c = Char(s);
|
|
while (*c) {
|
|
if (*c == '+')
|
|
na++;
|
|
c++;
|
|
}
|
|
return na;
|
|
}
|
|
|
|
int Swig_typemap_apply(ParmList *src, ParmList *dest) {
|
|
String *ssig, *dsig;
|
|
Parm *p, *np, *lastp, *dp, *lastdp = 0;
|
|
int narg = 0;
|
|
SwigType *type = 0, *name;
|
|
Hash *tm, *sm;
|
|
int match = 0;
|
|
|
|
/* Printf(stdout,"apply : %s --> %s\n", ParmList_str(src), ParmList_str(dest)); */
|
|
|
|
/* Create type signature of source */
|
|
ssig = NewStringEmpty();
|
|
dsig = NewStringEmpty();
|
|
p = src;
|
|
dp = dest;
|
|
lastp = 0;
|
|
while (p) {
|
|
lastp = p;
|
|
lastdp = dp;
|
|
np = nextSibling(p);
|
|
if (np) {
|
|
Printf(ssig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name"));
|
|
Printf(dsig, "-%s+%s:", Getattr(dp, "type"), Getattr(dp, "name"));
|
|
narg++;
|
|
}
|
|
p = np;
|
|
dp = nextSibling(dp);
|
|
}
|
|
|
|
/* make sure a typemap node exists for the last destination node */
|
|
type = Getattr(lastdp, "type");
|
|
tm = get_typemap(type);
|
|
if (!tm) {
|
|
set_typemap(type, &tm);
|
|
}
|
|
name = Getattr(lastdp, "name");
|
|
if (name) {
|
|
Hash *tm1 = Getattr(tm, name);
|
|
if (!tm1) {
|
|
tm1 = NewHash();
|
|
Setattr(tm, NewString(name), tm1);
|
|
Delete(tm1);
|
|
}
|
|
tm = tm1;
|
|
}
|
|
|
|
/* This is a little nasty. We need to go searching for all possible typemaps in the
|
|
source and apply them to the target */
|
|
|
|
type = Getattr(lastp, "type");
|
|
name = Getattr(lastp, "name");
|
|
|
|
/* See if there is a matching typemap in this scope */
|
|
sm = typemap_get(type, name);
|
|
|
|
/* if there is not matching, look for a typemap in the
|
|
original typedef, if any, like in:
|
|
|
|
typedef unsigned long size_t;
|
|
...
|
|
%apply(size_t) {my_size}; ==> %apply(unsigned long) {my_size};
|
|
*/
|
|
if (!sm) {
|
|
SwigType *ntype = SwigType_typedef_resolve(type);
|
|
if (ntype && (Cmp(ntype, type) != 0)) {
|
|
sm = typemap_get(ntype, name);
|
|
}
|
|
Delete(ntype);
|
|
}
|
|
|
|
if (sm) {
|
|
/* Got a typemap. Need to only merge attributes for methods that match our signature */
|
|
Iterator ki;
|
|
Hash *deferred_add;
|
|
match = 1;
|
|
|
|
/* Since typemap_register can modify the `sm` hash, we *cannot* call typemap_register while iterating over sm.
|
|
* Create a temporary hash of typemaps to add immediately after. */
|
|
deferred_add = NewHash();
|
|
for (ki = First(sm); ki.key; ki = Next(ki)) {
|
|
/* Check for a signature match with the source signature */
|
|
if ((count_args(ki.key) == narg) && (Strstr(ki.key, ssig))) {
|
|
String *oldm;
|
|
/* A typemap we have to copy */
|
|
String *nkey = Copy(ki.key);
|
|
Replace(nkey, ssig, dsig, DOH_REPLACE_ANY);
|
|
|
|
/* Make sure the typemap doesn't already exist in the target map */
|
|
oldm = Getattr(tm, nkey);
|
|
if (!oldm || (!Getattr(tm, "code"))) {
|
|
String *code;
|
|
Hash *sm1 = ki.item;
|
|
|
|
code = Getattr(sm1, "code");
|
|
if (code) {
|
|
Replace(nkey, dsig, "", DOH_REPLACE_ANY);
|
|
Replace(nkey, "tmap:", "", DOH_REPLACE_ANY);
|
|
Setattr(deferred_add, nkey, sm1);
|
|
}
|
|
}
|
|
Delete(nkey);
|
|
}
|
|
}
|
|
|
|
/* After assembling the key/item pairs, add the resulting typemaps */
|
|
for (ki = First(deferred_add); ki.key; ki = Next(ki)) {
|
|
Hash *sm1 = ki.item;
|
|
String *src_str = ParmList_str_multibrackets(src);
|
|
String *dest_str = ParmList_str_multibrackets(dest);
|
|
String *source_directive = NewStringf("apply %s { %s }", src_str, dest_str);
|
|
|
|
typemap_register(ki.key, dest, Getattr(sm1, "code"), Getattr(sm1, "locals"), Getattr(sm1, "kwargs"), source_directive);
|
|
|
|
Delete(source_directive);
|
|
Delete(dest_str);
|
|
Delete(src_str);
|
|
}
|
|
Delete(deferred_add);
|
|
}
|
|
Delete(ssig);
|
|
Delete(dsig);
|
|
return match;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_clear_apply()
|
|
*
|
|
* %clear directive. Clears all typemaps for a type (in the current scope only).
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
/* Multi-argument %clear directive */
|
|
void Swig_typemap_clear_apply(Parm *parms) {
|
|
String *tsig;
|
|
Parm *p, *np, *lastp;
|
|
int narg = 0;
|
|
Hash *tm;
|
|
String *name;
|
|
|
|
/* Create a type signature of the parameters */
|
|
tsig = NewStringEmpty();
|
|
p = parms;
|
|
lastp = 0;
|
|
while (p) {
|
|
lastp = p;
|
|
np = nextSibling(p);
|
|
if (np) {
|
|
Printf(tsig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name"));
|
|
narg++;
|
|
}
|
|
p = np;
|
|
}
|
|
tm = get_typemap(Getattr(lastp, "type"));
|
|
if (!tm) {
|
|
Delete(tsig);
|
|
return;
|
|
}
|
|
name = Getattr(lastp, "name");
|
|
if (name) {
|
|
tm = Getattr(tm, name);
|
|
}
|
|
if (tm) {
|
|
/* Clear typemaps that match our signature */
|
|
Iterator ki, ki2;
|
|
char *ctsig = Char(tsig);
|
|
for (ki = First(tm); ki.key; ki = Next(ki)) {
|
|
char *ckey = Char(ki.key);
|
|
if (strncmp(ckey, "tmap:", 5) == 0) {
|
|
int na = count_args(ki.key);
|
|
if ((na == narg) && strstr(ckey, ctsig)) {
|
|
Hash *h = ki.item;
|
|
for (ki2 = First(h); ki2.key; ki2 = Next(ki2)) {
|
|
Delattr(h, ki2.key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Delete(tsig);
|
|
}
|
|
|
|
/* Internal function to strip array dimensions. */
|
|
static SwigType *strip_arrays(SwigType *type) {
|
|
SwigType *t;
|
|
int ndim;
|
|
int i;
|
|
t = Copy(type);
|
|
ndim = SwigType_array_ndim(t);
|
|
for (i = 0; i < ndim; i++) {
|
|
SwigType_array_setdim(t, i, "ANY");
|
|
}
|
|
return t;
|
|
}
|
|
|
|
static void debug_search_result_display(Node *tm) {
|
|
if (tm)
|
|
Printf(stdout, " Using: %%%s\n", Getattr(tm, "source"));
|
|
else
|
|
Printf(stdout, " None found\n");
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_search_helper()
|
|
*
|
|
* Helper function for typemap_search to see if there is a type match in the typemap
|
|
* tm. A match is sought in this order:
|
|
* %typemap(tm_method) ctype cqualifiedname
|
|
* %typemap(tm_method) ctype cname
|
|
* %typemap(tm_method) ctype
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *typemap_search_helper(int debug_display, Hash *tm, const String *tm_method, SwigType *ctype, const String *cqualifiedname, const String *cname, Hash **backup) {
|
|
Hash *result = 0;
|
|
Hash *tm1;
|
|
if (debug_display && cqualifiedname)
|
|
Printf(stdout, " Looking for: %s\n", SwigType_str(ctype, cqualifiedname));
|
|
if (tm && cqualifiedname) {
|
|
tm1 = Getattr(tm, cqualifiedname);
|
|
if (tm1) {
|
|
result = Getattr(tm1, tm_method); /* See if there is a type - qualified name match */
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
if (result)
|
|
*backup = result;
|
|
}
|
|
}
|
|
if (debug_display && cname)
|
|
Printf(stdout, " Looking for: %s\n", SwigType_str(ctype, cname));
|
|
if (tm && cname) {
|
|
tm1 = Getattr(tm, cname);
|
|
if (tm1) {
|
|
result = Getattr(tm1, tm_method); /* See if there is a type - name match */
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
if (result)
|
|
*backup = result;
|
|
}
|
|
}
|
|
if (debug_display)
|
|
Printf(stdout, " Looking for: %s\n", SwigType_str(ctype, 0));
|
|
if (tm) {
|
|
result = Getattr(tm, tm_method); /* See if there is simply a type without name match */
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
if (result)
|
|
*backup = result;
|
|
}
|
|
ret_result:
|
|
return result;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_search()
|
|
*
|
|
* Search for a typemap match. This is where the typemap pattern matching rules
|
|
* are implemented... tries to find the most specific typemap that includes a
|
|
* 'code' attribute.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type, const_String_or_char_ptr name, const_String_or_char_ptr qualifiedname, SwigType **matchtype, Node *node) {
|
|
Hash *result = 0;
|
|
Hash *tm;
|
|
Hash *backup = 0;
|
|
SwigType *primitive = 0;
|
|
SwigType *ctype = 0;
|
|
SwigType *ctype_unstripped = 0;
|
|
int isarray;
|
|
const String *cname = 0;
|
|
const String *cqualifiedname = 0;
|
|
String *tm_method = typemap_method_name(tmap_method);
|
|
int debug_display = (in_typemap_search_multi == 0) && typemap_search_debug;
|
|
|
|
if ((name) && Len(name))
|
|
cname = name;
|
|
if ((qualifiedname) && Len(qualifiedname))
|
|
cqualifiedname = qualifiedname;
|
|
|
|
if (debug_display) {
|
|
String *typestr = SwigType_str(type, cqualifiedname ? cqualifiedname : cname);
|
|
Swig_diagnostic(Getfile(node), Getline(node), "Searching for a suitable '%s' typemap for: %s\n", tmap_method, typestr);
|
|
Delete(typestr);
|
|
}
|
|
ctype = Copy(type);
|
|
ctype_unstripped = Copy(ctype);
|
|
while (ctype) {
|
|
/* Try to get an exact type-match */
|
|
tm = get_typemap(ctype);
|
|
result = typemap_search_helper(debug_display, tm, tm_method, ctype, cqualifiedname, cname, &backup);
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
|
|
{
|
|
/* Look for the type reduced to just the template prefix - for templated types without the template parameter list being specified */
|
|
SwigType *template_prefix = SwigType_istemplate_only_templateprefix(ctype);
|
|
if (template_prefix) {
|
|
tm = get_typemap(template_prefix);
|
|
result = typemap_search_helper(debug_display, tm, tm_method, template_prefix, cqualifiedname, cname, &backup);
|
|
Delete(template_prefix);
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
}
|
|
}
|
|
|
|
/* look for [ANY] arrays */
|
|
isarray = SwigType_isarray(ctype);
|
|
if (isarray) {
|
|
/* If working with arrays, strip away all of the dimensions and replace with "ANY".
|
|
See if that generates a match */
|
|
SwigType *noarrays = strip_arrays(ctype);
|
|
tm = get_typemap(noarrays);
|
|
result = typemap_search_helper(debug_display, tm, tm_method, noarrays, cqualifiedname, cname, &backup);
|
|
Delete(noarrays);
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
}
|
|
|
|
/* No match so far - try with a qualifier stripped (strip one qualifier at a time until none remain)
|
|
* The order of stripping in SwigType_strip_single_qualifier is used to provide some sort of consistency
|
|
* with the default (SWIGTYPE) typemap matching rules for the first qualifier to be stripped. */
|
|
{
|
|
SwigType *oldctype = ctype;
|
|
ctype = SwigType_strip_single_qualifier(oldctype);
|
|
if (!Equal(ctype, oldctype)) {
|
|
Delete(oldctype);
|
|
continue;
|
|
}
|
|
Delete(oldctype);
|
|
}
|
|
|
|
/* Once all qualifiers are stripped try resolve a typedef */
|
|
{
|
|
SwigType *oldctype = ctype;
|
|
ctype = SwigType_typedef_resolve(ctype_unstripped);
|
|
Delete(oldctype);
|
|
Delete(ctype_unstripped);
|
|
ctype_unstripped = Copy(ctype);
|
|
}
|
|
}
|
|
|
|
/* Hmmm. Well, no match seems to be found at all. See if there is some kind of default (SWIGTYPE) mapping */
|
|
|
|
primitive = SwigType_default_create(type);
|
|
while (primitive) {
|
|
tm = get_typemap(primitive);
|
|
result = typemap_search_helper(debug_display, tm, tm_method, primitive, cqualifiedname, cname, &backup);
|
|
if (result && Getattr(result, "code"))
|
|
goto ret_result;
|
|
|
|
{
|
|
SwigType *nprim = SwigType_default_deduce(primitive);
|
|
Delete(primitive);
|
|
primitive = nprim;
|
|
}
|
|
}
|
|
if (ctype != type) {
|
|
Delete(ctype);
|
|
ctype = 0;
|
|
}
|
|
result = backup;
|
|
|
|
ret_result:
|
|
Delete(primitive);
|
|
if (matchtype)
|
|
*matchtype = Copy(ctype);
|
|
Delete(ctype);
|
|
Delete(ctype_unstripped);
|
|
return result;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_search_multi()
|
|
*
|
|
* Search for a multi-argument typemap.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *typemap_search_multi(const_String_or_char_ptr tmap_method, ParmList *parms, int *nmatch) {
|
|
SwigType *type;
|
|
SwigType *mtype = 0;
|
|
String *name;
|
|
String *multi_tmap_method;
|
|
Hash *tm;
|
|
Hash *tm1 = 0;
|
|
|
|
if (!parms) {
|
|
*nmatch = 0;
|
|
return 0;
|
|
}
|
|
type = Getattr(parms, "type");
|
|
name = Getattr(parms, "name");
|
|
|
|
/* Try to find a match on the first type */
|
|
tm = typemap_search(tmap_method, type, name, 0, &mtype, parms);
|
|
if (tm) {
|
|
if (mtype && SwigType_isarray(mtype)) {
|
|
Setattr(parms, "tmap:match", mtype);
|
|
}
|
|
Delete(mtype);
|
|
multi_tmap_method = NewStringf("%s-%s+%s:", tmap_method, type, name);
|
|
in_typemap_search_multi++;
|
|
tm1 = typemap_search_multi(multi_tmap_method, nextSibling(parms), nmatch);
|
|
in_typemap_search_multi--;
|
|
if (tm1)
|
|
tm = tm1;
|
|
if (Getattr(tm, "code")) {
|
|
*(nmatch) = *nmatch + 1;
|
|
if (typemap_search_debug && tm1 && (in_typemap_search_multi == 0)) {
|
|
Printf(stdout, " Multi-argument typemap found...\n");
|
|
}
|
|
} else {
|
|
tm = 0;
|
|
}
|
|
Delete(multi_tmap_method);
|
|
}
|
|
|
|
if (typemap_search_debug && (in_typemap_search_multi == 0))
|
|
debug_search_result_display(tm);
|
|
if (typemaps_used_debug && (in_typemap_search_multi == 0) && tm) {
|
|
String *typestr = SwigType_str(type, name);
|
|
Swig_diagnostic(Getfile(parms), Getline(parms), "Typemap for %s (%s) : %%%s\n", typestr, tmap_method, Getattr(tm, "source"));
|
|
assert(Getfile(parms) && Len(Getfile(parms)) > 0); /* Missing file and line numbering information */
|
|
Delete(typestr);
|
|
}
|
|
|
|
return tm;
|
|
}
|
|
|
|
|
|
static void replace_local_types(ParmList *p, const String *name, const String *rep) {
|
|
SwigType *t;
|
|
while (p) {
|
|
t = Getattr(p, "type");
|
|
Replace(t, name, rep, DOH_REPLACE_ANY);
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
static int check_locals(ParmList *p, const char *s) {
|
|
while (p) {
|
|
char *c = GetChar(p, "type");
|
|
if (strstr(c, s))
|
|
return 1;
|
|
p = nextSibling(p);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int replace_with_override(String *src, const DOHString_or_char *token, const DOHString_or_char *rep, int flags, Hash *override_vars) {
|
|
String *override_replace = override_vars ? Getattr(override_vars, token) : NULL;
|
|
if (override_replace)
|
|
return Replace(src, token, override_replace, flags);
|
|
return Replace(src, token, rep, flags);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_replace_vars()
|
|
*
|
|
* Replaces typemap variables in a string. index is the $n variable.
|
|
* type and pname are the type and parameter name.
|
|
* override_vars are only used to replace variable names (NOT types), so is only
|
|
* used for $n, but not the various ways of representing types: $n_ltype, $n_type etc
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, SwigType *rtype, String *pname, String *lname, int index, Hash *override_vars) {
|
|
char var[512];
|
|
char *varname;
|
|
SwigType *ftype;
|
|
int bare_substitution_count = 0;
|
|
|
|
Replaceall(s, "$typemap", "$TYPEMAP"); /* workaround for $type substitution below */
|
|
|
|
ftype = SwigType_typedef_resolve_all(type);
|
|
|
|
if (!pname)
|
|
pname = lname;
|
|
{
|
|
Parm *p;
|
|
int rep = 0;
|
|
p = locals;
|
|
while (p) {
|
|
if (Strchr(Getattr(p, "type"), '$'))
|
|
rep = 1;
|
|
p = nextSibling(p);
|
|
}
|
|
if (!rep)
|
|
locals = 0;
|
|
}
|
|
|
|
sprintf(var, "$%d_", index);
|
|
varname = &var[strlen(var)];
|
|
|
|
/* If the original datatype was an array. We're going to go through and substitute
|
|
its array dimensions */
|
|
|
|
if (SwigType_isarray(type) || SwigType_isarray(ftype)) {
|
|
String *size;
|
|
int ndim;
|
|
int i;
|
|
if (SwigType_array_ndim(type) != SwigType_array_ndim(ftype))
|
|
type = ftype;
|
|
ndim = SwigType_array_ndim(type);
|
|
size = NewStringEmpty();
|
|
for (i = 0; i < ndim; i++) {
|
|
String *dim = SwigType_array_getdim(type, i);
|
|
if (index == 1) {
|
|
char t[32];
|
|
sprintf(t, "$dim%d", i);
|
|
Replace(s, t, dim, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, t, dim);
|
|
}
|
|
sprintf(varname, "dim%d", i);
|
|
Replace(s, var, dim, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, var, dim);
|
|
if (Len(size))
|
|
Putc('*', size);
|
|
Append(size, dim);
|
|
Delete(dim);
|
|
}
|
|
sprintf(varname, "size");
|
|
Replace(s, var, size, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, var, size);
|
|
Delete(size);
|
|
}
|
|
|
|
/* Parameter name substitution */
|
|
if (index == 1) {
|
|
Replace(s, "$parmname", pname, DOH_REPLACE_ANY);
|
|
}
|
|
strcpy(varname, "name");
|
|
Replace(s, var, pname, DOH_REPLACE_ANY);
|
|
|
|
/* Type-related stuff */
|
|
{
|
|
SwigType *star_type, *amp_type, *base_type, *lex_type;
|
|
SwigType *ltype, *star_ltype, *amp_ltype;
|
|
String *mangle, *star_mangle, *amp_mangle, *base_mangle, *base_name, *base_type_str;
|
|
String *descriptor, *star_descriptor, *amp_descriptor;
|
|
String *ts;
|
|
char *sc;
|
|
|
|
sc = Char(s);
|
|
|
|
if (strstr(sc, "type") || check_locals(locals, "type")) {
|
|
/* Given type : $type */
|
|
ts = SwigType_str(type, 0);
|
|
if (index == 1) {
|
|
Replace(s, "$type", ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$type", type);
|
|
}
|
|
strcpy(varname, "type");
|
|
Replace(s, var, ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, var, type);
|
|
Delete(ts);
|
|
sc = Char(s);
|
|
}
|
|
if (strstr(sc, "ltype") || check_locals(locals, "ltype")) {
|
|
/* Local type: $ltype */
|
|
ltype = SwigType_ltype(type);
|
|
ts = SwigType_str(ltype, 0);
|
|
if (index == 1) {
|
|
Replace(s, "$ltype", ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$ltype", ltype);
|
|
}
|
|
strcpy(varname, "ltype");
|
|
Replace(s, var, ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, var, ltype);
|
|
Delete(ts);
|
|
Delete(ltype);
|
|
sc = Char(s);
|
|
}
|
|
if (strstr(sc, "mangle") || strstr(sc, "descriptor")) {
|
|
/* Mangled type */
|
|
|
|
mangle = SwigType_manglestr(type);
|
|
if (index == 1)
|
|
Replace(s, "$mangle", mangle, DOH_REPLACE_ANY);
|
|
strcpy(varname, "mangle");
|
|
Replace(s, var, mangle, DOH_REPLACE_ANY);
|
|
|
|
descriptor = NewStringf("SWIGTYPE%s", mangle);
|
|
|
|
if (index == 1)
|
|
if (Replace(s, "$descriptor", descriptor, DOH_REPLACE_ANY))
|
|
SwigType_remember(type);
|
|
|
|
strcpy(varname, "descriptor");
|
|
if (Replace(s, var, descriptor, DOH_REPLACE_ANY))
|
|
SwigType_remember(type);
|
|
|
|
Delete(descriptor);
|
|
Delete(mangle);
|
|
}
|
|
|
|
/* One pointer level removed */
|
|
/* This creates variables of the form
|
|
$*n_type
|
|
$*n_ltype
|
|
*/
|
|
|
|
if (SwigType_ispointer(ftype) || (SwigType_isarray(ftype)) || (SwigType_isreference(ftype)) || (SwigType_isrvalue_reference(ftype))) {
|
|
if (!(SwigType_isarray(type) || SwigType_ispointer(type) || SwigType_isreference(type) || SwigType_isrvalue_reference(type))) {
|
|
star_type = Copy(ftype);
|
|
} else {
|
|
star_type = Copy(type);
|
|
}
|
|
if (!(SwigType_isreference(star_type) || SwigType_isrvalue_reference(star_type))) {
|
|
if (SwigType_isarray(star_type)) {
|
|
SwigType_del_element(star_type);
|
|
} else {
|
|
SwigType_del_pointer(star_type);
|
|
}
|
|
ts = SwigType_str(star_type, 0);
|
|
if (index == 1) {
|
|
Replace(s, "$*type", ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$*type", star_type);
|
|
}
|
|
sprintf(varname, "$*%d_type", index);
|
|
Replace(s, varname, ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, varname, star_type);
|
|
Delete(ts);
|
|
} else {
|
|
SwigType_del_element(star_type);
|
|
}
|
|
star_ltype = SwigType_ltype(star_type);
|
|
ts = SwigType_str(star_ltype, 0);
|
|
if (index == 1) {
|
|
Replace(s, "$*ltype", ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$*ltype", star_ltype);
|
|
}
|
|
sprintf(varname, "$*%d_ltype", index);
|
|
Replace(s, varname, ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, varname, star_ltype);
|
|
Delete(ts);
|
|
Delete(star_ltype);
|
|
|
|
star_mangle = SwigType_manglestr(star_type);
|
|
if (index == 1)
|
|
Replace(s, "$*mangle", star_mangle, DOH_REPLACE_ANY);
|
|
|
|
sprintf(varname, "$*%d_mangle", index);
|
|
Replace(s, varname, star_mangle, DOH_REPLACE_ANY);
|
|
|
|
star_descriptor = NewStringf("SWIGTYPE%s", star_mangle);
|
|
if (index == 1)
|
|
if (Replace(s, "$*descriptor", star_descriptor, DOH_REPLACE_ANY))
|
|
SwigType_remember(star_type);
|
|
sprintf(varname, "$*%d_descriptor", index);
|
|
if (Replace(s, varname, star_descriptor, DOH_REPLACE_ANY))
|
|
SwigType_remember(star_type);
|
|
|
|
Delete(star_descriptor);
|
|
Delete(star_mangle);
|
|
Delete(star_type);
|
|
} else {
|
|
/* TODO: Signal error if one of the $* substitutions is
|
|
requested */
|
|
}
|
|
/* One pointer level added */
|
|
amp_type = Copy(type);
|
|
SwigType_add_pointer(amp_type);
|
|
ts = SwigType_str(amp_type, 0);
|
|
if (index == 1) {
|
|
Replace(s, "$&type", ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$&type", amp_type);
|
|
}
|
|
sprintf(varname, "$&%d_type", index);
|
|
Replace(s, varname, ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, varname, amp_type);
|
|
Delete(ts);
|
|
|
|
amp_ltype = SwigType_ltype(type);
|
|
SwigType_add_pointer(amp_ltype);
|
|
ts = SwigType_str(amp_ltype, 0);
|
|
|
|
if (index == 1) {
|
|
Replace(s, "$<ype", ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$<ype", amp_ltype);
|
|
}
|
|
sprintf(varname, "$&%d_ltype", index);
|
|
Replace(s, varname, ts, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, varname, amp_ltype);
|
|
Delete(ts);
|
|
Delete(amp_ltype);
|
|
|
|
amp_mangle = SwigType_manglestr(amp_type);
|
|
if (index == 1)
|
|
Replace(s, "$&mangle", amp_mangle, DOH_REPLACE_ANY);
|
|
sprintf(varname, "$&%d_mangle", index);
|
|
Replace(s, varname, amp_mangle, DOH_REPLACE_ANY);
|
|
|
|
amp_descriptor = NewStringf("SWIGTYPE%s", amp_mangle);
|
|
if (index == 1)
|
|
if (Replace(s, "$&descriptor", amp_descriptor, DOH_REPLACE_ANY))
|
|
SwigType_remember(amp_type);
|
|
sprintf(varname, "$&%d_descriptor", index);
|
|
if (Replace(s, varname, amp_descriptor, DOH_REPLACE_ANY))
|
|
SwigType_remember(amp_type);
|
|
|
|
Delete(amp_descriptor);
|
|
Delete(amp_mangle);
|
|
Delete(amp_type);
|
|
|
|
/* Base type */
|
|
if (SwigType_isarray(type)) {
|
|
base_type = Copy(type);
|
|
Delete(SwigType_pop_arrays(base_type));
|
|
} else {
|
|
base_type = SwigType_base(type);
|
|
}
|
|
|
|
base_type_str = SwigType_str(base_type, 0);
|
|
base_name = SwigType_namestr(base_type_str);
|
|
if (index == 1) {
|
|
Replace(s, "$basetype", base_name, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, "$basetype", base_name);
|
|
}
|
|
strcpy(varname, "basetype");
|
|
Replace(s, var, base_type_str, DOH_REPLACE_ANY);
|
|
replace_local_types(locals, var, base_name);
|
|
|
|
base_mangle = SwigType_manglestr(base_type);
|
|
if (index == 1)
|
|
Replace(s, "$basemangle", base_mangle, DOH_REPLACE_ANY);
|
|
strcpy(varname, "basemangle");
|
|
Replace(s, var, base_mangle, DOH_REPLACE_ANY);
|
|
Delete(base_mangle);
|
|
Delete(base_name);
|
|
Delete(base_type_str);
|
|
Delete(base_type);
|
|
|
|
lex_type = SwigType_base(rtype);
|
|
if (index == 1)
|
|
Replace(s, "$lextype", lex_type, DOH_REPLACE_ANY);
|
|
strcpy(varname, "lextype");
|
|
Replace(s, var, lex_type, DOH_REPLACE_ANY);
|
|
Delete(lex_type);
|
|
}
|
|
|
|
/* Replace variable usage $n. with (&$n)-> */
|
|
{
|
|
char temp[64];
|
|
sprintf(var, "$%d.", index);
|
|
sprintf(temp, "(&$%d)->", index);
|
|
Replace(s, var, temp, DOH_REPLACE_ANY);
|
|
}
|
|
|
|
/* Replace the bare $n variable */
|
|
sprintf(var, "$%d", index);
|
|
bare_substitution_count = replace_with_override(s, var, lname, DOH_REPLACE_NUMBER_END, override_vars);
|
|
Delete(ftype);
|
|
return bare_substitution_count;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
* static typemap_locals()
|
|
*
|
|
* Takes a string, a parameter list and a wrapper function argument and
|
|
* creates the local variables.
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
static void typemap_locals(String *s, ParmList *l, Wrapper *f, int argnum) {
|
|
Parm *p;
|
|
char *new_name;
|
|
|
|
p = l;
|
|
while (p) {
|
|
SwigType *pt = Getattr(p, "type");
|
|
SwigType *at = SwigType_alttype(pt, 1);
|
|
String *pn = Getattr(p, "name");
|
|
String *value = Getattr(p, "value");
|
|
if (at)
|
|
pt = at;
|
|
if (pn) {
|
|
if (Len(pn) > 0) {
|
|
String *str;
|
|
int isglobal = 0;
|
|
|
|
str = NewStringEmpty();
|
|
|
|
if (strncmp(Char(pn), "_global_", 8) == 0) {
|
|
isglobal = 1;
|
|
}
|
|
|
|
/* If the user gave us $type as the name of the local variable, we'll use
|
|
the passed datatype instead */
|
|
|
|
if ((argnum >= 0) && (!isglobal)) {
|
|
Printf(str, "%s%d", pn, argnum);
|
|
} else {
|
|
Append(str, pn);
|
|
}
|
|
if (isglobal && Wrapper_check_local(f, str)) {
|
|
p = nextSibling(p);
|
|
Delete(str);
|
|
if (at)
|
|
Delete(at);
|
|
continue;
|
|
}
|
|
if (value) {
|
|
String *pstr = SwigType_str(pt, str);
|
|
new_name = Wrapper_new_localv(f, str, pstr, "=", value, NIL);
|
|
Delete(pstr);
|
|
} else {
|
|
String *pstr = SwigType_str(pt, str);
|
|
new_name = Wrapper_new_localv(f, str, pstr, NIL);
|
|
Delete(pstr);
|
|
}
|
|
if (!isglobal) {
|
|
/* Substitute */
|
|
Replace(s, pn, new_name, DOH_REPLACE_ID | DOH_REPLACE_NOQUOTE);
|
|
}
|
|
Delete(str);
|
|
}
|
|
}
|
|
p = nextSibling(p);
|
|
if (at)
|
|
Delete(at);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_warn()
|
|
*
|
|
* If any warning message is attached to this parameter's "tmap:<method>:warning"
|
|
* attribute, return the warning message (special variables will need expanding
|
|
* before displaying the warning).
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static String *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);
|
|
return w ? Copy(w) : 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_merge_fragment_kwargs()
|
|
*
|
|
* If multiple 'fragment' attributes are provided to a typemap, combine them by
|
|
* concatenating with commas.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void typemap_merge_fragment_kwargs(Parm *kw) {
|
|
Parm *reattach_kw = NULL;
|
|
Parm *prev_kw = NULL;
|
|
Parm *next_kw = NULL;
|
|
String *fragment = NULL;
|
|
while (kw) {
|
|
next_kw = nextSibling(kw);
|
|
if (Strcmp(Getattr(kw, "name"), "fragment") == 0) {
|
|
String *thisfragment = Getattr(kw, "value");
|
|
String *kwtype = Getattr(kw, "type");
|
|
if (!fragment) {
|
|
/* First fragment found; it should remain in the list */
|
|
fragment = thisfragment;
|
|
prev_kw = kw;
|
|
} else {
|
|
/* Concatenate to previously found fragment */
|
|
Printv(fragment, ",", thisfragment, NULL);
|
|
reattach_kw = prev_kw;
|
|
}
|
|
if (kwtype) {
|
|
String *mangle = Swig_name_mangle_type(kwtype);
|
|
Append(fragment, mangle);
|
|
Delete(mangle);
|
|
/* Remove 'type' from kwargs so it's not duplicated later */
|
|
Setattr(kw, "type", NULL);
|
|
}
|
|
} else {
|
|
/* Not a fragment */
|
|
if (reattach_kw) {
|
|
/* Update linked list to remove duplicate fragment */
|
|
DohIncref(kw);
|
|
set_nextSibling(reattach_kw, kw);
|
|
set_previousSibling(kw, reattach_kw);
|
|
Delete(reattach_kw);
|
|
reattach_kw = NULL;
|
|
}
|
|
prev_kw = kw;
|
|
}
|
|
kw = next_kw;
|
|
}
|
|
if (reattach_kw) {
|
|
/* Update linked list to remove duplicate fragment */
|
|
set_nextSibling(reattach_kw, kw);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_lookup()
|
|
*
|
|
* Attach one or more typemaps to a node and optionally generate the typemap contents
|
|
* into the wrapper.
|
|
*
|
|
* 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 tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) {
|
|
SwigType *type;
|
|
SwigType *mtype = 0;
|
|
String *pname;
|
|
String *qpname = 0;
|
|
String *noscope_pname = 0;
|
|
Hash *tm = 0;
|
|
String *s = 0;
|
|
String *sdef = 0;
|
|
String *warning = 0;
|
|
ParmList *locals;
|
|
ParmList *kw;
|
|
char temp[256];
|
|
String *symname;
|
|
String *cname = 0;
|
|
String *clname = 0;
|
|
char *cmethod = Char(tmap_method);
|
|
int optimal_attribute = 0;
|
|
int optimal_substitution = 0;
|
|
int delete_optimal_attribute = 0;
|
|
int num_substitutions = 0;
|
|
SwigType *matchtype = 0;
|
|
|
|
type = Getattr(node, "type");
|
|
if (!type)
|
|
return sdef;
|
|
|
|
/* Special hook (hack!). Check for the 'ref' feature and add code it contains to any 'newfree' typemap code.
|
|
* We could choose to put this hook into a number of different typemaps, not necessarily 'newfree'...
|
|
* Rather confusingly 'newfree' is used to release memory and the 'ref' feature is used to add in memory references - yuck! */
|
|
if (Cmp(tmap_method, "newfree") == 0) {
|
|
String *base = SwigType_base(type);
|
|
Node *typenode = Swig_symbol_clookup(base, 0);
|
|
if (typenode)
|
|
sdef = Swig_ref_call(typenode, lname);
|
|
Delete(base);
|
|
}
|
|
|
|
pname = Getattr(node, "name");
|
|
noscope_pname = Copy(pname);
|
|
|
|
if (pname && Getattr(node, "sym:symtab")) {
|
|
/* Add on a qualified name search for any symbol in the symbol table, for example:
|
|
* struct Foo {
|
|
* int *foo(int bar) -> Foo::foo
|
|
* };
|
|
* Note that if node is a parameter (Parm *) then there will be no symbol table attached to the Parm *.
|
|
*/
|
|
String *qsn;
|
|
if (Swig_scopename_check(pname)) {
|
|
/* sometimes pname is qualified, so we remove all the scope for the lookup */
|
|
Delete(noscope_pname);
|
|
noscope_pname = Swig_scopename_last(pname);
|
|
/*
|
|
Printf(stdout, "Removed scope: %s => %s\n", pname, noscope_pname);
|
|
*/
|
|
}
|
|
qsn = Swig_symbol_qualified(node);
|
|
if (qsn && Len(qsn)) {
|
|
qpname = NewStringf("%s::%s", qsn, noscope_pname);
|
|
Delete(qsn);
|
|
}
|
|
}
|
|
|
|
tm = typemap_search(tmap_method, type, noscope_pname, qpname, &mtype, node);
|
|
if (typemap_search_debug)
|
|
debug_search_result_display(tm);
|
|
if (typemaps_used_debug && tm) {
|
|
String *typestr = SwigType_str(type, qpname ? qpname : pname);
|
|
Swig_diagnostic(Getfile(node), Getline(node), "Typemap for %s (%s) : %%%s\n", typestr, tmap_method, Getattr(tm, "source"));
|
|
assert(Getfile(node) && Len(Getfile(node)) > 0); /* Missing file and line numbering information */
|
|
Delete(typestr);
|
|
}
|
|
|
|
Delete(qpname);
|
|
qpname = 0;
|
|
Delete(noscope_pname);
|
|
noscope_pname = 0;
|
|
|
|
if (!tm)
|
|
return sdef;
|
|
|
|
s = Getattr(tm, "code");
|
|
if (!s)
|
|
return sdef;
|
|
|
|
/* Empty typemap. No match */
|
|
if (Cmp(s, "pass") == 0)
|
|
return sdef;
|
|
|
|
s = Copy(s); /* Make a local copy of the typemap code */
|
|
|
|
/* Look in the "out" typemap for the "optimal" attribute */
|
|
if (Cmp(cmethod, "out") == 0) {
|
|
kw = Getattr(tm, "kwargs");
|
|
while (kw) {
|
|
if (Cmp(Getattr(kw, "name"), "optimal") == 0) {
|
|
optimal_attribute = GetFlag(kw, "value");
|
|
break;
|
|
}
|
|
kw = nextSibling(kw);
|
|
}
|
|
}
|
|
|
|
if (optimal_attribute) {
|
|
/* Note: "out" typemap is the only typemap that will have the "optimal" attribute set.
|
|
* If f and actioncode are NULL, then the caller is just looking to attach the "out" attributes
|
|
* ie, not use the typemap code, otherwise both f and actioncode must be non null. */
|
|
if (actioncode) {
|
|
const String *result_equals = NewStringf("%s = ", Swig_cresult_name());
|
|
/* check that the code in the typemap can be used in this optimal way.
|
|
* The code should be in the form "result = ...;\n". We need to extract
|
|
* the "..." part. This may not be possible for various reasons, eg
|
|
* code added by %exception. This optimal code generation is bit of a
|
|
* hack and circumvents the normal requirement for a temporary variable
|
|
* to hold the result returned from a wrapped function call.
|
|
*/
|
|
if (Strncmp(actioncode, result_equals, Len(result_equals)) == 0 &&
|
|
Strchr(actioncode, ';') == Char(actioncode) + Len(actioncode) - 2 &&
|
|
Char(actioncode)[Len(actioncode) - 1] == '\n') {
|
|
clname = NewStringWithSize(Char(actioncode) + Len(result_equals),
|
|
Len(actioncode) - Len(result_equals) - 2);
|
|
lname = clname;
|
|
actioncode = 0;
|
|
optimal_substitution = 1;
|
|
} else {
|
|
Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_IGNORED, Getfile(node), Getline(node), "Method %s usage of the optimal attribute ignored\n", Swig_name_decl(node));
|
|
Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_IGNORED, Getfile(s), Getline(s), "in the out typemap as the following cannot be used to generate optimal code: %s\n", actioncode);
|
|
delete_optimal_attribute = 1;
|
|
}
|
|
} else {
|
|
assert(!f);
|
|
}
|
|
}
|
|
|
|
if (actioncode) {
|
|
assert(f);
|
|
Append(f->code, actioncode);
|
|
}
|
|
|
|
/* emit local variables declared in typemap, eg emit declarations for aa and bb in:
|
|
* %typemap(in) foo (int aa, int bb) "..." */
|
|
locals = Getattr(tm, "locals");
|
|
if (locals)
|
|
locals = CopyParmList(locals);
|
|
|
|
if (pname) {
|
|
if (SwigType_istemplate(pname)) {
|
|
cname = SwigType_namestr(pname);
|
|
pname = cname;
|
|
}
|
|
}
|
|
if (SwigType_istemplate((char *) lname)) {
|
|
clname = SwigType_namestr((char *) lname);
|
|
lname = clname;
|
|
}
|
|
|
|
matchtype = mtype && SwigType_isarray(mtype) ? mtype : type;
|
|
num_substitutions = typemap_replace_vars(s, locals, matchtype, type, pname, (char *) lname, 1, NULL);
|
|
if (optimal_substitution && num_substitutions > 1) {
|
|
Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE, Getfile(node), Getline(node), "Multiple calls to %s might be generated due to\n", Swig_name_decl(node));
|
|
Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE, Getfile(s), Getline(s), "optimal attribute usage in the out typemap.\n");
|
|
}
|
|
|
|
if (locals && f) {
|
|
typemap_locals(s, locals, f, -1);
|
|
}
|
|
|
|
{
|
|
ParmList *parm_sublist = NewParmWithoutFileLineInfo(type, pname);
|
|
Setattr(parm_sublist, "lname", lname);
|
|
replace_embedded_typemap(s, parm_sublist, f, tm);
|
|
Delete(parm_sublist);
|
|
}
|
|
|
|
/* Attach kwargs - ie the typemap attributes */
|
|
kw = Getattr(tm, "kwargs");
|
|
typemap_merge_fragment_kwargs(kw);
|
|
while (kw) {
|
|
String *value = Copy(Getattr(kw, "value"));
|
|
String *kwtype = Getattr(kw, "type");
|
|
char *ckwname = Char(Getattr(kw, "name"));
|
|
{
|
|
/* Expand special variables in typemap attributes. */
|
|
SwigType *ptype = Getattr(node, "type");
|
|
String *pname = Getattr(node, "name");
|
|
SwigType *mtype = Getattr(node, "tmap:match");
|
|
SwigType *matchtype = mtype ? mtype : ptype;
|
|
ParmList *parm_sublist;
|
|
typemap_replace_vars(value, NULL, matchtype, ptype, pname, (char *)lname, 1, NULL);
|
|
|
|
/* Expand special variable macros (embedded typemaps) in typemap attributes. */
|
|
parm_sublist = NewParmWithoutFileLineInfo(ptype, pname);
|
|
Setattr(parm_sublist, "lname", lname);
|
|
replace_embedded_typemap(value, parm_sublist, NULL, tm);
|
|
Delete(parm_sublist);
|
|
}
|
|
if (kwtype) {
|
|
String *mangle = Swig_name_mangle_type(kwtype);
|
|
Append(value, mangle);
|
|
Delete(mangle);
|
|
}
|
|
sprintf(temp, "%s:%s", cmethod, ckwname);
|
|
Setattr(node, typemap_method_name(temp), value);
|
|
Delete(value);
|
|
kw = nextSibling(kw);
|
|
}
|
|
|
|
if (delete_optimal_attribute)
|
|
Delattr(node, "tmap:out:optimal");
|
|
|
|
Replace(s, "$name", pname, DOH_REPLACE_ANY);
|
|
|
|
symname = Getattr(node, "sym:name");
|
|
if (symname)
|
|
Replace(s, "$symname", symname, DOH_REPLACE_ANY);
|
|
|
|
Setattr(node, typemap_method_name(tmap_method), s);
|
|
if (locals) {
|
|
sprintf(temp, "%s:locals", cmethod);
|
|
Setattr(node, typemap_method_name(temp), locals);
|
|
Delete(locals);
|
|
}
|
|
|
|
if (Checkattr(tm, "type", "SWIGTYPE")) {
|
|
sprintf(temp, "%s:SWIGTYPE", cmethod);
|
|
Setattr(node, typemap_method_name(temp), "1");
|
|
}
|
|
|
|
/* Print warnings, if any */
|
|
warning = typemap_warn(cmethod, node);
|
|
if (warning) {
|
|
typemap_replace_vars(warning, 0, matchtype, type, pname, (char *) lname, 1, NULL);
|
|
Replace(warning, "$name", pname, DOH_REPLACE_ANY);
|
|
if (symname)
|
|
Replace(warning, "$symname", symname, DOH_REPLACE_ANY);
|
|
Swig_warning(0, Getfile(node), Getline(node), "%s\n", warning);
|
|
Delete(warning);
|
|
}
|
|
|
|
/* Look for code fragments */
|
|
{
|
|
String *fragment;
|
|
sprintf(temp, "%s:fragment", cmethod);
|
|
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);
|
|
Delete(fname);
|
|
}
|
|
}
|
|
|
|
Delete(cname);
|
|
Delete(clname);
|
|
Delete(mtype);
|
|
if (sdef) { /* put 'ref' and 'newfree' codes together */
|
|
String *p = NewStringf("%s\n%s", sdef, s);
|
|
Delete(s);
|
|
Delete(sdef);
|
|
s = p;
|
|
}
|
|
Delete(actioncode);
|
|
return s;
|
|
}
|
|
|
|
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(tmap_method, "out") == 0);
|
|
return Swig_typemap_lookup_impl(tmap_method, node, lname, f, actioncode);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_attach_kwargs()
|
|
*
|
|
* If this hash (tm) contains a linked list of parameters under its "kwargs"
|
|
* attribute, add keys for each of those named keyword arguments to this
|
|
* parameter for later use.
|
|
* For example, attach the typemap attributes to firstp (first parameter in parameter list):
|
|
* %typemap(in, foo="xyz") ...
|
|
* A new attribute called "tmap:in:foo" with value "xyz" is attached to firstp.
|
|
* Also expands special variables and special variable macros in the typemap attributes.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr tmap_method, Parm *firstp, int nmatch) {
|
|
String *temp = NewStringEmpty();
|
|
Parm *kw = Getattr(tm, "kwargs");
|
|
typemap_merge_fragment_kwargs(kw);
|
|
while (kw) {
|
|
String *value = Copy(Getattr(kw, "value"));
|
|
String *type = Getattr(kw, "type");
|
|
int i;
|
|
Parm *p = firstp;
|
|
/* Expand special variables */
|
|
for (i = 0; i < nmatch; i++) {
|
|
SwigType *type = Getattr(p, "type");
|
|
String *pname = Getattr(p, "name");
|
|
String *lname = Getattr(p, "lname");
|
|
SwigType *mtype = Getattr(p, "tmap:match");
|
|
SwigType *matchtype = mtype ? mtype : type;
|
|
typemap_replace_vars(value, NULL, matchtype, type, pname, lname, i + 1, NULL);
|
|
p = nextSibling(p);
|
|
}
|
|
|
|
/* Expand special variable macros (embedded typemaps).
|
|
* Special variable are expanded first above as they might be used in the special variable macros.
|
|
* For example: $typemap(imtype, $2_type). */
|
|
p = firstp;
|
|
for (i = 0; i < nmatch; i++) {
|
|
SwigType *type = Getattr(p, "type");
|
|
String *pname = Getattr(p, "name");
|
|
String *lname = Getattr(p, "lname");
|
|
ParmList *parm_sublist = NewParmWithoutFileLineInfo(type, pname);
|
|
Setattr(parm_sublist, "lname", lname);
|
|
replace_embedded_typemap(value, parm_sublist, NULL, tm);
|
|
p = nextSibling(p);
|
|
}
|
|
if (type) {
|
|
Hash *v = NewHash();
|
|
Setattr(v, "type", type);
|
|
Setattr(v, "value", value);
|
|
Delete(value);
|
|
value = v;
|
|
}
|
|
Clear(temp);
|
|
Printf(temp, "%s:%s", tmap_method, Getattr(kw, "name"));
|
|
Setattr(firstp, typemap_method_name(temp), value);
|
|
Delete(value);
|
|
kw = nextSibling(kw);
|
|
}
|
|
Clear(temp);
|
|
Printf(temp, "%s:match_type", tmap_method);
|
|
Setattr(firstp, typemap_method_name(temp), Getattr(tm, "type"));
|
|
Delete(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));
|
|
Setline(fname, Getline(p));
|
|
Swig_fragment_emit(fname);
|
|
Delete(fname);
|
|
}
|
|
Delete(temp);
|
|
}
|
|
|
|
static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) {
|
|
Parm *kw = Getattr(tm, "kwargs");
|
|
while (kw) {
|
|
String *kname = Getattr(kw, "name");
|
|
if (Equal(kname, name)) {
|
|
return Getattr(kw, "value");
|
|
}
|
|
kw = nextSibling(kw);
|
|
}
|
|
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 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
|
|
* override_vars - Hash of variables from $typemap(...) that will override special variable replacements
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f, Hash *override_vars) {
|
|
Parm *p, *firstp;
|
|
Hash *tm;
|
|
int nmatch = 0;
|
|
int i;
|
|
String *s;
|
|
String *warning = 0;
|
|
ParmList *locals;
|
|
int argnum = 0;
|
|
char temp[256];
|
|
char *cmethod = Char(tmap_method);
|
|
String *kwmatch = 0;
|
|
p = parms;
|
|
|
|
#ifdef SWIG_DEBUG
|
|
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", tmap_method, Getattr(p, "name"), Getattr(p, "type"));
|
|
#endif
|
|
tm = typemap_search_multi(tmap_method, p, &nmatch);
|
|
#ifdef SWIG_DEBUG
|
|
if (tm)
|
|
Printf(stdout, "found: %s\n", tm);
|
|
#endif
|
|
if (!tm) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
/*
|
|
Check if the typemap requires to match the type of another
|
|
typemap, for example:
|
|
|
|
%typemap(in) SWIGTYPE * (int var) {...}
|
|
%typemap(freearg,match="in") SWIGTYPE * {if (var$argnum) ...}
|
|
|
|
here, the freearg typemap requires the "in" typemap to match,
|
|
or the 'var$argnum' variable will not exist.
|
|
*/
|
|
kwmatch = typemap_get_option(tm, "match");
|
|
if (kwmatch) {
|
|
String *tmname = NewStringf("tmap:%s", kwmatch);
|
|
String *tmin = Getattr(p, tmname);
|
|
Delete(tmname);
|
|
#ifdef SWIG_DEBUG
|
|
if (tm)
|
|
Printf(stdout, "matching: %s\n", kwmatch);
|
|
#endif
|
|
if (tmin) {
|
|
String *tmninp = NewStringf("tmap:%s:numinputs", kwmatch);
|
|
String *ninp = Getattr(p, tmninp);
|
|
Delete(tmninp);
|
|
if (ninp && Equal(ninp, "0")) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
} else {
|
|
SwigType *typetm = Getattr(tm, "type");
|
|
String *temp = NewStringf("tmap:%s:match_type", kwmatch);
|
|
SwigType *typein = Getattr(p, temp);
|
|
Delete(temp);
|
|
if (!Equal(typein, typetm)) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
} else {
|
|
int nnmatch;
|
|
Hash *tmapin = typemap_search_multi(kwmatch, p, &nnmatch);
|
|
String *tmname = Getattr(tm, "pname");
|
|
String *tnname = Getattr(tmapin, "pname");
|
|
if (!(tmname && tnname && Equal(tmname, tnname)) && !(!tmname && !tnname)) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
s = Getattr(tm, "code");
|
|
if (!s) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
#ifdef SWIG_DEBUG
|
|
if (s)
|
|
Printf(stdout, "code: %s\n", s);
|
|
#endif
|
|
|
|
/* Empty typemap. No match */
|
|
if (Cmp(s, "pass") == 0) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
|
|
s = Copy(s);
|
|
locals = Getattr(tm, "locals");
|
|
if (locals)
|
|
locals = CopyParmList(locals);
|
|
firstp = p;
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "nmatch: %d\n", nmatch);
|
|
#endif
|
|
for (i = 0; i < nmatch; i++) {
|
|
SwigType *type = Getattr(p, "type");
|
|
String *pname = Getattr(p, "name");
|
|
String *lname = Getattr(p, "lname");
|
|
SwigType *mtype = Getattr(p, "tmap:match");
|
|
SwigType *matchtype = mtype ? mtype : type;
|
|
|
|
typemap_replace_vars(s, locals, matchtype, type, pname, lname, i + 1, override_vars);
|
|
if (mtype)
|
|
Delattr(p, "tmap:match");
|
|
|
|
if (Checkattr(tm, "type", "SWIGTYPE")) {
|
|
sprintf(temp, "%s:SWIGTYPE", cmethod);
|
|
Setattr(p, typemap_method_name(temp), "1");
|
|
}
|
|
p = nextSibling(p);
|
|
}
|
|
|
|
if (locals && f) {
|
|
typemap_locals(s, locals, f, argnum);
|
|
}
|
|
|
|
replace_embedded_typemap(s, firstp, f, tm);
|
|
|
|
/* Attach attributes to object */
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), s);
|
|
#endif
|
|
Setattr(firstp, typemap_method_name(tmap_method), s); /* Code object */
|
|
|
|
if (locals) {
|
|
sprintf(temp, "%s:locals", cmethod);
|
|
Setattr(firstp, typemap_method_name(temp), locals);
|
|
Delete(locals);
|
|
}
|
|
|
|
/* Attach a link to the next parameter. Needed for multimaps */
|
|
sprintf(temp, "%s:next", cmethod);
|
|
Setattr(firstp, typemap_method_name(temp), p);
|
|
|
|
/* Attach kwargs */
|
|
typemap_attach_kwargs(tm, tmap_method, firstp, nmatch);
|
|
|
|
/* Replace the argument number */
|
|
sprintf(temp, "%d", argnum);
|
|
Replace(s, "$argnum", temp, DOH_REPLACE_ANY);
|
|
|
|
/* Print warnings, if any */
|
|
warning = typemap_warn(tmap_method, firstp);
|
|
if (warning) {
|
|
SwigType *type = Getattr(firstp, "type");
|
|
String *pname = Getattr(firstp, "name");
|
|
String *lname = Getattr(firstp, "lname");
|
|
SwigType *mtype = Getattr(firstp, "tmap:match");
|
|
SwigType *matchtype = mtype ? mtype : type;
|
|
typemap_replace_vars(warning, 0, matchtype, type, pname, lname, 1, override_vars);
|
|
Replace(warning, "$argnum", temp, DOH_REPLACE_ANY);
|
|
Swig_warning(0, Getfile(firstp), Getline(firstp), "%s\n", warning);
|
|
Delete(warning);
|
|
}
|
|
|
|
/* Look for code fragments */
|
|
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"), typemap_method_name(tmap_method), Getattr(firstp, typemap_method_name(tmap_method)));
|
|
#endif
|
|
|
|
}
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "Swig_typemap_attach_parms: end\n");
|
|
#endif
|
|
|
|
}
|
|
|
|
void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f) {
|
|
typemap_attach_parms(tmap_method, parms, f, NULL);
|
|
}
|
|
|
|
/* Splits the arguments of an embedded typemap */
|
|
static List *split_embedded_typemap(String *s) {
|
|
List *args = 0;
|
|
char *c, *start;
|
|
int level = 0;
|
|
int angle_level = 0;
|
|
int leading = 1;
|
|
|
|
args = NewList();
|
|
c = strchr(Char(s), '(');
|
|
assert(c);
|
|
c++;
|
|
|
|
start = c;
|
|
while (*c) {
|
|
if (*c == '\"') {
|
|
c++;
|
|
while (*c) {
|
|
if (*c == '\\') {
|
|
c++;
|
|
} else {
|
|
if (*c == '\"')
|
|
break;
|
|
}
|
|
c++;
|
|
}
|
|
}
|
|
if ((level == 0) && angle_level == 0 && ((*c == ',') || (*c == ')'))) {
|
|
String *tmp = NewStringWithSize(start, (int)(c - start));
|
|
Append(args, tmp);
|
|
Delete(tmp);
|
|
start = c + 1;
|
|
leading = 1;
|
|
if (*c == ')')
|
|
break;
|
|
c++;
|
|
continue;
|
|
}
|
|
if (*c == '(')
|
|
level++;
|
|
if (*c == ')')
|
|
level--;
|
|
if (*c == '<')
|
|
angle_level++;
|
|
if (*c == '>' && *(c - 1) != '-')
|
|
angle_level--;
|
|
if (isspace((int) *c) && leading)
|
|
start++;
|
|
if (!isspace((int) *c))
|
|
leading = 0;
|
|
c++;
|
|
}
|
|
return args;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_replace_embedded_typemap()
|
|
*
|
|
* For special variable macro $typemap(...) expansion outside of typemaps.
|
|
* Only limited usage works as most typemap special variables ($1, $input etc)
|
|
* are not expanded correctly outside of typemaps.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_replace_embedded_typemap(String *s, Node *file_line_node) {
|
|
Setfile(s, Getfile(file_line_node));
|
|
Setline(s, Getline(file_line_node));
|
|
Replaceall(s, "$typemap", "$TYPEMAP");
|
|
replace_embedded_typemap(s, 0, 0, file_line_node);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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 initially an experiment in the first implementation of $typemap.
|
|
* They allow one to override known special variable replacements or even add in new special variables for replacement
|
|
* from the calling typemap to the called 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) {...}
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f, Node *file_line_node) {
|
|
char *start = 0;
|
|
while ((start = strstr(Char(s), "$TYPEMAP("))) { /* note $typemap capitalisation to $TYPEMAP hack */
|
|
|
|
/* Gather the parameters */
|
|
char *end = 0, *c;
|
|
int level = 0;
|
|
String *dollar_typemap;
|
|
int syntax_error = 1;
|
|
c = start;
|
|
while (*c) {
|
|
if (*c == '(')
|
|
level++;
|
|
if (*c == ')') {
|
|
level--;
|
|
if (level == 0) {
|
|
end = c + 1;
|
|
break;
|
|
}
|
|
}
|
|
c++;
|
|
}
|
|
if (end) {
|
|
dollar_typemap = NewStringWithSize(start, (int)((end - start)));
|
|
syntax_error = 0;
|
|
} else {
|
|
dollar_typemap = NewStringWithSize(start, (int)((c - start)));
|
|
}
|
|
|
|
if (!syntax_error) {
|
|
List *l;
|
|
String *tmap_method;
|
|
Hash *override_vars;
|
|
syntax_error = 1;
|
|
|
|
/* Split apart each parameter in $typemap(...) */
|
|
l = split_embedded_typemap(dollar_typemap);
|
|
|
|
if (Len(l) >= 2) {
|
|
ParmList *to_match_parms;
|
|
tmap_method = Getitem(l, 0);
|
|
|
|
/* 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), file_line_node);
|
|
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);
|
|
}
|
|
Setattr(p, "lname", lname);
|
|
p = nextSibling(p);
|
|
}
|
|
Delete(empty_string);
|
|
}
|
|
|
|
/* process optional extra parameters - the override variable replacements (undocumented) */
|
|
override_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, (int)(eq - c));
|
|
String *value = NewString(eq + 1);
|
|
Insert(name, 0, "$");
|
|
Setattr(override_vars, name, value);
|
|
} else {
|
|
to_match_parms = 0; /* error - variable replacement parameters must be of form varname=value */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Perform a typemap search */
|
|
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
|
|
if (already_substituting < 10) {
|
|
char* found_colon;
|
|
already_substituting++;
|
|
if ((in_typemap_search_multi == 0) && typemap_search_debug) {
|
|
String *dtypemap = NewString(dollar_typemap);
|
|
Replaceall(dtypemap, "$TYPEMAP", "$typemap");
|
|
Printf(stdout, " Containing: %s\n", dtypemap);
|
|
Delete(dtypemap);
|
|
}
|
|
found_colon = Strchr(tmap_method, ':');
|
|
if (found_colon) {
|
|
/* Substitute from a keyword argument to a typemap. Avoid emitting local variables from the attached typemap by passing NULL for the file. */
|
|
String *temp_tmap_method = NewStringWithSize(Char(tmap_method), (int)(found_colon - Char(tmap_method)));
|
|
typemap_attach_parms(temp_tmap_method, to_match_parms, NULL, override_vars);
|
|
Delete(temp_tmap_method);
|
|
} else {
|
|
typemap_attach_parms(tmap_method, to_match_parms, f, override_vars);
|
|
}
|
|
already_substituting--;
|
|
|
|
/* Look for the typemap code */
|
|
attr = NewStringf("tmap:%s", tmap_method);
|
|
tm = Getattr(to_match_parms, attr);
|
|
if (tm) {
|
|
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(override_vars); ki.key; ki = Next(ki)) {
|
|
Replace(tm, ki.key, ki.item, 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) {
|
|
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 to prevent infinite recursion - this strategy only allows a limited
|
|
* number of calls by a embedded typemaps to other embedded typemaps though */
|
|
String *dtypemap = NewString(dollar_typemap);
|
|
Replaceall(dtypemap, "$TYPEMAP", "$typemap");
|
|
Swig_error(Getfile(s), Getline(s), "Likely recursive $typemap calls containing %s. Use -debug-tmsearch to debug.\n", dtypemap);
|
|
Delete(dtypemap);
|
|
}
|
|
syntax_error = 0;
|
|
}
|
|
Delete(override_vars);
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_debug()
|
|
*
|
|
* Display all typemaps
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_debug(void) {
|
|
int nesting_level = 2;
|
|
Printf(stdout, "---[ typemaps ]--------------------------------------------------------------\n");
|
|
Swig_print(typemaps, nesting_level);
|
|
Printf(stdout, "-----------------------------------------------------------------------------\n");
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_search_debug_set()
|
|
*
|
|
* Turn on typemap searching debug display
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_search_debug_set(void) {
|
|
typemap_search_debug = 1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_used_debug_set()
|
|
*
|
|
* Turn on typemaps used debug display
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_used_debug_set(void) {
|
|
typemaps_used_debug = 1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_register_debug_set()
|
|
*
|
|
* Turn on typemaps used debug display
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_register_debug_set(void) {
|
|
typemap_register_debug = 1;
|
|
}
|
|
|