git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@9604 626c5289-ae23-0410-ae9c-e8d60b6d4f22
1901 lines
48 KiB
C
1901 lines
48 KiB
C
/* -----------------------------------------------------------------------------
|
|
* See the LICENSE file for information on copyright, usage and redistribution
|
|
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
|
|
*
|
|
* typemap.c
|
|
*
|
|
* A somewhat generalized implementation of SWIG1.1 typemaps.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
char cvsroot_typemap_c[] = "$Id$";
|
|
|
|
#include "swig.h"
|
|
#include "swigkeys.h"
|
|
#include "cparse.h"
|
|
#include <ctype.h>
|
|
|
|
#if 0
|
|
#define SWIG_DEBUG
|
|
#endif
|
|
|
|
static void replace_embedded_typemap(String *s);
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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 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)
|
|
*
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#define MAX_SCOPE 32
|
|
|
|
|
|
static Hash *typemaps[MAX_SCOPE];
|
|
static int tm_scope = 0;
|
|
|
|
static Hash *get_typemap(int tm_scope, SwigType *type) {
|
|
Hash *tm = 0;
|
|
SwigType *dtype = 0;
|
|
if (SwigType_istemplate(type)) {
|
|
String *ty = Swig_symbol_template_deftype(type, 0);
|
|
dtype = Swig_symbol_type_qualify(ty, 0);
|
|
/* Printf(stderr,"gettm %s %s\n", type, dtype); */
|
|
type = dtype;
|
|
Delete(ty);
|
|
}
|
|
tm = Getattr(typemaps[tm_scope], type);
|
|
|
|
|
|
if (dtype) {
|
|
if (!tm) {
|
|
String *t_name = SwigType_templateprefix(type);
|
|
if (!Equal(t_name, type)) {
|
|
tm = Getattr(typemaps[tm_scope], t_name);
|
|
}
|
|
Delete(t_name);
|
|
}
|
|
Delete(dtype);
|
|
}
|
|
|
|
return tm;
|
|
}
|
|
|
|
static void set_typemap(int tm_scope, SwigType *type, Hash *tm) {
|
|
SwigType *dtype = 0;
|
|
if (SwigType_istemplate(type)) {
|
|
String *ty = Swig_symbol_template_deftype(type, 0);
|
|
dtype = Swig_symbol_type_qualify(ty, 0);
|
|
/* Printf(stderr,"settm %s %s\n", type, dtype); */
|
|
type = dtype;
|
|
Delete(ty);
|
|
} else {
|
|
dtype = Copy(type);
|
|
type = dtype;
|
|
}
|
|
Setattr(typemaps[tm_scope], type, tm);
|
|
Delete(dtype);
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_init()
|
|
*
|
|
* Initialize the typemap system
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_init() {
|
|
int i;
|
|
for (i = 0; i < MAX_SCOPE; i++) {
|
|
typemaps[i] = 0;
|
|
}
|
|
typemaps[0] = NewHash();
|
|
tm_scope = 0;
|
|
}
|
|
|
|
static String *tmop_name(const String_or_char *op) {
|
|
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.
|
|
|
|
(Swig_typemap_attach_kwargs calls tmop_name several times with
|
|
the "same" String *op (i.e., same object identity) but differing
|
|
string values.)
|
|
|
|
Most other callers work around this by using char* rather than
|
|
String *.
|
|
-- mkoeppe, Jun 17, 2003
|
|
*/
|
|
const char *op_without_object_identity = Char(op);
|
|
if (!names)
|
|
names = NewHash();
|
|
s = Getattr(names, op_without_object_identity);
|
|
if (s)
|
|
return s;
|
|
s = NewStringf("tmap:%s", op);
|
|
Setattr(names, op_without_object_identity, s);
|
|
Delete(s);
|
|
return s;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_new_scope()
|
|
*
|
|
* Create a new typemap scope
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_new_scope() {
|
|
tm_scope++;
|
|
typemaps[tm_scope] = NewHash();
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_pop_scope()
|
|
*
|
|
* Pop the last typemap scope off
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
Hash *Swig_typemap_pop_scope() {
|
|
if (tm_scope > 0) {
|
|
return typemaps[tm_scope--];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_register()
|
|
*
|
|
* Add a new multi-valued typemap
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_register(const String_or_char *op, ParmList *parms, String_or_char *code, ParmList *locals, ParmList *kwargs) {
|
|
Hash *tm;
|
|
Hash *tm1;
|
|
Hash *tm2;
|
|
Parm *np;
|
|
String *tmop;
|
|
SwigType *type;
|
|
String *pname;
|
|
|
|
if (!parms)
|
|
return;
|
|
tmop = tmop_name(op);
|
|
|
|
/* Register the first type in the parameter list */
|
|
|
|
type = Getattr(parms, k_type);
|
|
pname = Getattr(parms, k_name);
|
|
|
|
/* See if this type has been seen before */
|
|
tm = get_typemap(tm_scope, type);
|
|
if (!tm) {
|
|
tm = NewHash();
|
|
set_typemap(tm_scope, type, tm);
|
|
Delete(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 op has been seen before */
|
|
tm2 = Getattr(tm, tmop);
|
|
if (!tm2) {
|
|
tm2 = NewHash();
|
|
Setattr(tm, tmop, tm2);
|
|
Delete(tm2);
|
|
}
|
|
|
|
/* For a multi-valued 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.
|
|
|
|
For example, consider this typemap
|
|
|
|
%typemap(in) (int foo, int *bar, char *blah[]) {
|
|
...
|
|
}
|
|
|
|
To store it, we look at typemaps for the following:
|
|
|
|
operator type-name
|
|
----------------------------------------------
|
|
"in" int foo
|
|
"in-int+foo:" int *bar
|
|
"in-int+foo:-p.int+bar: char *blah[]
|
|
|
|
Notice how the operator expands to encode information about
|
|
previous arguments.
|
|
|
|
*/
|
|
|
|
np = nextSibling(parms);
|
|
if (np) {
|
|
/* Make an entirely new operator key */
|
|
String *newop = NewStringf("%s-%s+%s:", op, type, pname);
|
|
/* Now reregister on the remaining arguments */
|
|
Swig_typemap_register(newop, np, code, locals, kwargs);
|
|
|
|
/* Setattr(tm2,newop,newop); */
|
|
Delete(newop);
|
|
} else {
|
|
String *str = SwigType_str(type, pname);
|
|
String *typemap = NewStringf("typemap(%s) %s", op, str);
|
|
ParmList *clocals = CopyParmList(locals);
|
|
ParmList *ckwargs = CopyParmList(kwargs);
|
|
|
|
Setattr(tm2, k_code, code);
|
|
Setattr(tm2, k_type, type);
|
|
Setattr(tm2, k_typemap, typemap);
|
|
if (pname) {
|
|
Setattr(tm2, k_pname, pname);
|
|
}
|
|
Setattr(tm2, k_locals, clocals);
|
|
Setattr(tm2, k_kwargs, ckwargs);
|
|
|
|
Delete(clocals);
|
|
Delete(ckwargs);
|
|
|
|
Delete(str);
|
|
Delete(typemap);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_get()
|
|
*
|
|
* Retrieve typemap information from current scope.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Hash *Swig_typemap_get(SwigType *type, String_or_char *name, int scope) {
|
|
Hash *tm, *tm1;
|
|
/* See if this type has been seen before */
|
|
if ((scope < 0) || (scope > tm_scope))
|
|
return 0;
|
|
tm = get_typemap(scope, 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 *op, ParmList *srcparms, ParmList *parms) {
|
|
Hash *tm = 0;
|
|
String *tmop;
|
|
Parm *p;
|
|
String *pname;
|
|
SwigType *ptype;
|
|
int ts = tm_scope;
|
|
String *tmops, *newop;
|
|
if (ParmList_len(parms) != ParmList_len(srcparms))
|
|
return -1;
|
|
|
|
tmop = tmop_name(op);
|
|
while (ts >= 0) {
|
|
p = srcparms;
|
|
tmops = NewString(tmop);
|
|
while (p) {
|
|
ptype = Getattr(p, k_type);
|
|
pname = Getattr(p, k_name);
|
|
|
|
/* Lookup the type */
|
|
tm = Swig_typemap_get(ptype, pname, ts);
|
|
if (!tm)
|
|
break;
|
|
|
|
tm = Getattr(tm, tmops);
|
|
if (!tm)
|
|
break;
|
|
|
|
/* Got a match. Look for next typemap */
|
|
newop = NewStringf("%s-%s+%s:", tmops, ptype, pname);
|
|
Delete(tmops);
|
|
tmops = newop;
|
|
p = nextSibling(p);
|
|
}
|
|
Delete(tmops);
|
|
|
|
if (!p && tm) {
|
|
|
|
/* Got some kind of match */
|
|
Swig_typemap_register(op, parms, Getattr(tm, k_code), Getattr(tm, k_locals), Getattr(tm, k_kwargs));
|
|
return 0;
|
|
}
|
|
ts--;
|
|
}
|
|
/* Not found */
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_clear()
|
|
*
|
|
* Delete a multi-valued typemap
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_clear(const String_or_char *op, ParmList *parms) {
|
|
SwigType *type;
|
|
String *name;
|
|
Parm *p;
|
|
String *newop;
|
|
Hash *tm = 0;
|
|
|
|
/* This might not work */
|
|
newop = NewString(op);
|
|
p = parms;
|
|
while (p) {
|
|
type = Getattr(p, k_type);
|
|
name = Getattr(p, k_name);
|
|
tm = Swig_typemap_get(type, name, tm_scope);
|
|
if (!tm)
|
|
return;
|
|
p = nextSibling(p);
|
|
if (p)
|
|
Printf(newop, "-%s+%s:", type, name);
|
|
}
|
|
if (tm) {
|
|
tm = Getattr(tm, tmop_name(newop));
|
|
if (tm) {
|
|
Delattr(tm, k_code);
|
|
Delattr(tm, k_locals);
|
|
Delattr(tm, k_kwargs);
|
|
}
|
|
}
|
|
Delete(newop);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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;
|
|
int ts = tm_scope;
|
|
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, k_type), Getattr(p, k_name));
|
|
Printf(dsig, "-%s+%s:", Getattr(dp, k_type), Getattr(dp, k_name));
|
|
narg++;
|
|
}
|
|
p = np;
|
|
dp = nextSibling(dp);
|
|
}
|
|
|
|
/* make sure a typemap node exists for the last destination node */
|
|
type = Getattr(lastdp, k_type);
|
|
tm = get_typemap(tm_scope, type);
|
|
if (!tm) {
|
|
tm = NewHash();
|
|
set_typemap(tm_scope, type, tm);
|
|
Delete(tm);
|
|
}
|
|
name = Getattr(lastdp, k_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, k_type);
|
|
name = Getattr(lastp, k_name);
|
|
|
|
while (ts >= 0) {
|
|
|
|
/* See if there is a matching typemap in this scope */
|
|
sm = Swig_typemap_get(type, name, ts);
|
|
|
|
/* 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 = Swig_typemap_get(ntype, name, ts);
|
|
}
|
|
Delete(ntype);
|
|
}
|
|
|
|
if (sm) {
|
|
/* Got a typemap. Need to only merge attributes for methods that match our signature */
|
|
Iterator ki;
|
|
match = 1;
|
|
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, k_code))) {
|
|
String *code;
|
|
ParmList *locals;
|
|
ParmList *kwargs;
|
|
Hash *sm1 = ki.item;
|
|
|
|
code = Getattr(sm1, k_code);
|
|
locals = Getattr(sm1, k_locals);
|
|
kwargs = Getattr(sm1, k_kwargs);
|
|
if (code) {
|
|
Replace(nkey, dsig, "", DOH_REPLACE_ANY);
|
|
Replace(nkey, "tmap:", "", DOH_REPLACE_ANY);
|
|
Swig_typemap_register(nkey, dest, code, locals, kwargs);
|
|
}
|
|
}
|
|
Delete(nkey);
|
|
}
|
|
}
|
|
}
|
|
ts--;
|
|
}
|
|
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, k_type), Getattr(p, k_name));
|
|
narg++;
|
|
}
|
|
p = np;
|
|
}
|
|
tm = get_typemap(tm_scope, Getattr(lastp, k_type));
|
|
if (!tm) {
|
|
Delete(tsig);
|
|
return;
|
|
}
|
|
name = Getattr(lastp, k_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;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_search()
|
|
*
|
|
* Search for a typemap match. Tries to find the most specific typemap
|
|
* that includes a 'code' attribute.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
Hash *Swig_typemap_search(const String_or_char *op, SwigType *type, const String_or_char *name, SwigType **matchtype) {
|
|
Hash *result = 0, *tm, *tm1, *tma;
|
|
Hash *backup = 0;
|
|
SwigType *noarrays = 0;
|
|
SwigType *primitive = 0;
|
|
SwigType *ctype = 0;
|
|
int ts;
|
|
int isarray;
|
|
const String *cname = 0;
|
|
SwigType *unstripped = 0;
|
|
String *tmop = tmop_name(op);
|
|
|
|
if ((name) && Len(name))
|
|
cname = name;
|
|
ts = tm_scope;
|
|
|
|
while (ts >= 0) {
|
|
ctype = type;
|
|
while (ctype) {
|
|
/* Try to get an exact type-match */
|
|
tm = get_typemap(ts, ctype);
|
|
if (tm && cname) {
|
|
tm1 = Getattr(tm, cname);
|
|
if (tm1) {
|
|
result = Getattr(tm1, tmop); /* See if there is a type-name match */
|
|
if (result && Getattr(result, k_code))
|
|
goto ret_result;
|
|
if (result)
|
|
backup = result;
|
|
}
|
|
}
|
|
if (tm) {
|
|
result = Getattr(tm, tmop); /* See if there is simply a type match */
|
|
if (result && Getattr(result, k_code))
|
|
goto ret_result;
|
|
if (result)
|
|
backup = result;
|
|
}
|
|
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 */
|
|
if (!noarrays) {
|
|
noarrays = strip_arrays(ctype);
|
|
}
|
|
tma = get_typemap(ts, noarrays);
|
|
if (tma && cname) {
|
|
tm1 = Getattr(tma, cname);
|
|
if (tm1) {
|
|
result = Getattr(tm1, tmop); /* type-name match */
|
|
if (result && Getattr(result, k_code))
|
|
goto ret_result;
|
|
if (result)
|
|
backup = result;
|
|
}
|
|
}
|
|
if (tma) {
|
|
result = Getattr(tma, tmop); /* type match */
|
|
if (result && Getattr(result, k_code))
|
|
goto ret_result;
|
|
if (result)
|
|
backup = result;
|
|
}
|
|
Delete(noarrays);
|
|
noarrays = 0;
|
|
}
|
|
|
|
/* No match so far. If the type is unstripped, we'll strip its
|
|
qualifiers and check. Otherwise, we'll try to resolve a typedef */
|
|
|
|
if (!unstripped) {
|
|
unstripped = ctype;
|
|
ctype = SwigType_strip_qualifiers(ctype);
|
|
if (!StringEqual(ctype, unstripped))
|
|
continue; /* Types are different */
|
|
Delete(ctype);
|
|
ctype = unstripped;
|
|
unstripped = 0;
|
|
}
|
|
{
|
|
String *octype;
|
|
if (unstripped) {
|
|
Delete(ctype);
|
|
ctype = unstripped;
|
|
unstripped = 0;
|
|
}
|
|
octype = ctype;
|
|
ctype = SwigType_typedef_resolve(ctype);
|
|
if (octype != type)
|
|
Delete(octype);
|
|
}
|
|
}
|
|
|
|
/* Hmmm. Well, no match seems to be found at all. See if there is some kind of default mapping */
|
|
|
|
primitive = SwigType_default(type);
|
|
while (primitive) {
|
|
tm = get_typemap(ts, primitive);
|
|
if (tm && cname) {
|
|
tm1 = Getattr(tm, cname);
|
|
if (tm1) {
|
|
result = Getattr(tm1, tmop); /* See if there is a type-name match */
|
|
if (result)
|
|
goto ret_result;
|
|
}
|
|
}
|
|
if (tm) { /* See if there is simply a type match */
|
|
result = Getattr(tm, tmop);
|
|
if (result)
|
|
goto ret_result;
|
|
}
|
|
{
|
|
SwigType *nprim = SwigType_default(primitive);
|
|
Delete(primitive);
|
|
primitive = nprim;
|
|
}
|
|
}
|
|
if (ctype != type) {
|
|
Delete(ctype);
|
|
ctype = 0;
|
|
}
|
|
ts--; /* Hmmm. Nothing found in this scope. Guess we'll go try another scope */
|
|
}
|
|
result = backup;
|
|
|
|
ret_result:
|
|
if (noarrays)
|
|
Delete(noarrays);
|
|
if (primitive)
|
|
Delete(primitive);
|
|
if ((unstripped) && (unstripped != type))
|
|
Delete(unstripped);
|
|
if (matchtype) {
|
|
*matchtype = Copy(ctype);
|
|
}
|
|
if (type != ctype)
|
|
Delete(ctype);
|
|
return result;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_search_multi()
|
|
*
|
|
* Search for a multi-valued typemap.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
Hash *Swig_typemap_search_multi(const String_or_char *op, ParmList *parms, int *nmatch) {
|
|
SwigType *type;
|
|
SwigType *mtype = 0;
|
|
String *name;
|
|
String *newop;
|
|
Hash *tm, *tm1;
|
|
|
|
if (!parms) {
|
|
*nmatch = 0;
|
|
return 0;
|
|
}
|
|
type = Getattr(parms, k_type);
|
|
name = Getattr(parms, k_name);
|
|
|
|
/* Try to find a match on the first type */
|
|
tm = Swig_typemap_search(op, type, name, &mtype);
|
|
if (tm) {
|
|
if (mtype && SwigType_isarray(mtype)) {
|
|
Setattr(parms, k_tmapmatch, mtype);
|
|
}
|
|
Delete(mtype);
|
|
newop = NewStringf("%s-%s+%s:", op, type, name);
|
|
tm1 = Swig_typemap_search_multi(newop, nextSibling(parms), nmatch);
|
|
if (tm1)
|
|
tm = tm1;
|
|
if (Getattr(tm, k_code)) {
|
|
*(nmatch) = *nmatch + 1;
|
|
} else {
|
|
tm = 0;
|
|
}
|
|
Delete(newop);
|
|
}
|
|
return tm;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* typemap_replace_vars()
|
|
*
|
|
* Replaces typemap variables on a string. index is the $n variable.
|
|
* type and pname are the type and parameter name.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static
|
|
void replace_local_types(ParmList *p, const String *name, const String *rep) {
|
|
SwigType *t;
|
|
while (p) {
|
|
t = Getattr(p, k_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
|
|
void typemap_replace_vars(String *s, ParmList *locals, SwigType *type, SwigType *rtype, String *pname, String *lname, int index) {
|
|
char var[512];
|
|
char *varname;
|
|
SwigType *ftype;
|
|
|
|
Replaceall(s, "$typemap", "$TYPEMAP");
|
|
|
|
ftype = SwigType_typedef_resolve_all(type);
|
|
|
|
if (!pname)
|
|
pname = lname;
|
|
{
|
|
Parm *p;
|
|
int rep = 0;
|
|
p = locals;
|
|
while (p) {
|
|
if (Strchr(Getattr(p, k_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;
|
|
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))) {
|
|
if (!(SwigType_isarray(type) || SwigType_ispointer(type) || SwigType_isreference(type))) {
|
|
star_type = Copy(ftype);
|
|
} else {
|
|
star_type = Copy(type);
|
|
}
|
|
if (!SwigType_isreference(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)) {
|
|
SwigType *bt = Copy(type);
|
|
Delete(SwigType_pop_arrays(bt));
|
|
base_type = SwigType_str(bt, 0);
|
|
Delete(bt);
|
|
} else {
|
|
base_type = SwigType_base(type);
|
|
}
|
|
|
|
base_name = SwigType_namestr(base_type);
|
|
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, 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_type);
|
|
Delete(base_name);
|
|
|
|
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 any $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);
|
|
Replace(s, var, lname, DOH_REPLACE_ANY);
|
|
Delete(ftype);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
* static typemap_locals()
|
|
*
|
|
* Takes a string, a parameter list and a wrapper function argument and
|
|
* creates the local variables.
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
static void typemap_locals(DOHString * s, ParmList *l, Wrapper *f, int argnum) {
|
|
Parm *p;
|
|
char *new_name;
|
|
|
|
p = l;
|
|
while (p) {
|
|
SwigType *pt = Getattr(p, k_type);
|
|
SwigType *at = SwigType_alttype(pt, 1);
|
|
String *pn = Getattr(p, k_name);
|
|
String *value = Getattr(p, k_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 {
|
|
StringAppend(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);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_lookup()
|
|
*
|
|
* Perform a typemap lookup (ala SWIG1.1)
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_typemap_lookup(const String_or_char *op, SwigType *type, String_or_char *pname,
|
|
String_or_char *lname, String_or_char *source, String_or_char *target, Wrapper *f) {
|
|
Hash *tm;
|
|
String *s = 0;
|
|
SwigType *mtype = 0;
|
|
ParmList *locals;
|
|
tm = Swig_typemap_search(op, type, pname, &mtype);
|
|
if (!tm)
|
|
return 0;
|
|
|
|
s = Getattr(tm, k_code);
|
|
if (!s) {
|
|
if (mtype)
|
|
Delete(mtype);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Blocked */
|
|
if (Cmp(s, "pass") == 0) {
|
|
Delete(mtype);
|
|
return 0;
|
|
}
|
|
|
|
s = Copy(s); /* Make a local copy of the typemap code */
|
|
|
|
locals = Getattr(tm, k_locals);
|
|
if (locals)
|
|
locals = CopyParmList(locals);
|
|
|
|
/* This is wrong. It replaces locals in place. Need to fix this */
|
|
if (mtype && SwigType_isarray(mtype)) {
|
|
typemap_replace_vars(s, locals, mtype, type, pname, lname, 1);
|
|
} else {
|
|
typemap_replace_vars(s, locals, type, type, pname, lname, 1);
|
|
}
|
|
|
|
if (locals && f) {
|
|
typemap_locals(s, locals, f, -1);
|
|
}
|
|
|
|
replace_embedded_typemap(s);
|
|
|
|
/* Now perform character replacements */
|
|
Replace(s, "$source", source, DOH_REPLACE_ANY);
|
|
Replace(s, "$target", target, DOH_REPLACE_ANY);
|
|
|
|
/* {
|
|
String *tmname = Getattr(tm,"typemap");
|
|
if (tmname) Replace(s,"$typemap",tmname, DOH_REPLACE_ANY);
|
|
}
|
|
*/
|
|
|
|
Replace(s, "$parmname", pname, DOH_REPLACE_ANY);
|
|
/* Replace(s,"$name",pname,DOH_REPLACE_ANY); */
|
|
|
|
Delete(locals);
|
|
Delete(mtype);
|
|
return s;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_lookup_new()
|
|
*
|
|
* Attach one or more typemaps to a node
|
|
* op - typemap name, eg "out", "newfree"
|
|
* node - the node to attach the typemaps to
|
|
* lname -
|
|
* f -
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_typemap_lookup_new(const String_or_char *op, Node *node, const String_or_char *lname, Wrapper *f) {
|
|
SwigType *type;
|
|
SwigType *mtype = 0;
|
|
String *pname;
|
|
Hash *tm = 0;
|
|
String *s = 0;
|
|
String *sdef = 0;
|
|
ParmList *locals;
|
|
ParmList *kw;
|
|
char temp[256];
|
|
String *symname;
|
|
String *cname = 0;
|
|
String *clname = 0;
|
|
char *cop = Char(op);
|
|
/* special case, we need to check for 'ref' call
|
|
and set the default code 'sdef' */
|
|
if (Cmp(op, "newfree") == 0) {
|
|
sdef = Swig_ref_call(node, lname);
|
|
}
|
|
|
|
type = Getattr(node, k_type);
|
|
if (!type)
|
|
return sdef;
|
|
|
|
pname = Getattr(node, k_name);
|
|
|
|
#if 1
|
|
if (pname && node && checkAttribute(node, k_kind, "function")) {
|
|
/*
|
|
For functions, look qualified names first, such as
|
|
|
|
struct Foo {
|
|
int *foo(int bar) -> Foo::foo
|
|
};
|
|
*/
|
|
Symtab *st = Getattr(node, k_symsymtab);
|
|
String *qsn = st ? Swig_symbol_string_qualify(pname, st) : 0;
|
|
if (qsn) {
|
|
if (StringLen(qsn) && !Equal(qsn, pname)) {
|
|
tm = Swig_typemap_search(op, type, qsn, &mtype);
|
|
if (tm && (!Getattr(tm, k_pname) || strstr(Char(Getattr(tm, k_type)), "SWIGTYPE"))) {
|
|
tm = 0;
|
|
}
|
|
}
|
|
Delete(qsn);
|
|
}
|
|
}
|
|
if (!tm)
|
|
#endif
|
|
tm = Swig_typemap_search(op, type, pname, &mtype);
|
|
if (!tm)
|
|
return sdef;
|
|
|
|
s = Getattr(tm, k_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 */
|
|
|
|
locals = Getattr(tm, k_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;
|
|
}
|
|
|
|
if (mtype && SwigType_isarray(mtype)) {
|
|
typemap_replace_vars(s, locals, mtype, type, pname, (char *) lname, 1);
|
|
} else {
|
|
typemap_replace_vars(s, locals, type, type, pname, (char *) lname, 1);
|
|
}
|
|
|
|
if (locals && f) {
|
|
typemap_locals(s, locals, f, -1);
|
|
}
|
|
replace_embedded_typemap(s);
|
|
/* {
|
|
String *tmname = Getattr(tm,"typemap");
|
|
if (tmname) Replace(s,"$typemap",tmname, DOH_REPLACE_ANY);
|
|
} */
|
|
|
|
Replace(s, "$name", pname, DOH_REPLACE_ANY);
|
|
|
|
symname = Getattr(node, k_symname);
|
|
if (symname) {
|
|
Replace(s, "$symname", symname, DOH_REPLACE_ANY);
|
|
}
|
|
|
|
Setattr(node, tmop_name(op), s);
|
|
if (locals) {
|
|
sprintf(temp, "%s:locals", cop);
|
|
Setattr(node, tmop_name(temp), locals);
|
|
Delete(locals);
|
|
}
|
|
|
|
if (HashCheckAttr(tm, k_type, k_SWIGTYPE)) {
|
|
sprintf(temp, "%s:SWIGTYPE", cop);
|
|
Setattr(node, tmop_name(temp), k_1);
|
|
}
|
|
|
|
/* Attach kwargs */
|
|
kw = Getattr(tm, k_kwargs);
|
|
while (kw) {
|
|
String *value = Copy(Getattr(kw, k_value));
|
|
String *type = Getattr(kw, k_type);
|
|
char *ckwname = Char(Getattr(kw, k_name));
|
|
if (type) {
|
|
String *mangle = Swig_string_mangle(type);
|
|
StringAppend(value, mangle);
|
|
Delete(mangle);
|
|
}
|
|
sprintf(temp, "%s:%s", cop, ckwname);
|
|
Setattr(node, tmop_name(temp), value);
|
|
Delete(value);
|
|
kw = nextSibling(kw);
|
|
}
|
|
|
|
/* Look for warnings */
|
|
{
|
|
String *w;
|
|
sprintf(temp, "%s:warning", cop);
|
|
w = Getattr(node, tmop_name(temp));
|
|
if (w) {
|
|
Swig_warning(0, Getfile(node), Getline(node), "%s\n", w);
|
|
}
|
|
}
|
|
|
|
/* Look for code fragments */
|
|
{
|
|
String *f;
|
|
sprintf(temp, "%s:fragment", cop);
|
|
f = Getattr(node, tmop_name(temp));
|
|
if (f) {
|
|
String *fname = Copy(f);
|
|
Setfile(fname, Getfile(node));
|
|
Setline(fname, Getline(node));
|
|
Swig_fragment_emit(fname);
|
|
Delete(fname);
|
|
}
|
|
}
|
|
|
|
if (cname)
|
|
Delete(cname);
|
|
if (clname)
|
|
Delete(clname);
|
|
if (mtype)
|
|
Delete(mtype);
|
|
if (sdef) { /* put 'ref' and 'newfree' codes together */
|
|
String *p = NewStringf("%s\n%s", sdef, s);
|
|
Delete(s);
|
|
Delete(sdef);
|
|
s = p;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_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 p:
|
|
* %typemap(in, foo="xyz") ...
|
|
* A new attribute called "tmap:in:foo" with value "xyz" is attached to p.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_attach_kwargs(Hash *tm, const String_or_char *op, Parm *p) {
|
|
String *temp = NewStringEmpty();
|
|
Parm *kw = Getattr(tm, k_kwargs);
|
|
while (kw) {
|
|
String *value = Copy(Getattr(kw, k_value));
|
|
String *type = Getattr(kw, k_type);
|
|
if (type) {
|
|
Hash *v = NewHash();
|
|
Setattr(v, k_type, type);
|
|
Setattr(v, k_value, value);
|
|
Delete(value);
|
|
value = v;
|
|
}
|
|
Clear(temp);
|
|
Printf(temp, "%s:%s", op, Getattr(kw, k_name));
|
|
Setattr(p, tmop_name(temp), value);
|
|
Delete(value);
|
|
kw = nextSibling(kw);
|
|
}
|
|
Clear(temp);
|
|
Printf(temp, "%s:match_type", op);
|
|
Setattr(p, tmop_name(temp), Getattr(tm, k_type));
|
|
Delete(temp);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_warn()
|
|
*
|
|
* If any warning message is attached to this parameter's "tmap:op:warning"
|
|
* attribute, print that warning message.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void Swig_typemap_warn(const String_or_char *op, Parm *p) {
|
|
String *temp = NewStringf("%s:warning", op);
|
|
String *w = Getattr(p, tmop_name(temp));
|
|
Delete(temp);
|
|
if (w) {
|
|
Swig_warning(0, Getfile(p), Getline(p), "%s\n", w);
|
|
}
|
|
}
|
|
|
|
static void Swig_typemap_emit_code_fragments(const String_or_char *op, Parm *p) {
|
|
String *temp = NewStringf("%s:fragment", op);
|
|
String *f = Getattr(p, tmop_name(temp));
|
|
if (f) {
|
|
String *fname = Copy(f);
|
|
Setfile(fname, Getfile(p));
|
|
Setline(fname, Getline(p));
|
|
Swig_fragment_emit(fname);
|
|
Delete(fname);
|
|
}
|
|
Delete(temp);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_attach_parms()
|
|
*
|
|
* Given a parameter list, this function attaches all of the typemaps for a
|
|
* given typemap type
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *Swig_typemap_get_option(Hash *tm, String *name) {
|
|
Parm *kw = Getattr(tm, k_kwargs);
|
|
while (kw) {
|
|
String *kname = Getattr(kw, k_name);
|
|
if (Equal(kname, name)) {
|
|
return Getattr(kw, k_value);
|
|
}
|
|
kw = nextSibling(kw);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Swig_typemap_attach_parms(const String_or_char *op, ParmList *parms, Wrapper *f) {
|
|
Parm *p, *firstp;
|
|
Hash *tm;
|
|
int nmatch = 0;
|
|
int i;
|
|
String *s;
|
|
ParmList *locals;
|
|
int argnum = 0;
|
|
char temp[256];
|
|
char *cop = Char(op);
|
|
String *kwmatch = 0;
|
|
p = parms;
|
|
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "Swig_typemap_attach_parms: %s\n", op);
|
|
#endif
|
|
|
|
while (p) {
|
|
argnum++;
|
|
nmatch = 0;
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "parms: %s %s %s\n", op, Getattr(p, k_name), Getattr(p, k_type));
|
|
#endif
|
|
tm = Swig_typemap_search_multi(op, 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 = Swig_typemap_get_option(tm, k_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, k_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 = Swig_typemap_search_multi(kwmatch, p, &nnmatch);
|
|
String *tmname = Getattr(tm, k_pname);
|
|
String *tnname = Getattr(tmapin, k_pname);
|
|
if (!(tmname && tnname && Equal(tmname, tnname)) && !(!tmname && !tnname)) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
s = Getattr(tm, k_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, k_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;
|
|
String *pname;
|
|
String *lname;
|
|
SwigType *mtype;
|
|
|
|
|
|
type = Getattr(p, k_type);
|
|
pname = Getattr(p, k_name);
|
|
lname = Getattr(p, k_lname);
|
|
mtype = Getattr(p, k_tmapmatch);
|
|
|
|
if (mtype) {
|
|
typemap_replace_vars(s, locals, mtype, type, pname, lname, i + 1);
|
|
Delattr(p, k_tmapmatch);
|
|
} else {
|
|
typemap_replace_vars(s, locals, type, type, pname, lname, i + 1);
|
|
}
|
|
|
|
if (HashCheckAttr(tm, k_type, k_SWIGTYPE)) {
|
|
sprintf(temp, "%s:SWIGTYPE", cop);
|
|
Setattr(p, tmop_name(temp), k_1);
|
|
}
|
|
p = nextSibling(p);
|
|
}
|
|
|
|
if (locals && f) {
|
|
typemap_locals(s, locals, f, argnum);
|
|
}
|
|
|
|
replace_embedded_typemap(s);
|
|
|
|
/* Replace the argument number */
|
|
sprintf(temp, "%d", argnum);
|
|
Replace(s, "$argnum", temp, DOH_REPLACE_ANY);
|
|
|
|
/* Attach attributes to object */
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, k_name), tmop_name(op), s);
|
|
#endif
|
|
Setattr(firstp, tmop_name(op), s); /* Code object */
|
|
|
|
if (locals) {
|
|
sprintf(temp, "%s:locals", cop);
|
|
Setattr(firstp, tmop_name(temp), locals);
|
|
Delete(locals);
|
|
}
|
|
|
|
/* Attach a link to the next parameter. Needed for multimaps */
|
|
sprintf(temp, "%s:next", cop);
|
|
Setattr(firstp, tmop_name(temp), p);
|
|
|
|
/* Attach kwargs */
|
|
Swig_typemap_attach_kwargs(tm, op, firstp);
|
|
|
|
/* Print warnings, if any */
|
|
Swig_typemap_warn(op, firstp);
|
|
|
|
/* Look for code fragments */
|
|
Swig_typemap_emit_code_fragments(op, firstp);
|
|
|
|
/* increase argnum to consider numinputs */
|
|
argnum += nmatch - 1;
|
|
Delete(s);
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "res: %s %s %s\n", Getattr(firstp, k_name), tmop_name(op), Getattr(firstp, tmop_name(op)));
|
|
#endif
|
|
|
|
}
|
|
#ifdef SWIG_DEBUG
|
|
Printf(stdout, "Swig_typemap_attach_parms: end\n");
|
|
#endif
|
|
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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) {
|
|
List *args = 0;
|
|
char *c, *start;
|
|
int level = 0;
|
|
int leading = 1;
|
|
args = NewList();
|
|
|
|
c = strchr(Char(s), '(');
|
|
c++;
|
|
|
|
start = c;
|
|
while (*c) {
|
|
if (*c == '\"') {
|
|
c++;
|
|
while (*c) {
|
|
if (*c == '\\') {
|
|
c++;
|
|
} else {
|
|
if (*c == '\"')
|
|
break;
|
|
}
|
|
c++;
|
|
}
|
|
}
|
|
if ((level == 0) && ((*c == ',') || (*c == ')'))) {
|
|
String *tmp = NewStringWithSize(start, c - start);
|
|
Append(args, tmp);
|
|
Delete(tmp);
|
|
start = c + 1;
|
|
leading = 1;
|
|
if (*c == ')')
|
|
break;
|
|
c++;
|
|
continue;
|
|
}
|
|
if (*c == '(')
|
|
level++;
|
|
if (*c == ')')
|
|
level--;
|
|
if (isspace((int) *c) && leading)
|
|
start++;
|
|
if (!isspace((int) *c))
|
|
leading = 0;
|
|
c++;
|
|
}
|
|
return args;
|
|
}
|
|
|
|
static void split_var(String *s, String **name, String **value) {
|
|
char *eq;
|
|
char *c;
|
|
|
|
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) {
|
|
char *start = 0;
|
|
while ((start = strstr(Char(s), "$TYPEMAP("))) {
|
|
|
|
/* Gather the argument */
|
|
char *end = 0, *c;
|
|
int level = 0;
|
|
String *tmp;
|
|
c = start;
|
|
while (*c) {
|
|
if (*c == '(')
|
|
level++;
|
|
if (*c == ')') {
|
|
level--;
|
|
if (level == 0) {
|
|
end = c + 1;
|
|
break;
|
|
}
|
|
}
|
|
c++;
|
|
}
|
|
if (end) {
|
|
tmp = NewStringWithSize(start, (end - start));
|
|
} else {
|
|
tmp = 0;
|
|
}
|
|
|
|
/* Got a substitution. Split it apart into pieces */
|
|
if (tmp) {
|
|
List *l;
|
|
Hash *vars;
|
|
String *method;
|
|
int i, ilen;
|
|
|
|
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);
|
|
}
|
|
|
|
method = Getitem(l, 0);
|
|
/* Generate the parameter list for matching typemaps */
|
|
|
|
{
|
|
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, k_lname, Getattr(p, k_name));
|
|
if (Getattr(p, k_value)) {
|
|
Setattr(p, k_name, Getattr(p, k_value));
|
|
}
|
|
if (!first)
|
|
first = p;
|
|
DohIncref(p);
|
|
Delattr(vars, temp);
|
|
} else {
|
|
break;
|
|
}
|
|
n++;
|
|
}
|
|
/* Perform a typemap search */
|
|
if (first) {
|
|
#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));
|
|
|
|
/* Look for the typemap code */
|
|
tm = Getattr(first, 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 */
|
|
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);
|
|
Delete(tm);
|
|
match = 1;
|
|
}
|
|
}
|
|
if (!match) {
|
|
Swig_error(Getfile(s), Getline(s), "No typemap found for %s\n", tmp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Replace(s, tmp, "<embedded typemap>", DOH_REPLACE_ANY);
|
|
Delete(vars);
|
|
Delete(tmp);
|
|
Delete(l);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Swig_typemap_debug()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void Swig_typemap_debug() {
|
|
int ts;
|
|
Printf(stdout, "---[ typemaps ]--------------------------------------------------------------\n");
|
|
|
|
ts = tm_scope;
|
|
while (ts >= 0) {
|
|
Printf(stdout, "::: scope %d\n\n", ts);
|
|
Printf(stdout, "%s\n", typemaps[ts]);
|
|
ts--;
|
|
}
|
|
Printf(stdout, "-----------------------------------------------------------------------------\n");
|
|
}
|