/* ----------------------------------------------------------------------------- * 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[] = "$Header: /cvsroot/swig/SWIG/Source/Swig/typemap.c,v 1.72 2006/11/01 23:54:54 wsfulton Exp $"; #include "swig.h" #include "swigkeys.h" #include "cparse.h" #include #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, "", 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"); }