int Swig_MethodToFunction(Node *n, String *classname, int flags, SwigType *director_type, int is_director) {
  String *name, *qualifier;
  ParmList *parms;
  SwigType *type;
  Parm *p;
  String *self = 0;

  /* If smart pointer, change self dereferencing */
  if (flags & CWRAP_SMART_POINTER) {
    self = NewString("(*this)->");
  }

  /* If node is a member template expansion, we don't allow added code */
  if (Getattr(n, k_templatetype))
    flags &= ~(CWRAP_EXTEND);

  name = Getattr(n, k_name);
  qualifier = Getattr(n, k_qualifier);
  parms = CopyParmList(nonvoid_parms(Getattr(n, k_parms)));

  type = NewString(classname);
  if (qualifier) {
    SwigType_push(type, qualifier);
  }
  SwigType_add_pointer(type);
  p = NewParm(type, k_self);
  Setattr(p, k_self, "1");
  Setattr(p, k_hidden, "1");
  /*
     Disable the 'this' ownership in 'self' to manage inplace
     operations like:

     A& A::operator+=(int i) { ...; return *this;}

     Here the 'self' parameter ownership needs to be disabled since
     there could be two objects sharing the same 'this' pointer: the
     input and the result one. And worse, the pointer could be deleted
     in one of the objects (input), leaving the other (output) with
     just a seg. fault to happen.

     To avoid the previous problem, use

     %feature("self:disown") *::operator+=;
     %feature("new") *::operator+=;

     These two lines just transfer the ownership of the 'this' pointer
     from the input to the output wrapping object.

     This happens in python, but may also happens in other target
     languages.
   */
  if (GetFlag(n, "feature:self:disown")) {
    Setattr(p, k_wrapdisown, "1");
  }
  set_nextSibling(p, parms);
  Delete(type);

  /* Generate action code for the access */
  if (!(flags & CWRAP_EXTEND)) {
    String *explicit_qualifier = 0;
    String *call = 0;
    String *cres = 0;
    String *explicitcall_name = 0;
    int pure_virtual = !(Cmp(Getattr(n, k_storage), "virtual")) && !(Cmp(Getattr(n, k_value), "0"));

    /* Call the explicit method rather than allow for a polymorphic call */
    if ((flags & CWRAP_DIRECTOR_TWO_CALLS) || (flags & CWRAP_DIRECTOR_ONE_CALL)) {
      String *access = Getattr(n, "access");
      if (access && (Cmp(access, "protected") == 0)) {
	/* If protected access (can only be if a director method) then call the extra public accessor method (language module must provide this) */
	String *explicit_qualifier_tmp = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), k_qname));
	explicitcall_name = NewStringf("%sSwigPublic", name);
	explicit_qualifier = NewStringf("SwigDirector_%s", explicit_qualifier_tmp);
	Delete(explicit_qualifier_tmp);
      } else {
	explicit_qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), k_qname));
      }
    }

    call = Swig_cmethod_call(explicitcall_name ? explicitcall_name : name, p, self, explicit_qualifier, director_type);
    cres = Swig_cresult(Getattr(n, k_type), k_result, call);

    if (pure_virtual && is_director && (flags & CWRAP_DIRECTOR_TWO_CALLS)) {
      String *qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), k_qname));
      Delete(cres);
      cres = NewStringf("Swig::DirectorPureVirtualException::raise(\"%s::%s\");", qualifier, name);
      Delete(qualifier);
    }

    if (flags & CWRAP_DIRECTOR_TWO_CALLS) {
      /* Create two method calls, one to call the explicit method, the other a normal polymorphic function call */
      String *cres_both_calls = NewStringf("");
      String *call_extra = Swig_cmethod_call(name, p, self, 0, director_type);
      String *cres_extra = Swig_cresult(Getattr(n, k_type), k_result, call_extra);
      Printv(cres_both_calls, "if (upcall) {\n", cres, "\n", "} else {", cres_extra, "\n}", NIL);
      Setattr(n, k_wrapaction, cres_both_calls);
      Delete(cres_extra);
      Delete(call_extra);
      Delete(cres_both_calls);
    } else {
      Setattr(n, k_wrapaction, cres);
    }

    Delete(explicitcall_name);
    Delete(call);
    Delete(cres);
    Delete(explicit_qualifier);
  } else {
    /* Methods with default arguments are wrapped with additional methods for each default argument,
     * however, only one extra %extend method is generated. */

    String *defaultargs = Getattr(n, k_defaultargs);
    String *code = Getattr(n, k_code);
    String *cname = Getattr(n, k_classname) ? Getattr(n, k_classname) : classname;
    String *membername = Swig_name_member(cname, name);
    String *mangled = Swig_name_mangle(membername);
    int is_smart_pointer = flags & CWRAP_SMART_POINTER;

    type = Getattr(n, k_type);

    /* Check if the method is overloaded.   If so, and it has code attached, we append an extra suffix
       to avoid a name-clash in the generated wrappers.  This allows overloaded methods to be defined
       in C. */
    if (Getattr(n, k_symoverloaded) && code) {
      Append(mangled, Getattr(defaultargs ? defaultargs : n, k_symovername));
    }

    /* See if there is any code that we need to emit */
    if (!defaultargs && code && !is_smart_pointer) {
      Swig_add_extension_code(n, mangled, p, type, code, cparse_cplusplus, k_self);
    }
    if (is_smart_pointer) {
      int i = 0;
      Parm *pp = p;
      String *func = NewStringf("%s(", mangled);
      String *cres;

      if (Cmp(Getattr(n, k_storage), k_static) != 0) {
	String *pname = Swig_cparm_name(pp, i);
        String *ctname = SwigType_namestr(cname);
	String *fadd = NewStringf("(%s*)(%s)->operator ->()", ctname, pname);
	Append(func, fadd);
        Delete(ctname);
	Delete(fadd);
	Delete(pname);
	pp = nextSibling(pp);
	if (pp)
	  Append(func, ",");
      } else {
	pp = nextSibling(pp);
      }
      ++i;
      while (pp) {
	SwigType *pt = Getattr(pp, k_type);
	if ((SwigType_type(pt) != T_VOID)) {
	  String *pname = Swig_cparm_name(pp, i++);
	  String *rcaststr = SwigType_rcaststr(pt, pname);
	  Append(func, rcaststr);
	  Delete(rcaststr);
	  Delete(pname);
	  pp = nextSibling(pp);
	  if (pp)
	    Append(func, ",");
	}
      }
      Append(func, ")");
      cres = Swig_cresult(Getattr(n, k_type), k_result, func);
      Setattr(n, k_wrapaction, cres);
      Delete(cres);
    } else {
      String *call = Swig_cfunction_call(mangled, p);
      String *cres = Swig_cresult(Getattr(n, k_type), k_result, call);
      Setattr(n, k_wrapaction, cres);
      Delete(call);
      Delete(cres);
    }

    Delete(membername);
    Delete(mangled);
  }
  Setattr(n, k_parms, p);
  Delete(p);
  Delete(self);
  Delete(parms);
  return SWIG_OK;
}
int Swig_ConstructorToFunction(Node *n, String *classname, String *none_comparison, String *director_ctor, int cplus, int flags) {
  ParmList *parms;
  Parm *prefix_args;
  Parm *p;
  ParmList *directorparms;
  SwigType *type;
  Node *classNode;
  int use_director;

  classNode = Swig_methodclass(n);
  use_director = Swig_directorclass(n);

  parms = CopyParmList(nonvoid_parms(Getattr(n, k_parms)));

  /* Prepend the list of prefix_args (if any) */
  prefix_args = Getattr(n, k_directorprefixargs);
  if (prefix_args != NIL) {
    Parm *p2, *p3;

    directorparms = CopyParmList(prefix_args);
    for (p = directorparms; nextSibling(p); p = nextSibling(p));
    for (p2 = parms; p2; p2 = nextSibling(p2)) {
      p3 = CopyParm(p2);
      set_nextSibling(p, p3);
      Delete(p3);
      p = p3;
    }
  } else
    directorparms = parms;

  type = NewString(classname);
  SwigType_add_pointer(type);

  if (flags & CWRAP_EXTEND) {
    /* Constructors with default arguments are wrapped with additional constructor methods for each default argument,
     * however, only one extra %extend method is generated. */
    String *call;
    String *cres;
    String *defaultargs = Getattr(n, k_defaultargs);
    String *code = Getattr(n, k_code);
    String *membername = Swig_name_construct(classname);
    String *mangled = Swig_name_mangle(membername);

    /* Check if the constructor is overloaded.   If so, and it has code attached, we append an extra suffix
       to avoid a name-clash in the generated wrappers.  This allows overloaded constructors to be defined
       in C. */
    if (Getattr(n, k_symoverloaded) && code) {
      Append(mangled, Getattr(defaultargs ? defaultargs : n, k_symovername));
    }

    /* See if there is any code that we need to emit */
    if (!defaultargs && code) {
      Swig_add_extension_code(n, mangled, parms, type, code, cparse_cplusplus, k_self);
    }

    call = Swig_cfunction_call(mangled, parms);
    cres = Swig_cresult(type, k_result, call);
    Setattr(n, k_wrapaction, cres);
    Delete(cres);
    Delete(call);
    Delete(membername);
    Delete(mangled);
  } else {
    if (cplus) {
      /* if a C++ director class exists, create it rather than the original class */
      if (use_director) {
	Node *parent = Swig_methodclass(n);
	int abstract = Getattr(parent, k_abstract) != 0;
	String *name = Getattr(parent, k_symname);
	String *directorname = NewStringf("SwigDirector_%s", name);
	String *action = NewStringEmpty();
	String *tmp_none_comparison = Copy(none_comparison);
	String *director_call;
	String *nodirector_call;

	Replaceall(tmp_none_comparison, "$arg", "arg1");

	director_call = Swig_cppconstructor_director_call(directorname, directorparms);
	nodirector_call = Swig_cppconstructor_nodirector_call(classname, parms);

	if (abstract) {
	  /* whether or not the abstract class has been subclassed in python,
	   * create a director instance (there's no way to create a normal
	   * instance).  if any of the pure virtual methods haven't been
	   * implemented in the target language, calls to those methods will
	   * generate Swig::DirectorPureVirtualException exceptions.
	   */
	  String *cres = Swig_cresult(type, k_result, director_call);
	  Append(action, cres);
	  Delete(cres);
	} else {
	  /* (scottm): The code for creating a new director is now a string
	     template that gets passed in via the director_ctor argument.

	     $comparison : an 'if' comparison from none_comparison
	     $director_new: Call new for director class
	     $nondirector_new: Call new for non-director class
	   */
	  String *cres;
	  Append(action, director_ctor);
	  Replaceall(action, "$comparison", tmp_none_comparison);

	  cres = Swig_cresult(type, k_result, director_call);
	  Replaceall(action, "$director_new", cres);
	  Delete(cres);

	  cres = Swig_cresult(type, k_result, nodirector_call);
	  Replaceall(action, "$nondirector_new", cres);
	  Delete(cres);
	}
	Setattr(n, k_wrapaction, action);
	Delete(tmp_none_comparison);
	Delete(action);
	Delete(directorname);
      } else {
	String *call = Swig_cppconstructor_call(classname, parms);
	String *cres = Swig_cresult(type, k_result, call);
	Setattr(n, k_wrapaction, cres);
	Delete(cres);
	Delete(call);
      }
    } else {
      String *call = Swig_cconstructor_call(classname);
      String *cres = Swig_cresult(type, k_result, call);
      Setattr(n, k_wrapaction, cres);
      Delete(cres);
      Delete(call);
    }
  }
  Setattr(n, k_type, type);
  Setattr(n, k_parms, parms);
  Delete(type);
  if (directorparms != parms)
    Delete(directorparms);
  Delete(parms);
  return SWIG_OK;
}
Exemple #3
0
static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) {
  Node *n;
  String *tname, *rname = 0;
  Node *templ;
  List *mpartials = 0;
  Parm *p;
  Parm *parms;
  Parm *targs;
  ParmList *expandedparms;

  tname = Copy(name);
  parms = CopyParmList(tparms);

  /* Search for generic template */
  templ = Swig_symbol_clookup(name, 0);

  /* Add default values from generic template */
  if (templ) {
    Symtab *tsdecl = Getattr(templ, "sym:symtab");

    targs = Getattr(templ, "templateparms");
    expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, tsdecl);
  } else {
    expandedparms = parms;
  }


  /* reduce the typedef */
  p = expandedparms;
  while (p) {
    SwigType *ty = Getattr(p, "type");
    if (ty) {
      SwigType *nt = Swig_symbol_type_qualify(ty, tscope);
      Setattr(p, "type", nt);
      Delete(nt);
    }
    p = nextSibling(p);
  }

  SwigType_add_template(tname, expandedparms);

  if (template_debug) {
    Printf(stdout, "\n%s:%d: template_debug: Searching for %s\n", cparse_file, cparse_line, tname);
  }

  /* Search for an exact specialization.
     Example: template<> class name<int> { ... } */
  {
    if (template_debug) {
      Printf(stdout, "    searching: '%s' (exact specialization)\n", tname);
    }
    n = Swig_symbol_clookup_local(tname, 0);
    if (!n) {
      SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope);
      if (!Equal(rname, tname)) {
	if (template_debug) {
	  Printf(stdout, "    searching: '%s' (exact specialization)\n", rname);
	}
	n = Swig_symbol_clookup_local(rname, 0);
      }
      Delete(rname);
    }
    if (n) {
      Node *tn;
      String *nodeType = nodeType(n);
      if (Equal(nodeType, "template"))
	goto success;
      tn = Getattr(n, "template");
      if (tn) {
	n = tn;
	goto success;		/* Previously wrapped by a template return that */
      }
      Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n));
      Delete(tname);
      Delete(parms);
      return 0;			/* Found a match, but it's not a template of any kind. */
    }
  }

  /* Search for partial specialization. 
     Example: template<typename T> class name<T *> { ... } */

  /* Generate reduced template name (stripped of extraneous pointers, etc.) */

  rname = NewStringf("%s<(", name);
  p = parms;
  while (p) {
    String *t;
    t = Getattr(p, "type");
    if (!t)
      t = Getattr(p, "value");
    if (t) {
      String *ty = Swig_symbol_typedef_reduce(t, tscope);
      String *tb = SwigType_base(ty);
      String *td = SwigType_default(ty);
      Replaceid(td, "enum SWIGTYPE", tb);
      Replaceid(td, "SWIGTYPE", tb);
      Append(rname, td);
      Delete(tb);
      Delete(ty);
      Delete(td);
    }
    p = nextSibling(p);
    if (p) {
      Append(rname, ",");
    }
  }
  Append(rname, ")>");

  mpartials = NewList();
  if (templ) {
    /* First, we search using an exact type prototype */
    Parm *p;
    char tmp[32];
    int i;
    List *partials;
    String *ss;
    Iterator pi;

    partials = Getattr(templ, "partials");
    if (partials) {
      for (pi = First(partials); pi.item; pi = Next(pi)) {
	ss = Copy(pi.item);
	p = parms;
	i = 1;
	while (p) {
	  String *t, *tn;
	  sprintf(tmp, "$%d", i);
	  t = Getattr(p, "type");
	  if (!t)
	    t = Getattr(p, "value");
	  if (t) {
	    String *ty = Swig_symbol_typedef_reduce(t, tscope);
	    tn = SwigType_base(ty);
	    Replaceid(ss, tmp, tn);
	    Delete(tn);
	    Delete(ty);
	  }
	  i++;
	  p = nextSibling(p);
	}
	if (template_debug) {
	  Printf(stdout, "    searching: '%s' (partial specialization - %s)\n", ss, pi.item);
	}
	if ((Equal(ss, tname)) || (Equal(ss, rname))) {
	  Append(mpartials, pi.item);
	}
	Delete(ss);
      }
    }
  }

  if (template_debug) {
    Printf(stdout, "    Matched partials: %s\n", mpartials);
  }

  if (Len(mpartials)) {
    String *s = Getitem(mpartials, 0);
    n = Swig_symbol_clookup_local(s, 0);
    if (Len(mpartials) > 1) {
      if (n) {
	Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname));
	Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), "  instantiation '%s' is used.\n", SwigType_namestr(Getattr(n, "name")));
      }
    }
  }

  if (!n) {
    n = templ;
  }
  if (!n) {
    Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
  } else if (n) {
    String *nodeType = nodeType(n);
    if (!Equal(nodeType, "template")) {
      Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType);
      n = 0;
    }
  }
success:
  Delete(tname);
  Delete(rname);
  Delete(mpartials);
  if ((template_debug) && (n)) {
    Printf(stdout, "Node: %p\n", n);
    Swig_print_node(n);
  }
  Delete(parms);
  return n;
}
Exemple #4
0
int
Swig_ConstructorToFunction(Node *n, String *classname, 
			   String *none_comparison, String *director_ctor, int cplus, int flags)
{
  ParmList *parms;
  Parm     *prefix_args;
  Parm     *postfix_args;
  Parm     *p;
  ParmList *directorparms;
  SwigType *type;
  String   *membername;
  String   *mangled;
  Node     *classNode;
  int      use_director;
  
  classNode = Swig_methodclass(n);
  use_director = Swig_directorclass(n);

  membername = Swig_name_construct(classname);
  mangled = Swig_name_mangle(membername);

  parms = CopyParmList(nonvoid_parms(Getattr(n,"parms")));

  /* Prepend the list of prefix_args (if any) */
  prefix_args = Getattr(n,"director:prefix_args");
  if (prefix_args != NIL) {
    Parm *p2, *p3;

    directorparms = CopyParmList(prefix_args);
    for (p = directorparms; nextSibling(p); p = nextSibling(p));
    for (p2 = parms; p2; p2 = nextSibling(p2)) {
      p3 = CopyParm(p2);
      set_nextSibling(p, p3);
      p = p3;
    }
  } else
    directorparms = parms;

  postfix_args = Getattr(n,"director:postfix_args");
  if (postfix_args != NIL) {
    Parm *p2, *p3, *p4;

    if (prefix_args == NIL) /* no prefix args from above. */
      directorparms = CopyParmList(parms);

    if (directorparms != NIL) {
      p2 = directorparms;
      for ( ; nextSibling(p2); p2 = nextSibling(p2));
      for (p3 = postfix_args; p3; p3 = nextSibling(p3)) {
        p4 = CopyParm(p3);
        set_nextSibling(p2, p4);
        p2 = p4;
      }
    } else
      directorparms = CopyParmList(postfix_args);
  }

  type  = NewString(classname);
  SwigType_add_pointer(type);

  if (flags & CWRAP_EXTEND) {
    String *code = Getattr(n,"code");
    if (code) {
      String *wrap, *s;
      if (Getattr(n,"sym:overloaded") && code) {
	Append(mangled,Getattr(n,"sym:overname"));
      }
      s = NewStringf("%s(%s)", mangled, ParmList_str(parms));
      wrap = SwigType_str(type,s);
      Delete(s);
      Printv(wrap,code,"\n",NIL);
      Setattr(n,"wrap:code",wrap);
      Delete(wrap);
    }
    Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cfunction_call(mangled,parms)));
  } else {
    if (cplus) {
      /* if a C++ director class exists, create it rather than the original class */
      if (use_director) {
  	int abstract = Getattr(n, "abstract") != 0;
	Node *parent = Swig_methodclass(n);
	String *name = Getattr(parent, "sym:name");
        String* directorname = NewStringf("SwigDirector_%s", name);
	String* action = NewString("");
	String* tmp_none_comparison = Copy(none_comparison);
	String* director_call;
	String* nodirector_call;
	
	Replaceall( tmp_none_comparison, "$arg", "arg1" );

	director_call = Swig_cppconstructor_director_call(directorname, directorparms);
	nodirector_call = Swig_cppconstructor_nodirector_call(classname, parms);

	if (abstract) {
	  /* whether or not the abstract class has been subclassed in python,
	   * create a director instance (there's no way to create a normal
	   * instance).  if any of the pure virtual methods haven't been
	   * implemented in the target language, calls to those methods will
	   * generate Swig::DirectorPureVirtualException exceptions.
	   */
	  Printv(action, Swig_cresult(type, "result", director_call), NIL);
	} else {
	  /* (scottm): The code for creating a new director is now a string
	     template that gets passed in via the director_ctor argument.

	     $comparison : an 'if' comparison from none_comparison
	     $director_new: Call new for director class
	     $nondirector_new: Call new for non-director class
	   */
	  Printv(action, director_ctor, NIL);
	  Replaceall( action, "$comparison", tmp_none_comparison);
	  Replaceall( action, "$director_new", 
		      Swig_cresult(type, "result", director_call) );
	  Replaceall( action, "$nondirector_new", 
		      Swig_cresult(type, "result", nodirector_call) );
	}
	Setattr(n, "wrap:action", action);
	Delete(tmp_none_comparison);
	Delete(action);
        Delete(directorname);
      } else {
        Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cppconstructor_call(classname,parms)));
      }
    } else {
      Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cconstructor_call(classname)));
    }
  }
  Setattr(n,"type",type);
  Setattr(n,"parms", parms);
  Delete(type);
  if (directorparms != parms)
    Delete(directorparms);
  Delete(parms);
  Delete(mangled);
  Delete(membername);
  return SWIG_OK;
}
Exemple #5
0
int
Swig_MethodToFunction(Node *n, String *classname, int flags) {
  String   *name, *qualifier;
  ParmList *parms;
  SwigType *type;
  Parm     *p;
  String   *self = 0;

  /* If smart pointer, change self derefencing */
  if (flags & CWRAP_SMART_POINTER) {
    self = NewString("(*this)->");
  }
  /* If node is a member template expansion, we don't allow added code */

  if (Getattr(n,"templatetype")) flags &= ~(CWRAP_EXTEND);

  name      = Getattr(n,"name");
  qualifier = Getattr(n,"qualifier");
  parms     = CopyParmList(nonvoid_parms(Getattr(n,"parms")));
 
  type = NewString(classname);
  if (qualifier) {
    SwigType_push(type,qualifier);
  }
  SwigType_add_pointer(type);
  p = NewParm(type,"self");
  Setattr(p,"hidden","1");
  set_nextSibling(p,parms);
  Delete(type);
  
  /* Generate action code for the access */
  if (!(flags & CWRAP_EXTEND)) {
    Setattr(n,"wrap:action", Swig_cresult(Getattr(n,"type"),"result", Swig_cmethod_call(name,p,self)));
  } else {
    String *code;
    String *mangled;
    String *membername = Swig_name_member(classname, name);
    mangled = Swig_name_mangle(membername);

    code = Getattr(n,"code");
    type = Getattr(n,"type");

    /* Check if the method is overloaded.   If so, and it has code attached, we append an extra suffix
       to avoid a name-clash in the generated wrappers.  This allows overloaded methods to be defined
       in C. */

    if (Getattr(n,"sym:overloaded") && code) {
      Append(mangled,Getattr(n,"sym:overname"));
    }

    Setattr(n,"wrap:action", Swig_cresult(Getattr(n,"type"),"result", Swig_cfunction_call(mangled,p)));

    /* See if there is any code that we need to emit */
    if (code) {
      String *body;
      String *tmp = NewStringf("%s(%s)", mangled, ParmList_str(p));
      body = SwigType_str(type,tmp);
      Delete(tmp);
      Printv(body,code,"\n",NIL);
      Setattr(n,"wrap:code",body);
    }
    Delete(membername);
    Delete(mangled);
  }
  Setattr(n,"parms",p);
  Delete(p);
  Delete(self);
  return SWIG_OK;
}
Exemple #6
0
static Node *template_locate(String *name, Parm *tparms, Symtab *tscope) {
  Node *n = 0;
  String *tname = 0;
  Node *templ;
  Symtab *primary_scope = 0;
  List *possiblepartials = 0;
  Parm *p;
  Parm *parms = 0;
  Parm *targs;
  ParmList *expandedparms;
  int *priorities_matrix = 0;
  int max_possible_partials = 0;
  int posslen = 0;

  /* Search for primary (unspecialized) template */
  templ = Swig_symbol_clookup(name, 0);

  if (template_debug) {
    tname = Copy(name);
    SwigType_add_template(tname, tparms);
    Printf(stdout, "\n");
    Swig_diagnostic(cparse_file, cparse_line, "template_debug: Searching for match to: '%s'\n", tname);
    Delete(tname);
    tname = 0;
  }

  if (templ) {
    tname = Copy(name);
    parms = CopyParmList(tparms);

    /* All template specializations must be in the primary template's scope, store the symbol table for this scope for specialization lookups */
    primary_scope = Getattr(templ, "sym:symtab");

    /* Add default values from primary template */
    targs = Getattr(templ, "templateparms");
    expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, primary_scope);

    /* reduce the typedef */
    p = expandedparms;
    while (p) {
      SwigType *ty = Getattr(p, "type");
      if (ty) {
	SwigType *nt = Swig_symbol_type_qualify(ty, tscope);
	Setattr(p, "type", nt);
	Delete(nt);
      }
      p = nextSibling(p);
    }
    SwigType_add_template(tname, expandedparms);

    /* Search for an explicit (exact) specialization. Example: template<> class name<int> { ... } */
    {
      if (template_debug) {
	Printf(stdout, "    searching for : '%s' (explicit specialization)\n", tname);
      }
      n = Swig_symbol_clookup_local(tname, primary_scope);
      if (!n) {
	SwigType *rname = Swig_symbol_typedef_reduce(tname, tscope);
	if (!Equal(rname, tname)) {
	  if (template_debug) {
	    Printf(stdout, "    searching for : '%s' (explicit specialization with typedef reduction)\n", rname);
	  }
	  n = Swig_symbol_clookup_local(rname, primary_scope);
	}
	Delete(rname);
      }
      if (n) {
	Node *tn;
	String *nodeType = nodeType(n);
	if (Equal(nodeType, "template")) {
	  if (template_debug) {
	    Printf(stdout, "    explicit specialization found: '%s'\n", Getattr(n, "name"));
	  }
	  goto success;
	}
	tn = Getattr(n, "template");
	if (tn) {
	  if (template_debug) {
	    Printf(stdout, "    previous instantiation found: '%s'\n", Getattr(n, "name"));
	  }
	  n = tn;
	  goto success;	  /* Previously wrapped by a template instantiation */
	}
	Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType(n));
	Delete(tname);
	Delete(parms);
	return 0;	  /* Found a match, but it's not a template of any kind. */
      }
    }

    /* Search for partial specializations.
     * Example: template<typename T> class name<T *> { ... } 

     * There are 3 types of template arguments:
     * (1) Template type arguments
     * (2) Template non type arguments
     * (3) Template template arguments
     * only (1) is really supported for partial specializations
     */

    /* Rank each template parameter against the desired template parameters then build a matrix of best matches */
    possiblepartials = NewList();
    {
      char tmp[32];
      List *partials;

      partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */
      if (partials) {
	Iterator pi;
	int parms_len = ParmList_len(parms);
	int *priorities_row;
	max_possible_partials = Len(partials);
	priorities_matrix = (int *)malloc(sizeof(int) * max_possible_partials * parms_len); /* slightly wasteful allocation for max possible matches */
	priorities_row = priorities_matrix;
	for (pi = First(partials); pi.item; pi = Next(pi)) {
	  Parm *p = parms;
	  int all_parameters_match = 1;
	  int i = 1;
	  Parm *partialparms = Getattr(pi.item, "partialparms");
	  Parm *pp = partialparms;
	  String *templcsymname = Getattr(pi.item, "templcsymname");
	  if (template_debug) {
	    Printf(stdout, "    checking match: '%s' (partial specialization)\n", templcsymname);
	  }
	  if (ParmList_len(partialparms) == parms_len) {
	    while (p && pp) {
	      SwigType *t;
	      sprintf(tmp, "$%d", i);
	      t = Getattr(p, "type");
	      if (!t)
		t = Getattr(p, "value");
	      if (t) {
		EMatch match = does_parm_match(t, Getattr(pp, "type"), tmp, tscope, priorities_row + i - 1);
		if (match < (int)PartiallySpecializedMatch) {
		  all_parameters_match = 0;
		  break;
		}
	      }
	      i++;
	      p = nextSibling(p);
	      pp = nextSibling(pp);
	    }
	    if (all_parameters_match) {
	      Append(possiblepartials, pi.item);
	      priorities_row += parms_len;
	    }
	  }
	}
      }
    }

    posslen = Len(possiblepartials);
    if (template_debug) {
      int i;
      if (posslen == 0)
	Printf(stdout, "    matched partials: NONE\n");
      else if (posslen == 1)
	Printf(stdout, "    chosen partial: '%s'\n", Getattr(Getitem(possiblepartials, 0), "templcsymname"));
      else {
	Printf(stdout, "    possibly matched partials:\n");
	for (i = 0; i < posslen; i++) {
	  Printf(stdout, "      '%s'\n", Getattr(Getitem(possiblepartials, i), "templcsymname"));
	}
      }
    }

    if (posslen > 1) {
      /* Now go through all the possibly matched partial specialization templates and look for a non-ambiguous match.
       * Exact matches rank the highest and deduced parameters are ranked by how specialized they are, eg looking for
       * a match to const int *, the following rank (highest to lowest):
       *   const int * (exact match)
       *   const T *
       *   T *
       *   T
       *
       *   An ambiguous example when attempting to match as either specialization could match: %template() X<int *, double *>;
       *   template<typename T1, typename T2> X class {};  // primary template
       *   template<typename T1> X<T1, double *> class {}; // specialization (1)
       *   template<typename T2> X<int *, T2> class {};    // specialization (2)
       */
      if (template_debug) {
	int row, col;
	int parms_len = ParmList_len(parms);
	Printf(stdout, "      parameter priorities matrix (%d parms):\n", parms_len);
	for (row = 0; row < posslen; row++) {
	  int *priorities_row = priorities_matrix + row*parms_len;
	  Printf(stdout, "        ");
	  for (col = 0; col < parms_len; col++) {
	    Printf(stdout, "%5d ", priorities_row[col]);
	  }
	  Printf(stdout, "\n");
	}
      }
      {
	int row, col;
	int parms_len = ParmList_len(parms);
	/* Printf(stdout, "      parameter priorities inverse matrix (%d parms):\n", parms_len); */
	for (col = 0; col < parms_len; col++) {
	  int *priorities_col = priorities_matrix + col;
	  int maxpriority = -1;
	  /* 
	     Printf(stdout, "max_possible_partials: %d col:%d\n", max_possible_partials, col);
	     Printf(stdout, "        ");
	     */
	  /* determine the highest rank for this nth parameter */
	  for (row = 0; row < posslen; row++) {
	    int *element_ptr = priorities_col + row*parms_len;
	    int priority = *element_ptr;
	    if (priority > maxpriority)
	      maxpriority = priority;
	    /* Printf(stdout, "%5d ", priority); */
	  }
	  /* Printf(stdout, "\n"); */
	  /* flag all the parameters which equal the highest rank */
	  for (row = 0; row < posslen; row++) {
	    int *element_ptr = priorities_col + row*parms_len;
	    int priority = *element_ptr;
	    *element_ptr = (priority >= maxpriority) ? 1 : 0;
	  }
	}
      }
      {
	int row, col;
	int parms_len = ParmList_len(parms);
	Iterator pi = First(possiblepartials);
	Node *chosenpartials = NewList();
	if (template_debug)
	  Printf(stdout, "      priority flags matrix:\n");
	for (row = 0; row < posslen; row++) {
	  int *priorities_row = priorities_matrix + row*parms_len;
	  int highest_count = 0; /* count of highest priority parameters */
	  for (col = 0; col < parms_len; col++) {
	    highest_count += priorities_row[col];
	  }
	  if (template_debug) {
	    Printf(stdout, "        ");
	    for (col = 0; col < parms_len; col++) {
	      Printf(stdout, "%5d ", priorities_row[col]);
	    }
	    Printf(stdout, "\n");
	  }
	  if (highest_count == parms_len) {
	    Append(chosenpartials, pi.item);
	  }
	  pi = Next(pi);
	}
	if (Len(chosenpartials) > 0) {
	  /* one or more best match found */
	  Delete(possiblepartials);
	  possiblepartials = chosenpartials;
	  posslen = Len(possiblepartials);
	} else {
	  /* no best match found */
	  Delete(chosenpartials);
	}
      }
    }

    if (posslen > 0) {
      String *s = Getattr(Getitem(possiblepartials, 0), "templcsymname");
      n = Swig_symbol_clookup_local(s, primary_scope);
      if (posslen > 1) {
	int i;
	if (n) {
	  Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, cparse_file, cparse_line, "Instantiation of template '%s' is ambiguous,\n", SwigType_namestr(tname));
	  Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(n), Getline(n), "  instantiation '%s' used,\n", SwigType_namestr(Getattr(n, "name")));
	}
	for (i = 1; i < posslen; i++) {
	  String *templcsymname = Getattr(Getitem(possiblepartials, i), "templcsymname");
	  Node *ignored_node = Swig_symbol_clookup_local(templcsymname, primary_scope);
	  assert(ignored_node);
	  Swig_warning(WARN_PARSE_TEMPLATE_AMBIG, Getfile(ignored_node), Getline(ignored_node), "  instantiation '%s' ignored.\n", SwigType_namestr(Getattr(ignored_node, "name")));
	}
      }
    }

    if (!n) {
      if (template_debug) {
	Printf(stdout, "    chosen primary template: '%s'\n", Getattr(templ, "name"));
      }
      n = templ;
    }
  } else {
    if (template_debug) {
      Printf(stdout, "    primary template not found\n");
    }
    /* Give up if primary (unspecialized) template not found as specializations will only exist if there is a primary template */
    n = 0;
  }

  if (!n) {
    Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
  } else if (n) {
    String *nodeType = nodeType(n);
    if (!Equal(nodeType, "template")) {
      Swig_error(cparse_file, cparse_line, "'%s' is not defined as a template. (%s)\n", name, nodeType);
      n = 0;
    }
  }
success:
  Delete(tname);
  Delete(possiblepartials);
  if ((template_debug) && (n)) {
    /*
    Printf(stdout, "Node: %p\n", n);
    Swig_print_node(n);
    */
    Printf(stdout, "    chosen template:'%s'\n", Getattr(n, "name"));
  }
  Delete(parms);
  free(priorities_matrix);
  return n;
}