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